Bug #336142 - Add support for using a thread to wait for locks inside
authorZac Medico <zmedico@gentoo.org>
Mon, 13 Sep 2010 07:23:34 +0000 (00:23 -0700)
committerZac Medico <zmedico@gentoo.org>
Mon, 13 Sep 2010 07:23:34 +0000 (00:23 -0700)
dblink.lockdb() so that the scheduler can concurrently service ipc
calls in the main thread.

pym/portage/dbapi/vartree.py
pym/portage/locks.py

index fddb4326cb99573da0dce8b8c5f422afc62c8c4c..19ebaaa763c2ebb03b4f95205eb13c93c2dd45a3 100644 (file)
@@ -37,7 +37,7 @@ from portage.const import _ENABLE_DYN_LINK_MAP, _ENABLE_PRESERVE_LIBS
 from portage.dbapi import dbapi
 from portage.exception import CommandNotFound, \
        InvalidData, InvalidPackageName, \
-       FileNotFound, PermissionDenied, UnsupportedAPIException
+       FileNotFound, PermissionDenied, TryAgain, UnsupportedAPIException
 from portage.localization import _
 from portage.util.movefile import movefile
 
@@ -62,6 +62,10 @@ import os as _os
 import stat
 import sys
 import tempfile
+try:
+       import threading
+except ImportError:
+       import dummy_threading as threading
 import time
 import warnings
 
@@ -1276,13 +1280,39 @@ class dblink(object):
                        raise AssertionError("Lock already held.")
                # At least the parent needs to exist for the lock file.
                ensure_dirs(self.dbroot)
-               self._lock_vdb = lockdir(self.dbroot)
+               if self._scheduler is None:
+                       self._lock_vdb = lockdir(self.dbroot)
+               else:
+                       try:
+                               self._lock_vdb = lockdir(self.dbroot, flags=os.O_NONBLOCK)
+                       except TryAgain:
+                               self._lockdb_rlock = threading.RLock()
+                               lockdb_thread = threading.Thread(
+                                       target=self._lockdb_thread)
+                               lockdb_thread.start()
+                               if not self._lockdb_have_lock():
+                                       self._scheduler.schedule(
+                                               condition=self._lockdb_have_lock)
+                               lockdb_thread.join()
+                               self._lockdb_rlock = None
 
        def unlockdb(self):
                if self._lock_vdb:
                        unlockdir(self._lock_vdb)
                        self._lock_vdb = None
 
+       def _lockdb_thread(self):
+               lock_vdb = lockdir(self.dbroot)
+               self._lockdb_rlock.acquire()
+               self._lock_vdb = lock_vdb
+               self._lockdb_rlock.release()
+
+       def _lockdb_have_lock(self):
+               self._lockdb_rlock.acquire()
+               rval = self._lock_vdb is not None
+               self._lockdb_rlock.release()
+               return rval
+
        def getpath(self):
                "return path to location of db information (for >>> informational display)"
                return self.dbdir
index ed20e30ca1538363ada917abd1fb2da17d22035e..00a50b818e79da8a42642dc1fb43301ca1699d2c 100644 (file)
@@ -30,8 +30,8 @@ HARDLINK_FD = -2
 # so that it doesn't interfere with the status display.
 _quiet = False
 
-def lockdir(mydir):
-       return lockfile(mydir,wantnewlockfile=1)
+def lockdir(mydir, flags=0):
+       return lockfile(mydir, wantnewlockfile=1, flags=flags)
 def unlockdir(mylock):
        return unlockfile(mylock)