From 0ed15bb56ce1f5d33a0974f197d99aa234c277af Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Tue, 10 May 2011 12:52:36 -0700 Subject: MergeProcess: lock vdb earlier when appropriate --- pym/portage/dbapi/_MergeProcess.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/pym/portage/dbapi/_MergeProcess.py b/pym/portage/dbapi/_MergeProcess.py index 05f45d51a..62f5bec96 100644 --- a/pym/portage/dbapi/_MergeProcess.py +++ b/pym/portage/dbapi/_MergeProcess.py @@ -27,7 +27,7 @@ class MergeProcess(SpawnProcess): __slots__ = ('dblink', 'mycat', 'mypkg', 'settings', 'treetype', 'vartree', 'scheduler', 'blockers', 'pkgloc', 'infloc', 'myebuild', 'mydbapi', 'prev_mtimes', '_elog_reader_fd', '_elog_reg_id', - '_buf', '_elog_keys') + '_buf', '_elog_keys', '_locked_vdb') def _start(self): # Portage should always call setcpv prior to this @@ -48,6 +48,25 @@ class MergeProcess(SpawnProcess): self._handle_self_reinstall() super(MergeProcess, self)._start() + def _lock_vdb(self): + """ + Lock the vdb if FEATURES=parallel-install is NOT enabled, + otherwise do nothing. This is implemented with + vardbapi.lock(), which supports reentrance by the + subprocess that we spawn. + """ + if "parallel-install" not in self.settings.features: + self.vartree.dbapi.lock() + self._locked_vdb = True + + def _unlock_vdb(self): + """ + Unlock the vdb if we hold a lock, otherwise do nothing. + """ + if self._locked_vdb: + self.vartree.dbapi.unlock() + self._locked_vdb = False + def _handle_self_reinstall(self): """ If portage is reinstalling itself, create temporary @@ -143,6 +162,14 @@ class MergeProcess(SpawnProcess): fd_pipes[elog_writer_fd] = elog_writer_fd self._elog_reg_id = self.scheduler.register(elog_reader_fd, self._registered_events, self._elog_output_handler) + + # If a concurrent emerge process tries to install a package + # in the same SLOT as this one at the same time, there is an + # extremely unlikely chance that the COUNTER values will not be + # ordered correctly unless we lock the vdb here. + # FEATURES=parallel-install skips this lock in order to + # improve performance, and the risk is practically negligible. + self._lock_vdb() counter = self.vartree.dbapi.counter_tick() pid = os.fork() @@ -211,6 +238,7 @@ class MergeProcess(SpawnProcess): """ Unregister from the scheduler and close open files. """ + self._unlock_vdb() if self._elog_reg_id is not None: self.scheduler.unregister(self._elog_reg_id) self._elog_reg_id = None -- cgit v1.2.3-1-g7c22