We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Implementation of does_batch in DeclarativeContent is wrong
**Describe the bug**
`does_batch` is supposed to decide, whether content can be waited on, or must be evaluated asap. It produces `False` unnecessarily often, leading to performance issues.

**Additional context**
This is suspected to at least one of the reasons for: https://github.com/pulp/pulp_deb/issues/466

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pulpcore/plugin/stages/models.py`
Content:
```
1 from gettext import gettext as _
2 
3 import asyncio
4 
5 from pulpcore.constants import ALL_KNOWN_CONTENT_CHECKSUMS
6 from pulpcore.plugin.models import Artifact
7 
8 
9 class DeclarativeArtifact:
10     """
11     Relates an :class:`~pulpcore.plugin.models.Artifact`, how to download it, and its
12     `relative_path` used later during publishing.
13 
14     This is used by the Stages API stages to determine if an
15     :class:`~pulpcore.plugin.models.Artifact` is already present and ensure Pulp can download it in
16     the future. The `artifact` can be either saved or unsaved. If unsaved, the `artifact` attributes
17     may be incomplete because not all digest information can be computed until the
18     :class:`~pulpcore.plugin.models.Artifact` is downloaded.
19 
20     Attributes:
21         artifact (:class:`~pulpcore.plugin.models.Artifact`): An
22             :class:`~pulpcore.plugin.models.Artifact` either saved or unsaved. If unsaved, it
23             may have partial digest information attached to it.
24         url (str): the url to fetch the :class:`~pulpcore.plugin.models.Artifact` from.
25         relative_path (str): the relative_path this :class:`~pulpcore.plugin.models.Artifact`
26             should be published at for any Publication.
27         remote (:class:`~pulpcore.plugin.models.Remote`): The remote used to fetch this
28             :class:`~pulpcore.plugin.models.Artifact`.
29         extra_data (dict): A dictionary available for additional data to be stored in.
30         deferred_download (bool): Whether this artifact should be downloaded and saved
31             in the artifact stages. Defaults to `False`. See :ref:`on-demand-support`.
32 
33     Raises:
34         ValueError: If `artifact`, `url`, or `relative_path` are not specified. If `remote` is not
35         specified and `artifact` doesn't have a file.
36     """
37 
38     __slots__ = ("artifact", "url", "relative_path", "remote", "extra_data", "deferred_download")
39 
40     def __init__(
41         self,
42         artifact=None,
43         url=None,
44         relative_path=None,
45         remote=None,
46         extra_data=None,
47         deferred_download=False,
48     ):
49         if not url:
50             raise ValueError(_("DeclarativeArtifact must have a 'url'"))
51         if not relative_path:
52             raise ValueError(_("DeclarativeArtifact must have a 'relative_path'"))
53         if not artifact:
54             raise ValueError(_("DeclarativeArtifact must have a 'artifact'"))
55         if not remote and not artifact.file:
56             raise ValueError(
57                 _(
58                     "DeclarativeArtifact must have a 'remote' if the Artifact doesn't "
59                     "have a file backing it."
60                 )
61             )
62         self.artifact = artifact
63         self.url = url
64         self.relative_path = relative_path
65         self.remote = remote
66         self.extra_data = extra_data or {}
67         self.deferred_download = deferred_download
68 
69     async def download(self):
70         """
71         Download content and update the associated Artifact.
72 
73         Returns:
74             Returns the :class:`~pulpcore.plugin.download.DownloadResult` of the Artifact.
75         """
76         expected_digests = {}
77         validation_kwargs = {}
78         for digest_name in ALL_KNOWN_CONTENT_CHECKSUMS:
79             digest_value = getattr(self.artifact, digest_name)
80             if digest_value:
81                 expected_digests[digest_name] = digest_value
82         if expected_digests:
83             validation_kwargs["expected_digests"] = expected_digests
84         if self.artifact.size:
85             expected_size = self.artifact.size
86             validation_kwargs["expected_size"] = expected_size
87         downloader = self.remote.get_downloader(url=self.url, **validation_kwargs)
88         # Custom downloaders may need extra information to complete the request.
89         download_result = await downloader.run(extra_data=self.extra_data)
90         self.artifact = Artifact(**download_result.artifact_attributes, file=download_result.path)
91         return download_result
92 
93 
94 class DeclarativeContent:
95     """
96     Relates a Content unit and zero or more :class:`~pulpcore.plugin.stages.DeclarativeArtifact`
97     objects.
98 
99     This is used by the Stages API stages to determine if a Content unit is already present and
100     ensure all of its associated :class:`~pulpcore.plugin.stages.DeclarativeArtifact` objects are
101     related correctly. The `content` can be either saved or unsaved depending on where in the Stages
102     API pipeline this is used.
103 
104     Attributes:
105         content (subclass of :class:`~pulpcore.plugin.models.Content`): A Content unit, possibly
106             unsaved
107         d_artifacts (list): A list of zero or more
108             :class:`~pulpcore.plugin.stages.DeclarativeArtifact` objects associated with `content`.
109         extra_data (dict): A dictionary available for additional data to be stored in.
110 
111     Raises:
112         ValueError: If `content` is not specified.
113     """
114 
115     __slots__ = (
116         "content",
117         "d_artifacts",
118         "extra_data",
119         "_future",
120         "_thaw_queue_event",
121         "_resolved",
122     )
123 
124     def __init__(self, content=None, d_artifacts=None, extra_data=None):
125         if not content:
126             raise ValueError(_("DeclarativeContent must have a 'content'"))
127         self.content = content
128         self.d_artifacts = d_artifacts or []
129         self.extra_data = extra_data or {}
130         self._future = None
131         self._thaw_queue_event = None
132         self._resolved = False
133 
134     @property
135     def does_batch(self):
136         """Whether this content is being awaited on and must therefore not wait forever in batches.
137         When overwritten in subclasses, a `True` value must never be turned into `False`.
138         """
139         return not self._resolved and self._future is None
140 
141     async def resolution(self):
142         """Coroutine that waits for the content to be saved to database.
143         Returns the content unit."""
144         if self._resolved:
145             # Already resolved ~> shortcut
146             return self.content
147         if self._future is None:
148             # We do not yet have a future
149             self._future = asyncio.get_event_loop().create_future()
150             if self._thaw_queue_event:
151                 # We have a future now but are still stuck in a queue
152                 self._thaw_queue_event.set()
153         # Now we wait
154         return await self._future
155 
156     def resolve(self):
157         """Resolve this content unit and notify any waiting tasks."""
158         self._resolved = True
159         if self._future:
160             self._future.set_result(self.content)
161             self._future = None
162 
163     def __str__(self):
164         return str(self.content.__class__.__name__)
165
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pulpcore/plugin/stages/models.py b/pulpcore/plugin/stages/models.py
--- a/pulpcore/plugin/stages/models.py
+++ b/pulpcore/plugin/stages/models.py
@@ -136,7 +136,7 @@
         """Whether this content is being awaited on and must therefore not wait forever in batches.
         When overwritten in subclasses, a `True` value must never be turned into `False`.
         """
-        return not self._resolved and self._future is None
+        return self._resolved or self._future is None
 
     async def resolution(self):
         """Coroutine that waits for the content to be saved to database.

{"golden_diff": "diff --git a/pulpcore/plugin/stages/models.py b/pulpcore/plugin/stages/models.py\n--- a/pulpcore/plugin/stages/models.py\n+++ b/pulpcore/plugin/stages/models.py\n@@ -136,7 +136,7 @@\n         \"\"\"Whether this content is being awaited on and must therefore not wait forever in batches.\n         When overwritten in subclasses, a `True` value must never be turned into `False`.\n         \"\"\"\n-        return not self._resolved and self._future is None\n+        return self._resolved or self._future is None\n \n     async def resolution(self):\n         \"\"\"Coroutine that waits for the content to be saved to database.\n", "issue": "Implementation of does_batch in DeclarativeContent is wrong\n**Describe the bug**\r\n`does_batch` is supposed to decide, whether content can be waited on, or must be evaluated asap. It produces `False` unnecessarily often, leading to performance issues.\r\n\r\n**Additional context**\r\nThis is suspected to at least one of the reasons for: https://github.com/pulp/pulp_deb/issues/466\n", "before_files": [{"content": "from gettext import gettext as _\n\nimport asyncio\n\nfrom pulpcore.constants import ALL_KNOWN_CONTENT_CHECKSUMS\nfrom pulpcore.plugin.models import Artifact\n\n\nclass DeclarativeArtifact:\n    \"\"\"\n    Relates an :class:`~pulpcore.plugin.models.Artifact`, how to download it, and its\n    `relative_path` used later during publishing.\n\n    This is used by the Stages API stages to determine if an\n    :class:`~pulpcore.plugin.models.Artifact` is already present and ensure Pulp can download it in\n    the future. The `artifact` can be either saved or unsaved. If unsaved, the `artifact` attributes\n    may be incomplete because not all digest information can be computed until the\n    :class:`~pulpcore.plugin.models.Artifact` is downloaded.\n\n    Attributes:\n        artifact (:class:`~pulpcore.plugin.models.Artifact`): An\n            :class:`~pulpcore.plugin.models.Artifact` either saved or unsaved. If unsaved, it\n            may have partial digest information attached to it.\n        url (str): the url to fetch the :class:`~pulpcore.plugin.models.Artifact` from.\n        relative_path (str): the relative_path this :class:`~pulpcore.plugin.models.Artifact`\n            should be published at for any Publication.\n        remote (:class:`~pulpcore.plugin.models.Remote`): The remote used to fetch this\n            :class:`~pulpcore.plugin.models.Artifact`.\n        extra_data (dict): A dictionary available for additional data to be stored in.\n        deferred_download (bool): Whether this artifact should be downloaded and saved\n            in the artifact stages. Defaults to `False`. See :ref:`on-demand-support`.\n\n    Raises:\n        ValueError: If `artifact`, `url`, or `relative_path` are not specified. If `remote` is not\n        specified and `artifact` doesn't have a file.\n    \"\"\"\n\n    __slots__ = (\"artifact\", \"url\", \"relative_path\", \"remote\", \"extra_data\", \"deferred_download\")\n\n    def __init__(\n        self,\n        artifact=None,\n        url=None,\n        relative_path=None,\n        remote=None,\n        extra_data=None,\n        deferred_download=False,\n    ):\n        if not url:\n            raise ValueError(_(\"DeclarativeArtifact must have a 'url'\"))\n        if not relative_path:\n            raise ValueError(_(\"DeclarativeArtifact must have a 'relative_path'\"))\n        if not artifact:\n            raise ValueError(_(\"DeclarativeArtifact must have a 'artifact'\"))\n        if not remote and not artifact.file:\n            raise ValueError(\n                _(\n                    \"DeclarativeArtifact must have a 'remote' if the Artifact doesn't \"\n                    \"have a file backing it.\"\n                )\n            )\n        self.artifact = artifact\n        self.url = url\n        self.relative_path = relative_path\n        self.remote = remote\n        self.extra_data = extra_data or {}\n        self.deferred_download = deferred_download\n\n    async def download(self):\n        \"\"\"\n        Download content and update the associated Artifact.\n\n        Returns:\n            Returns the :class:`~pulpcore.plugin.download.DownloadResult` of the Artifact.\n        \"\"\"\n        expected_digests = {}\n        validation_kwargs = {}\n        for digest_name in ALL_KNOWN_CONTENT_CHECKSUMS:\n            digest_value = getattr(self.artifact, digest_name)\n            if digest_value:\n                expected_digests[digest_name] = digest_value\n        if expected_digests:\n            validation_kwargs[\"expected_digests\"] = expected_digests\n        if self.artifact.size:\n            expected_size = self.artifact.size\n            validation_kwargs[\"expected_size\"] = expected_size\n        downloader = self.remote.get_downloader(url=self.url, **validation_kwargs)\n        # Custom downloaders may need extra information to complete the request.\n        download_result = await downloader.run(extra_data=self.extra_data)\n        self.artifact = Artifact(**download_result.artifact_attributes, file=download_result.path)\n        return download_result\n\n\nclass DeclarativeContent:\n    \"\"\"\n    Relates a Content unit and zero or more :class:`~pulpcore.plugin.stages.DeclarativeArtifact`\n    objects.\n\n    This is used by the Stages API stages to determine if a Content unit is already present and\n    ensure all of its associated :class:`~pulpcore.plugin.stages.DeclarativeArtifact` objects are\n    related correctly. The `content` can be either saved or unsaved depending on where in the Stages\n    API pipeline this is used.\n\n    Attributes:\n        content (subclass of :class:`~pulpcore.plugin.models.Content`): A Content unit, possibly\n            unsaved\n        d_artifacts (list): A list of zero or more\n            :class:`~pulpcore.plugin.stages.DeclarativeArtifact` objects associated with `content`.\n        extra_data (dict): A dictionary available for additional data to be stored in.\n\n    Raises:\n        ValueError: If `content` is not specified.\n    \"\"\"\n\n    __slots__ = (\n        \"content\",\n        \"d_artifacts\",\n        \"extra_data\",\n        \"_future\",\n        \"_thaw_queue_event\",\n        \"_resolved\",\n    )\n\n    def __init__(self, content=None, d_artifacts=None, extra_data=None):\n        if not content:\n            raise ValueError(_(\"DeclarativeContent must have a 'content'\"))\n        self.content = content\n        self.d_artifacts = d_artifacts or []\n        self.extra_data = extra_data or {}\n        self._future = None\n        self._thaw_queue_event = None\n        self._resolved = False\n\n    @property\n    def does_batch(self):\n        \"\"\"Whether this content is being awaited on and must therefore not wait forever in batches.\n        When overwritten in subclasses, a `True` value must never be turned into `False`.\n        \"\"\"\n        return not self._resolved and self._future is None\n\n    async def resolution(self):\n        \"\"\"Coroutine that waits for the content to be saved to database.\n        Returns the content unit.\"\"\"\n        if self._resolved:\n            # Already resolved ~> shortcut\n            return self.content\n        if self._future is None:\n            # We do not yet have a future\n            self._future = asyncio.get_event_loop().create_future()\n            if self._thaw_queue_event:\n                # We have a future now but are still stuck in a queue\n                self._thaw_queue_event.set()\n        # Now we wait\n        return await self._future\n\n    def resolve(self):\n        \"\"\"Resolve this content unit and notify any waiting tasks.\"\"\"\n        self._resolved = True\n        if self._future:\n            self._future.set_result(self.content)\n            self._future = None\n\n    def __str__(self):\n        return str(self.content.__class__.__name__)\n", "path": "pulpcore/plugin/stages/models.py"}], "after_files": [{"content": "from gettext import gettext as _\n\nimport asyncio\n\nfrom pulpcore.constants import ALL_KNOWN_CONTENT_CHECKSUMS\nfrom pulpcore.plugin.models import Artifact\n\n\nclass DeclarativeArtifact:\n    \"\"\"\n    Relates an :class:`~pulpcore.plugin.models.Artifact`, how to download it, and its\n    `relative_path` used later during publishing.\n\n    This is used by the Stages API stages to determine if an\n    :class:`~pulpcore.plugin.models.Artifact` is already present and ensure Pulp can download it in\n    the future. The `artifact` can be either saved or unsaved. If unsaved, the `artifact` attributes\n    may be incomplete because not all digest information can be computed until the\n    :class:`~pulpcore.plugin.models.Artifact` is downloaded.\n\n    Attributes:\n        artifact (:class:`~pulpcore.plugin.models.Artifact`): An\n            :class:`~pulpcore.plugin.models.Artifact` either saved or unsaved. If unsaved, it\n            may have partial digest information attached to it.\n        url (str): the url to fetch the :class:`~pulpcore.plugin.models.Artifact` from.\n        relative_path (str): the relative_path this :class:`~pulpcore.plugin.models.Artifact`\n            should be published at for any Publication.\n        remote (:class:`~pulpcore.plugin.models.Remote`): The remote used to fetch this\n            :class:`~pulpcore.plugin.models.Artifact`.\n        extra_data (dict): A dictionary available for additional data to be stored in.\n        deferred_download (bool): Whether this artifact should be downloaded and saved\n            in the artifact stages. Defaults to `False`. See :ref:`on-demand-support`.\n\n    Raises:\n        ValueError: If `artifact`, `url`, or `relative_path` are not specified. If `remote` is not\n        specified and `artifact` doesn't have a file.\n    \"\"\"\n\n    __slots__ = (\"artifact\", \"url\", \"relative_path\", \"remote\", \"extra_data\", \"deferred_download\")\n\n    def __init__(\n        self,\n        artifact=None,\n        url=None,\n        relative_path=None,\n        remote=None,\n        extra_data=None,\n        deferred_download=False,\n    ):\n        if not url:\n            raise ValueError(_(\"DeclarativeArtifact must have a 'url'\"))\n        if not relative_path:\n            raise ValueError(_(\"DeclarativeArtifact must have a 'relative_path'\"))\n        if not artifact:\n            raise ValueError(_(\"DeclarativeArtifact must have a 'artifact'\"))\n        if not remote and not artifact.file:\n            raise ValueError(\n                _(\n                    \"DeclarativeArtifact must have a 'remote' if the Artifact doesn't \"\n                    \"have a file backing it.\"\n                )\n            )\n        self.artifact = artifact\n        self.url = url\n        self.relative_path = relative_path\n        self.remote = remote\n        self.extra_data = extra_data or {}\n        self.deferred_download = deferred_download\n\n    async def download(self):\n        \"\"\"\n        Download content and update the associated Artifact.\n\n        Returns:\n            Returns the :class:`~pulpcore.plugin.download.DownloadResult` of the Artifact.\n        \"\"\"\n        expected_digests = {}\n        validation_kwargs = {}\n        for digest_name in ALL_KNOWN_CONTENT_CHECKSUMS:\n            digest_value = getattr(self.artifact, digest_name)\n            if digest_value:\n                expected_digests[digest_name] = digest_value\n        if expected_digests:\n            validation_kwargs[\"expected_digests\"] = expected_digests\n        if self.artifact.size:\n            expected_size = self.artifact.size\n            validation_kwargs[\"expected_size\"] = expected_size\n        downloader = self.remote.get_downloader(url=self.url, **validation_kwargs)\n        # Custom downloaders may need extra information to complete the request.\n        download_result = await downloader.run(extra_data=self.extra_data)\n        self.artifact = Artifact(**download_result.artifact_attributes, file=download_result.path)\n        return download_result\n\n\nclass DeclarativeContent:\n    \"\"\"\n    Relates a Content unit and zero or more :class:`~pulpcore.plugin.stages.DeclarativeArtifact`\n    objects.\n\n    This is used by the Stages API stages to determine if a Content unit is already present and\n    ensure all of its associated :class:`~pulpcore.plugin.stages.DeclarativeArtifact` objects are\n    related correctly. The `content` can be either saved or unsaved depending on where in the Stages\n    API pipeline this is used.\n\n    Attributes:\n        content (subclass of :class:`~pulpcore.plugin.models.Content`): A Content unit, possibly\n            unsaved\n        d_artifacts (list): A list of zero or more\n            :class:`~pulpcore.plugin.stages.DeclarativeArtifact` objects associated with `content`.\n        extra_data (dict): A dictionary available for additional data to be stored in.\n\n    Raises:\n        ValueError: If `content` is not specified.\n    \"\"\"\n\n    __slots__ = (\n        \"content\",\n        \"d_artifacts\",\n        \"extra_data\",\n        \"_future\",\n        \"_thaw_queue_event\",\n        \"_resolved\",\n    )\n\n    def __init__(self, content=None, d_artifacts=None, extra_data=None):\n        if not content:\n            raise ValueError(_(\"DeclarativeContent must have a 'content'\"))\n        self.content = content\n        self.d_artifacts = d_artifacts or []\n        self.extra_data = extra_data or {}\n        self._future = None\n        self._thaw_queue_event = None\n        self._resolved = False\n\n    @property\n    def does_batch(self):\n        \"\"\"Whether this content is being awaited on and must therefore not wait forever in batches.\n        When overwritten in subclasses, a `True` value must never be turned into `False`.\n        \"\"\"\n        return self._resolved or self._future is None\n\n    async def resolution(self):\n        \"\"\"Coroutine that waits for the content to be saved to database.\n        Returns the content unit.\"\"\"\n        if self._resolved:\n            # Already resolved ~> shortcut\n            return self.content\n        if self._future is None:\n            # We do not yet have a future\n            self._future = asyncio.get_event_loop().create_future()\n            if self._thaw_queue_event:\n                # We have a future now but are still stuck in a queue\n                self._thaw_queue_event.set()\n        # Now we wait\n        return await self._future\n\n    def resolve(self):\n        \"\"\"Resolve this content unit and notify any waiting tasks.\"\"\"\n        self._resolved = True\n        if self._future:\n            self._future.set_result(self.content)\n            self._future = None\n\n    def __str__(self):\n        return str(self.content.__class__.__name__)\n", "path": "pulpcore/plugin/stages/models.py"}]}