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 1/6] EbuildBuildDir: add async_lock method (bug 614112)
Date: Sat, 21 Apr 2018 08:28:26
Message-Id: 20180421082440.32706-2-zmedico@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH 0/6] EbuildBuildDir: add async_lock method (bug 614112) by Zac Medico
1 Asynchronoulsy handle locking of both the category directory and
2 build directory.
3
4 Bug: https://bugs.gentoo.org/614112
5 ---
6 pym/_emerge/EbuildBuildDir.py | 76 +++++++++++++++++++++++++++++++++++++++++++
7 1 file changed, 76 insertions(+)
8
9 diff --git a/pym/_emerge/EbuildBuildDir.py b/pym/_emerge/EbuildBuildDir.py
10 index 69f694992..9163deacf 100644
11 --- a/pym/_emerge/EbuildBuildDir.py
12 +++ b/pym/_emerge/EbuildBuildDir.py
13 @@ -1,6 +1,8 @@
14 # Copyright 1999-2012 Gentoo Foundation
15 # Distributed under the terms of the GNU General Public License v2
16
17 +import functools
18 +
19 from _emerge.AsynchronousLock import AsynchronousLock
20
21 import portage
22 @@ -84,6 +86,80 @@ class EbuildBuildDir(SlotObject):
23 except OSError:
24 pass
25
26 + def async_lock(self):
27 + """
28 + Acquire the lock asynchronously. Notification is available
29 + via the add_done_callback method of the returned Future instance.
30 +
31 + This raises an AlreadyLocked exception if async_lock() is called
32 + while a lock is already held. In order to avoid this, call
33 + async_unlock() or check whether the "locked" attribute is True
34 + or False before calling async_lock().
35 +
36 + @returns: Future, result is None
37 + """
38 + if self._lock_obj is not None:
39 + raise self.AlreadyLocked((self._lock_obj,))
40 +
41 + dir_path = self.settings.get('PORTAGE_BUILDDIR')
42 + if not dir_path:
43 + raise AssertionError('PORTAGE_BUILDDIR is unset')
44 + catdir = os.path.dirname(dir_path)
45 + self._catdir = catdir
46 + catdir_lock = AsynchronousLock(path=catdir, scheduler=self.scheduler)
47 + builddir_lock = AsynchronousLock(path=dir_path, scheduler=self.scheduler)
48 + result = self.scheduler.create_future()
49 +
50 + def catdir_locked(catdir_lock):
51 + try:
52 + self._assert_lock(catdir_lock)
53 + except AssertionError as e:
54 + result.set_exception(e)
55 + return
56 +
57 + try:
58 + portage.util.ensure_dirs(catdir,
59 + gid=portage.portage_gid,
60 + mode=0o70, mask=0)
61 + except PortageException as e:
62 + if not os.path.isdir(catdir):
63 + result.set_exception(e)
64 + return
65 +
66 + builddir_lock.addExitListener(builddir_locked)
67 + builddir_lock.start()
68 +
69 + def builddir_locked(builddir_lock):
70 + try:
71 + self._assert_lock(builddir_lock)
72 + except AssertionError as e:
73 + catdir_lock.async_unlock.add_done_callback(
74 + functools.partial(catdir_unlocked, exception=e))
75 + return
76 +
77 + self._lock_obj = builddir_lock
78 + self.locked = True
79 + self.settings['PORTAGE_BUILDDIR_LOCKED'] = '1'
80 + catdir_lock.async_unlock().add_done_callback(catdir_unlocked)
81 +
82 + def catdir_unlocked(future, exception=None):
83 + if not (exception is None and future.exception() is None):
84 + result.set_exception(exception or future.exception())
85 + else:
86 + result.set_result(None)
87 +
88 + try:
89 + portage.util.ensure_dirs(os.path.dirname(catdir),
90 + gid=portage.portage_gid,
91 + mode=0o70, mask=0)
92 + except PortageException:
93 + if not os.path.isdir(os.path.dirname(catdir)):
94 + raise
95 +
96 + catdir_lock.addExitListener(catdir_locked)
97 + catdir_lock.start()
98 + return result
99 +
100 def async_unlock(self):
101 """
102 Release the lock asynchronously. Release notification is available
103 --
104 2.13.6