public inbox for gentoo-portage-dev@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-portage-dev] [PATCH] bindbapi: add reentrant lock method (bug 685236)
@ 2019-05-07  0:14 Zac Medico
  2019-05-07 14:55 ` Alec Warner
  0 siblings, 1 reply; 6+ messages in thread
From: Zac Medico @ 2019-05-07  0:14 UTC (permalink / raw
  To: gentoo-portage-dev; +Cc: Zac Medico

Add a reentrant lock/unlock method which is useful for things like
emaint binhost and eclean-pkg. The vardbapi class already provides
lock/unlock methods that behave the same way.

Bug: https://bugs.gentoo.org/685236
Signed-off-by: Zac Medico <zmedico@gentoo.org>
---
 lib/portage/dbapi/bintree.py                  | 46 ++++++++++++++-----
 lib/portage/emaint/modules/binhost/binhost.py |  9 ++--
 2 files changed, 38 insertions(+), 17 deletions(-)

diff --git a/lib/portage/dbapi/bintree.py b/lib/portage/dbapi/bintree.py
index 9c2d877e7..707958858 100644
--- a/lib/portage/dbapi/bintree.py
+++ b/lib/portage/dbapi/bintree.py
@@ -1,4 +1,4 @@
-# Copyright 1998-2018 Gentoo Foundation
+# Copyright 1998-2019 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 from __future__ import unicode_literals
@@ -94,6 +94,8 @@ class bindbapi(fakedbapi):
 			])
 		self._aux_cache_slot_dict = slot_dict_class(self._aux_cache_keys)
 		self._aux_cache = {}
+		self._lock = None
+		self._lock_count = 0
 
 	@property
 	def writable(self):
@@ -106,6 +108,34 @@ class bindbapi(fakedbapi):
 		"""
 		return os.access(first_existing(self.bintree.pkgdir), os.W_OK)
 
+	def lock(self):
+		"""
+		Acquire a reentrant lock, blocking, for cooperation with concurrent
+		processes.
+		"""
+		if self._lock_count <= 0:
+			if self._lock is not None:
+				raise AssertionError("already locked")
+			# At least the parent needs to exist for the lock file.
+			ensure_dirs(self.bintree.pkgdir)
+			self._lock = lockfile(self.bintree._pkgindex_file, wantnewlockfile=True)
+
+		self._lock_count += 1
+
+	def unlock(self):
+		"""
+		Release a lock, decrementing the recursion level. Each unlock() call
+		must be matched with a prior lock() call, or else an AssertionError
+		will be raised if unlock() is called while not locked.
+		"""
+		if self._lock_count <= 1:
+			if self._lock is None:
+				raise AssertionError("not locked")
+			unlockfile(self._lock)
+			self._lock = None
+
+		self._lock_count -= 1
+
 	def match(self, *pargs, **kwargs):
 		if self.bintree and not self.bintree.populated:
 			self.bintree.populate()
@@ -545,16 +575,13 @@ class binarytree(object):
 				# that changes made by a concurrent process cannot be lost. This
 				# case is avoided when possible, in order to minimize lock
 				# contention.
-				pkgindex_lock = None
+				self.dbapi.lock()
 				try:
-					pkgindex_lock = lockfile(self._pkgindex_file,
-						wantnewlockfile=True)
 					update_pkgindex = self._populate_local()
 					if update_pkgindex:
 						self._pkgindex_write(update_pkgindex)
 				finally:
-					if pkgindex_lock:
-						unlockfile(pkgindex_lock)
+					self.dbapi.unlock()
 
 			if getbinpkgs:
 				if not self.settings.get("PORTAGE_BINHOST"):
@@ -1110,10 +1137,8 @@ class binarytree(object):
 
 		# Reread the Packages index (in case it's been changed by another
 		# process) and then updated it, all while holding a lock.
-		pkgindex_lock = None
+		self.dbapi.lock()
 		try:
-			pkgindex_lock = lockfile(self._pkgindex_file,
-				wantnewlockfile=1)
 			if filename is not None:
 				new_filename = self.getname(cpv, allocate_new=True)
 				try:
@@ -1154,8 +1179,7 @@ class binarytree(object):
 			self._pkgindex_write(pkgindex)
 
 		finally:
-			if pkgindex_lock:
-				unlockfile(pkgindex_lock)
+			self.dbapi.unlock()
 
 		# This is used to record BINPKGMD5 in the installed package
 		# database, for a package that has just been built.
diff --git a/lib/portage/emaint/modules/binhost/binhost.py b/lib/portage/emaint/modules/binhost/binhost.py
index d3df0cbce..ceb9e87f3 100644
--- a/lib/portage/emaint/modules/binhost/binhost.py
+++ b/lib/portage/emaint/modules/binhost/binhost.py
@@ -1,4 +1,4 @@
-# Copyright 2005-2014 Gentoo Foundation
+# Copyright 2005-2019 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import errno
@@ -27,7 +27,6 @@ class BinhostHandler(object):
 		eroot = portage.settings['EROOT']
 		self._bintree = portage.db[eroot]["bintree"]
 		self._bintree.populate()
-		self._pkgindex_file = self._bintree._pkgindex_file
 		self._pkgindex = self._bintree._load_pkgindex()
 
 	def _need_update(self, cpv, data):
@@ -118,9 +117,7 @@ class BinhostHandler(object):
 				missing.append(cpv)
 
 		if missing or stale:
-			from portage import locks
-			pkgindex_lock = locks.lockfile(
-				self._pkgindex_file, wantnewlockfile=1)
+			bintree.dbapi.lock()
 			try:
 				# Repopulate with lock held. If _populate_local returns
 				# data then use that, since _load_pkgindex would return
@@ -174,7 +171,7 @@ class BinhostHandler(object):
 				bintree._pkgindex_write(self._pkgindex)
 
 			finally:
-				locks.unlockfile(pkgindex_lock)
+				bintree.dbapi.unlock()
 
 		if onProgress:
 			if maxval == 0:
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-05-10  9:05 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-05-07  0:14 [gentoo-portage-dev] [PATCH] bindbapi: add reentrant lock method (bug 685236) Zac Medico
2019-05-07 14:55 ` Alec Warner
2019-05-07 20:01   ` Zac Medico
2019-05-08 18:05     ` Zac Medico
2019-05-08 18:09       ` Alec Warner
2019-05-10  9:05       ` Zac Medico

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox