Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH] ManifestScheduler: async fetchlist_dict (bug 653946)
Date: Tue, 24 Apr 2018 08:09:56
Message-Id: 20180424080928.12067-1-zmedico@gentoo.org
1 In order to avoid event loop recursion, pass fetchlist_dict to
2 ManifestTask as a Future.
3
4 Bug: https://bugs.gentoo.org/653946
5 ---
6 .../ebuild/_parallel_manifest/ManifestScheduler.py | 70 +++++++++++++++++-----
7 .../ebuild/_parallel_manifest/ManifestTask.py | 22 +++++++
8 pym/portage/tests/dbapi/test_portdb_cache.py | 1 +
9 3 files changed, 79 insertions(+), 14 deletions(-)
10
11 diff --git a/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py b/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py
12 index 38ac4825e..42854b05b 100644
13 --- a/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py
14 +++ b/pym/portage/package/ebuild/_parallel_manifest/ManifestScheduler.py
15 @@ -4,9 +4,9 @@
16 import portage
17 from portage import os
18 from portage.dep import _repo_separator
19 -from portage.exception import InvalidDependString
20 from portage.localization import _
21 from portage.util._async.AsyncScheduler import AsyncScheduler
22 +from portage.util.futures import asyncio
23 from .ManifestTask import ManifestTask
24
25 class ManifestScheduler(AsyncScheduler):
26 @@ -63,21 +63,11 @@ class ManifestScheduler(AsyncScheduler):
27 cpv_list = portdb.cp_list(cp, mytree=[repo_config.location])
28 if not cpv_list:
29 continue
30 - fetchlist_dict = {}
31 - try:
32 - for cpv in cpv_list:
33 - fetchlist_dict[cpv] = \
34 - list(portdb.getFetchMap(cpv, mytree=mytree))
35 - except InvalidDependString as e:
36 - portage.writemsg(
37 - _("!!! %s%s%s: SRC_URI: %s\n") %
38 - (cp, _repo_separator, repo_config.name, e),
39 - noiselevel=-1)
40 - self._error_count += 1
41 - continue
42
43 yield ManifestTask(cp=cp, distdir=distdir,
44 - fetchlist_dict=fetchlist_dict, repo_config=repo_config,
45 + fetchlist_dict=_future_fetchlist(
46 + self._event_loop, portdb, repo_config, cp, cpv_list),
47 + repo_config=repo_config,
48 gpg_cmd=self._gpg_cmd, gpg_vars=self._gpg_vars,
49 force_sign_key=self._force_sign_key)
50
51 @@ -91,3 +81,55 @@ class ManifestScheduler(AsyncScheduler):
52 noiselevel=-1)
53
54 AsyncScheduler._task_exit(self, task)
55 +
56 +
57 +def _future_fetchlist(loop, portdb, repo_config, cp, cpv_list):
58 + """
59 + Asynchronous form of FetchlistDict.
60 +
61 + @param loop: event loop
62 + @type loop: EventLoop
63 + @param portdb: portdbapi instance
64 + @type portdb: portdbapi
65 + @param repo_config: repository configuration for a Manifest
66 + @type repo_config: RepoConfig
67 + @param cp: cp for a Manifest
68 + @type cp: str
69 + @param cpv_list: list of ebuild cpv values for a Manifest
70 + @type cpv_list: list
71 + @return: a Future resulting in a Mapping compatible with FetchlistDict
72 + @rtype: asyncio.Future (or compatible)
73 + """
74 + loop = getattr(loop, '_asyncio_wrapper', loop)
75 + result = loop.create_future()
76 + futures = {}
77 + for cpv in cpv_list:
78 + futures[cpv] = portdb.async_fetch_map(
79 + cpv, mytree=repo_config.location, loop=loop)
80 +
81 + def futures_done(wait_result):
82 + if result.cancelled():
83 + return
84 + e = None
85 + for future in futures.values():
86 + if (future.done() and future.exception() is not None):
87 + # Retrieve exceptions from all futures in order to
88 + # avoid triggering the event loop's error handler.
89 + e = future.exception()
90 +
91 + if e is None:
92 + result.set_result(dict((k, list(v.result()))
93 + for k, v in futures.items()))
94 + else:
95 + result.set_exception(e)
96 +
97 + wait_result = asyncio.ensure_future(
98 + asyncio.wait(list(futures.values()),
99 + loop=loop),
100 + loop=loop)
101 +
102 + wait_result.add_done_callback(futures_done)
103 + result.add_done_callback(lambda result:
104 + wait_result.cancel() if result.cancelled() else None)
105 +
106 + return result
107 diff --git a/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py b/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py
108 index 0ee2b910d..6f5fe5b16 100644
109 --- a/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py
110 +++ b/pym/portage/package/ebuild/_parallel_manifest/ManifestTask.py
111 @@ -8,8 +8,12 @@ import subprocess
112 from portage import os
113 from portage import _unicode_encode, _encodings
114 from portage.const import MANIFEST2_IDENTIFIERS
115 +from portage.dep import _repo_separator
116 +from portage.exception import InvalidDependString
117 +from portage.localization import _
118 from portage.util import (atomic_ofstream, grablines,
119 shlex_split, varexpand, writemsg)
120 +from portage.util._async.AsyncTaskFuture import AsyncTaskFuture
121 from portage.util._async.PipeLogger import PipeLogger
122 from portage.util._async.PopenProcess import PopenProcess
123 from _emerge.CompositeTask import CompositeTask
124 @@ -29,6 +33,24 @@ class ManifestTask(CompositeTask):
125 def _start(self):
126 self._manifest_path = os.path.join(self.repo_config.location,
127 self.cp, "Manifest")
128 +
129 + self._start_task(
130 + AsyncTaskFuture(future=self.fetchlist_dict),
131 + self._start_with_fetchlist)
132 +
133 + def _start_with_fetchlist(self, fetchlist_task):
134 + if self._default_exit(fetchlist_task) != os.EX_OK:
135 + if not self.fetchlist_dict.cancelled():
136 + try:
137 + self.fetchlist_dict.result()
138 + except InvalidDependString as e:
139 + writemsg(
140 + _("!!! %s%s%s: SRC_URI: %s\n") %
141 + (self.cp, _repo_separator, self.repo_config.name, e),
142 + noiselevel=-1)
143 + self._async_wait()
144 + return
145 + self.fetchlist_dict = self.fetchlist_dict.result()
146 manifest_proc = ManifestProcess(cp=self.cp, distdir=self.distdir,
147 fetchlist_dict=self.fetchlist_dict, repo_config=self.repo_config,
148 scheduler=self.scheduler)
149 diff --git a/pym/portage/tests/dbapi/test_portdb_cache.py b/pym/portage/tests/dbapi/test_portdb_cache.py
150 index bd934460a..1f139b256 100644
151 --- a/pym/portage/tests/dbapi/test_portdb_cache.py
152 +++ b/pym/portage/tests/dbapi/test_portdb_cache.py
153 @@ -38,6 +38,7 @@ class PortdbCacheTestCase(TestCase):
154 portage_python = portage._python_interpreter
155 egencache_cmd = (portage_python, "-b", "-Wd",
156 os.path.join(self.bindir, "egencache"),
157 + "--update-manifests", "--sign-manifests=n",
158 "--repo", "test_repo",
159 "--repositories-configuration", settings.repositories.config_string())
160 python_cmd = (portage_python, "-b", "-Wd", "-c")
161 --
162 2.13.6

Replies