From 39b034d11b8a3118e8c1cfc6f6d06df43e5efa35 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Sat, 14 May 2011 19:43:12 -0700 Subject: vardbapi: add reentrant _fs_lock/unlock methods --- pym/portage/dbapi/vartree.py | 65 +++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index d1905663d..a2e38f6ec 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -140,6 +140,10 @@ class vardbapi(dbapi): self._lock = None self._lock_count = 0 + self._conf_mem_file = self._eroot + CONFIG_MEMORY_FILE + self._fs_lock_obj = None + self._fs_lock_count = 0 + if vartree is None: vartree = portage.db[self.root]["vartree"] self.vartree = vartree @@ -210,6 +214,28 @@ class vardbapi(dbapi): unlockdir(self._lock) self._lock = None + def _fs_lock(self): + """ + Acquire a reentrant lock, blocking, for cooperation with concurrent + processes. + """ + if self._fs_lock_count < 1: + if self._fs_lock_obj is not None: + raise AssertionError("already locked") + self._fs_lock_obj = lockfile(self._conf_mem_file) + self._fs_lock_count += 1 + + def _fs_unlock(self): + """ + Release a lock, decrementing the recursion level. + """ + if self._fs_lock_count <= 1: + if self._fs_lock_obj is None: + raise AssertionError("not locked") + unlockfile(self._fs_lock_obj) + self._fs_lock_obj = None + self._fs_lock_count -= 1 + def _bump_mtime(self, cpv): """ This is called before an after any modifications, so that consumers @@ -1680,12 +1706,11 @@ class dblink(object): showMessage(_("!!! FAILED prerm: %s\n") % retval, level=logging.ERROR, noiselevel=-1) - conf_mem_file = os.path.join(self._eroot, CONFIG_MEMORY_FILE) - conf_mem_lock = lockfile(conf_mem_file) + self.vartree.dbapi._fs_lock() try: - self._unmerge_pkgfiles(pkgfiles, others_in_slot, conf_mem_file) + self._unmerge_pkgfiles(pkgfiles, others_in_slot) finally: - unlockfile(conf_mem_lock) + self.vartree.dbapi._fs_unlock() self._clear_contents_cache() if myebuildpath: @@ -1795,15 +1820,14 @@ class dblink(object): # Lock the config memory file to prevent symlink creation # in merge_contents from overlapping with env-update. - conf_mem_file = os.path.join(self._eroot, CONFIG_MEMORY_FILE) - conf_mem_lock = lockfile(conf_mem_file) + self.vartree.dbapi._fs_lock() try: env_update(target_root=self.settings['ROOT'], prev_mtimes=ldpath_mtimes, contents=contents, env=self.settings.environ(), writemsg_level=self._display_merge) finally: - unlockfile(conf_mem_lock) + self.vartree.dbapi._fs_unlock() return os.EX_OK @@ -1826,7 +1850,7 @@ class dblink(object): log_path=log_path, background=background, level=level, noiselevel=noiselevel) - def _unmerge_pkgfiles(self, pkgfiles, others_in_slot, conf_mem_file): + def _unmerge_pkgfiles(self, pkgfiles, others_in_slot): """ Unmerges the contents of a package from the liveFS @@ -1862,7 +1886,7 @@ class dblink(object): dest_root = self._eroot dest_root_len = len(dest_root) - 1 - cfgfiledict = grabdict(conf_mem_file) + cfgfiledict = grabdict(self.vartree.dbapi._conf_mem_file) stale_confmem = [] unmerge_orphans = "unmerge-orphans" in self.settings.features @@ -2112,7 +2136,7 @@ class dblink(object): if stale_confmem: for filename in stale_confmem: del cfgfiledict[filename] - writedict(cfgfiledict, conf_mem_file) + writedict(cfgfiledict, self.vartree.dbapi._conf_mem_file) #remove self from vartree database so that our own virtual gets zapped if we're the last node self.vartree.zap(self.mycpv) @@ -3342,10 +3366,9 @@ class dblink(object): self.updateprotect() #if we have a file containing previously-merged config file md5sums, grab it. - conf_mem_file = os.path.join(self._eroot, CONFIG_MEMORY_FILE) - conf_mem_lock = lockfile(conf_mem_file) + self.vartree.dbapi._fs_lock() try: - cfgfiledict = grabdict(conf_mem_file) + cfgfiledict = grabdict(self.vartree.dbapi._conf_mem_file) if "NOCONFMEM" in self.settings: cfgfiledict["IGNORE"]=1 else: @@ -3360,12 +3383,11 @@ class dblink(object): cfgfiledict["IGNORE"] = 1 break - rval = self._merge_contents(srcroot, destroot, cfgfiledict, - conf_mem_file) + rval = self._merge_contents(srcroot, destroot, cfgfiledict) if rval != os.EX_OK: return rval finally: - unlockfile(conf_mem_lock) + self.vartree.dbapi._fs_unlock() # These caches are populated during collision-protect and the data # they contain is now invalid. It's very important to invalidate @@ -3573,8 +3595,7 @@ class dblink(object): # Lock the config memory file to prevent symlink creation # in merge_contents from overlapping with env-update. - conf_mem_file = os.path.join(self._eroot, CONFIG_MEMORY_FILE) - conf_mem_lock = lockfile(conf_mem_file) + self.vartree.dbapi._fs_lock() try: #update environment settings, library paths. DO NOT change symlinks. env_update(makelinks=(not downgrade), @@ -3582,7 +3603,7 @@ class dblink(object): contents=contents, env=self.settings.environ(), writemsg_level=self._display_merge) finally: - unlockfile(conf_mem_lock) + self.vartree.dbapi._fs_unlock() # For gcc upgrades, preserved libs have to be removed after the # the library path has been updated. @@ -3610,7 +3631,7 @@ class dblink(object): return backup_p - def _merge_contents(self, srcroot, destroot, cfgfiledict, conf_mem_file): + def _merge_contents(self, srcroot, destroot, cfgfiledict): cfgfiledict_orig = cfgfiledict.copy() @@ -3672,9 +3693,9 @@ class dblink(object): # write out our collection of md5sums if cfgfiledict != cfgfiledict_orig: cfgfiledict.pop("IGNORE", None) - ensure_dirs(os.path.dirname(conf_mem_file), + ensure_dirs(os.path.dirname(self.vartree.dbapi._conf_mem_file), gid=portage_gid, mode=0o2750, mask=0o2) - writedict(cfgfiledict, conf_mem_file) + writedict(cfgfiledict, self.vartree.dbapi._conf_mem_file) return os.EX_OK -- cgit v1.2.3-1-g7c22