[Zodb-checkins] CVS: Zope/lib/python/ZODB - DB.py:1.53.2.5

Tim Peters tim.one at comcast.net
Fri May 21 19:06:09 EDT 2004


Update of /cvs-repository/Zope/lib/python/ZODB
In directory cvs.zope.org:/tmp/cvs-serv28634/lib/python/ZODB

Modified Files:
      Tag: Zope-2_7-branch
	DB.py 
Log Message:
DB.open():  Under exceedingly rare conditions, a timing hole made it
possible for a second open() call on a database to block for an
arbitrarily long time.  This accounts for the intermittent failure of a
thread to make any progress after 5 minutes(!) in
checkConcurrentUpdates1Storage.  I've only seen that fail on a 3.2GHz P4
with hyper-threading enabled.  It *may* account for other rare ZEO test
failures of the "thread #n didn't add any keys" flavor (in
checkConcurrentUpdates1Storage, that turned out to be because the thread
never managed to open a connection, not because it tried to add keys but
didn't succeed -- I misunderstood the true cause for a looooong time).


=== Zope/lib/python/ZODB/DB.py 1.53.2.4 => 1.53.2.5 ===
--- Zope/lib/python/ZODB/DB.py:1.53.2.4	Mon May 10 12:07:25 2004
+++ Zope/lib/python/ZODB/DB.py	Fri May 21 19:06:03 2004
@@ -429,9 +429,9 @@
             # set whenever the pool becomes empty so that threads are
             # forced to wait until the pool gets a connection in it.
             # The lock is acquired when the (empty) pool is
-            # created. The The lock is acquired just prior to removing
-            # the last connection from the pool and just after adding
-            # a connection to an empty pool.
+            # created.  The lock is acquired just prior to removing
+            # the last connection from the pool and released just after
+            # adding a connection to an empty pool.
 
 
             if pools.has_key(version):
@@ -471,13 +471,28 @@
                     else: return
 
             elif len(pool)==1:
-                # Taking last one, lock the pool
+                # Taking last one, lock the pool.
                 # Note that another thread might grab the lock
                 # before us, so we might actually block, however,
                 # when we get the lock back, there *will* be a
-                # connection in the pool.
+                # connection in the pool.  OTOH, there's no limit on
+                # how long we may need to wait:  if the other thread
+                # grabbed the lock in this section too, we'll wait
+                # here until another connection is closed.
+                # checkConcurrentUpdates1Storage provoked this frequently
+                # on a hyperthreaded machine, with its second thread
+                # timing out after waiting 5 minutes for DB.open() to
+                # return.  So, if we can't get the pool lock immediately,
+                # now we make a recursive call.  This allows the current
+                # thread to allocate a new connection instead of waiting
+                # arbitrarily long for the single connection in the pool
+                # right now.
                 self._r()
-                pool_lock.acquire()
+                if not pool_lock.acquire(0):
+                    result = DB.open(self, version, transaction, temporary,
+                                     force, waitflag)
+                    self._a()
+                    return result
                 self._a()
                 if len(pool) > 1:
                     # Note that the pool size will normally be 1 here,
@@ -494,7 +509,8 @@
             if transaction is not None: transaction[version]=c
             return c
 
-        finally: self._r()
+        finally:
+            self._r()
 
     def removeVersionPool(self, version):
         pools, pooll = self._pools




More information about the Zodb-checkins mailing list