[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