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] bindbapi: add reentrant lock method (bug 685236)
Date: Tue, 07 May 2019 00:15:04
Message-Id: 20190507001437.25448-1-zmedico@gentoo.org
1 Add a reentrant lock/unlock method which is useful for things like
2 emaint binhost and eclean-pkg. The vardbapi class already provides
3 lock/unlock methods that behave the same way.
4
5 Bug: https://bugs.gentoo.org/685236
6 Signed-off-by: Zac Medico <zmedico@g.o>
7 ---
8 lib/portage/dbapi/bintree.py | 46 ++++++++++++++-----
9 lib/portage/emaint/modules/binhost/binhost.py | 9 ++--
10 2 files changed, 38 insertions(+), 17 deletions(-)
11
12 diff --git a/lib/portage/dbapi/bintree.py b/lib/portage/dbapi/bintree.py
13 index 9c2d877e7..707958858 100644
14 --- a/lib/portage/dbapi/bintree.py
15 +++ b/lib/portage/dbapi/bintree.py
16 @@ -1,4 +1,4 @@
17 -# Copyright 1998-2018 Gentoo Foundation
18 +# Copyright 1998-2019 Gentoo Authors
19 # Distributed under the terms of the GNU General Public License v2
20
21 from __future__ import unicode_literals
22 @@ -94,6 +94,8 @@ class bindbapi(fakedbapi):
23 ])
24 self._aux_cache_slot_dict = slot_dict_class(self._aux_cache_keys)
25 self._aux_cache = {}
26 + self._lock = None
27 + self._lock_count = 0
28
29 @property
30 def writable(self):
31 @@ -106,6 +108,34 @@ class bindbapi(fakedbapi):
32 """
33 return os.access(first_existing(self.bintree.pkgdir), os.W_OK)
34
35 + def lock(self):
36 + """
37 + Acquire a reentrant lock, blocking, for cooperation with concurrent
38 + processes.
39 + """
40 + if self._lock_count <= 0:
41 + if self._lock is not None:
42 + raise AssertionError("already locked")
43 + # At least the parent needs to exist for the lock file.
44 + ensure_dirs(self.bintree.pkgdir)
45 + self._lock = lockfile(self.bintree._pkgindex_file, wantnewlockfile=True)
46 +
47 + self._lock_count += 1
48 +
49 + def unlock(self):
50 + """
51 + Release a lock, decrementing the recursion level. Each unlock() call
52 + must be matched with a prior lock() call, or else an AssertionError
53 + will be raised if unlock() is called while not locked.
54 + """
55 + if self._lock_count <= 1:
56 + if self._lock is None:
57 + raise AssertionError("not locked")
58 + unlockfile(self._lock)
59 + self._lock = None
60 +
61 + self._lock_count -= 1
62 +
63 def match(self, *pargs, **kwargs):
64 if self.bintree and not self.bintree.populated:
65 self.bintree.populate()
66 @@ -545,16 +575,13 @@ class binarytree(object):
67 # that changes made by a concurrent process cannot be lost. This
68 # case is avoided when possible, in order to minimize lock
69 # contention.
70 - pkgindex_lock = None
71 + self.dbapi.lock()
72 try:
73 - pkgindex_lock = lockfile(self._pkgindex_file,
74 - wantnewlockfile=True)
75 update_pkgindex = self._populate_local()
76 if update_pkgindex:
77 self._pkgindex_write(update_pkgindex)
78 finally:
79 - if pkgindex_lock:
80 - unlockfile(pkgindex_lock)
81 + self.dbapi.unlock()
82
83 if getbinpkgs:
84 if not self.settings.get("PORTAGE_BINHOST"):
85 @@ -1110,10 +1137,8 @@ class binarytree(object):
86
87 # Reread the Packages index (in case it's been changed by another
88 # process) and then updated it, all while holding a lock.
89 - pkgindex_lock = None
90 + self.dbapi.lock()
91 try:
92 - pkgindex_lock = lockfile(self._pkgindex_file,
93 - wantnewlockfile=1)
94 if filename is not None:
95 new_filename = self.getname(cpv, allocate_new=True)
96 try:
97 @@ -1154,8 +1179,7 @@ class binarytree(object):
98 self._pkgindex_write(pkgindex)
99
100 finally:
101 - if pkgindex_lock:
102 - unlockfile(pkgindex_lock)
103 + self.dbapi.unlock()
104
105 # This is used to record BINPKGMD5 in the installed package
106 # database, for a package that has just been built.
107 diff --git a/lib/portage/emaint/modules/binhost/binhost.py b/lib/portage/emaint/modules/binhost/binhost.py
108 index d3df0cbce..ceb9e87f3 100644
109 --- a/lib/portage/emaint/modules/binhost/binhost.py
110 +++ b/lib/portage/emaint/modules/binhost/binhost.py
111 @@ -1,4 +1,4 @@
112 -# Copyright 2005-2014 Gentoo Foundation
113 +# Copyright 2005-2019 Gentoo Authors
114 # Distributed under the terms of the GNU General Public License v2
115
116 import errno
117 @@ -27,7 +27,6 @@ class BinhostHandler(object):
118 eroot = portage.settings['EROOT']
119 self._bintree = portage.db[eroot]["bintree"]
120 self._bintree.populate()
121 - self._pkgindex_file = self._bintree._pkgindex_file
122 self._pkgindex = self._bintree._load_pkgindex()
123
124 def _need_update(self, cpv, data):
125 @@ -118,9 +117,7 @@ class BinhostHandler(object):
126 missing.append(cpv)
127
128 if missing or stale:
129 - from portage import locks
130 - pkgindex_lock = locks.lockfile(
131 - self._pkgindex_file, wantnewlockfile=1)
132 + bintree.dbapi.lock()
133 try:
134 # Repopulate with lock held. If _populate_local returns
135 # data then use that, since _load_pkgindex would return
136 @@ -174,7 +171,7 @@ class BinhostHandler(object):
137 bintree._pkgindex_write(self._pkgindex)
138
139 finally:
140 - locks.unlockfile(pkgindex_lock)
141 + bintree.dbapi.unlock()
142
143 if onProgress:
144 if maxval == 0:
145 --
146 2.21.0

Replies