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] BinpkgFetcher: use async lock (bug 614110)
Date: Sat, 21 Apr 2018 19:30:16
Message-Id: 20180421192728.16056-1-zmedico@gentoo.org
1 In order to avoid event loop recursion, convert the
2 _BinpkgFetcherProcess.lock() method to an async_lock
3 method for use by BinpkgFetcher.
4
5 Bug: https://bugs.gentoo.org/614110
6 ---
7 pym/_emerge/BinpkgFetcher.py | 53 +++++++++++++++++++++++++++-----------------
8 1 file changed, 33 insertions(+), 20 deletions(-)
9
10 diff --git a/pym/_emerge/BinpkgFetcher.py b/pym/_emerge/BinpkgFetcher.py
11 index 5ca7a45cf..2bbc0a26f 100644
12 --- a/pym/_emerge/BinpkgFetcher.py
13 +++ b/pym/_emerge/BinpkgFetcher.py
14 @@ -32,11 +32,24 @@ class BinpkgFetcher(CompositeTask):
15 pkg.cpv) + ".partial"
16
17 def _start(self):
18 - self._start_task(
19 - _BinpkgFetcherProcess(background=self.background,
20 - logfile=self.logfile, pkg=self.pkg, pkg_path=self.pkg_path,
21 - pretend=self.pretend, scheduler=self.scheduler),
22 - self._fetcher_exit)
23 + fetcher = _BinpkgFetcherProcess(background=self.background,
24 + logfile=self.logfile, pkg=self.pkg, pkg_path=self.pkg_path,
25 + pretend=self.pretend, scheduler=self.scheduler)
26 +
27 + if not self.pretend:
28 + portage.util.ensure_dirs(os.path.dirname(self.pkg_path))
29 + if "distlocks" in self.pkg.root_config.settings.features:
30 + self._start_task(
31 + AsyncTaskFuture(future=fetcher.async_lock()),
32 + functools.partial(self._start_locked, fetcher))
33 + return
34 +
35 + self._start_task(fetcher, self._fetcher_exit)
36 +
37 + def _start_locked(self, fetcher, lock_task):
38 + self._assert_current(lock_task)
39 + lock_task.future.result()
40 + self._start_task(fetcher, self._fetcher_exit)
41
42 def _fetcher_exit(self, fetcher):
43 self._assert_current(fetcher)
44 @@ -68,13 +81,8 @@ class _BinpkgFetcherProcess(SpawnProcess):
45 pretend = self.pretend
46 bintree = pkg.root_config.trees["bintree"]
47 settings = bintree.settings
48 - use_locks = "distlocks" in settings.features
49 pkg_path = self.pkg_path
50
51 - if not pretend:
52 - portage.util.ensure_dirs(os.path.dirname(pkg_path))
53 - if use_locks:
54 - self.lock()
55 exists = os.path.exists(pkg_path)
56 resume = exists and os.path.basename(pkg_path) in bintree.invalids
57 if not (pretend or resume):
58 @@ -184,7 +192,7 @@ class _BinpkgFetcherProcess(SpawnProcess):
59 except OSError:
60 pass
61
62 - def lock(self):
63 + def async_lock(self):
64 """
65 This raises an AlreadyLocked exception if lock() is called
66 while a lock is already held. In order to avoid this, call
67 @@ -194,17 +202,22 @@ class _BinpkgFetcherProcess(SpawnProcess):
68 if self._lock_obj is not None:
69 raise self.AlreadyLocked((self._lock_obj,))
70
71 - async_lock = AsynchronousLock(path=self.pkg_path,
72 - scheduler=self.scheduler)
73 - async_lock.start()
74 + result = self.scheduler.create_future()
75
76 - if async_lock.wait() != os.EX_OK:
77 - # TODO: Use CompositeTask for better handling, like in EbuildPhase.
78 - raise AssertionError("AsynchronousLock failed with returncode %s" \
79 - % (async_lock.returncode,))
80 + def acquired_lock(async_lock):
81 + if async_lock.wait() == os.EX_OK:
82 + self.locked = True
83 + result.set_result(None)
84 + else:
85 + result.set_exception(AssertionError(
86 + "AsynchronousLock failed with returncode %s"
87 + % (async_lock.returncode,)))
88
89 - self._lock_obj = async_lock
90 - self.locked = True
91 + self._lock_obj = AsynchronousLock(path=self.pkg_path,
92 + scheduler=self.scheduler)
93 + self._lock_obj.addExitListener(acquired_lock)
94 + self._lock_obj.start()
95 + return result
96
97 class AlreadyLocked(portage.exception.PortageException):
98 pass
99 --
100 2.13.6

Replies