[Zodb-checkins] SVN: ZODB/trunk/src/ZEO/ClientStorage.py Refactored to avoid a race condition between saving a blob to the

Jim Fulton jim at zope.com
Wed Jun 10 18:03:28 EDT 2009


Log message for revision 100815:
  Refactored to avoid a race condition between saving a blob to the
  cache and cleaning the cache.
  

Changed:
  U   ZODB/trunk/src/ZEO/ClientStorage.py

-=-
Modified: ZODB/trunk/src/ZEO/ClientStorage.py
===================================================================
--- ZODB/trunk/src/ZEO/ClientStorage.py	2009-06-10 21:40:56 UTC (rev 100814)
+++ ZODB/trunk/src/ZEO/ClientStorage.py	2009-06-10 22:03:27 UTC (rev 100815)
@@ -1006,15 +1006,7 @@
         # getting it multiple times even accross separate client
         # processes on the same machine. We'll use file locking.
 
-        lockfilename = os.path.join(os.path.dirname(blob_filename), '.lock')
-        while 1:
-            try:
-                lock = zc.lockfile.LockFile(lockfilename)
-            except zc.lockfile.LockError:
-                time.sleep(0.01)
-            else:
-                break
-
+        lock = _lock_blob(blob_filename)
         try:
             # We got the lock, so it's our job to download it.  First,
             # we'll double check that someone didn't download it while we
@@ -1049,15 +1041,7 @@
             # Fall through and try again with the protection of the lock.
             pass
 
-        lockfilename = os.path.join(os.path.dirname(blob_filename), '.lock')
-        while 1:
-            try:
-                lock = zc.lockfile.LockFile(lockfilename)
-            except zc.lockfile.LockError:
-                time.sleep(.01)
-            else:
-                break
-
+        lock = _lock_blob(blob_filename)
         try:
             blob_filename = self.fshelper.getBlobFilename(oid, serial)
             if not os.path.exists(blob_filename):
@@ -1216,14 +1200,23 @@
 
         if self.fshelper is not None:
             blobs = self._tbuf.blobs
+            had_blobs = False
             while blobs:
                 oid, blobfilename = blobs.pop()
                 self._blob_data_bytes_loaded += os.stat(blobfilename).st_size
                 targetpath = self.fshelper.getPathForOID(oid, create=True)
-                ZODB.blob.rename_or_copy_blob(
-                    blobfilename,
-                    self.fshelper.getBlobFilename(oid, tid),
-                    )
+                target_blob_file_name = self.fshelper.getBlobFilename(oid, tid)
+                lock = _lock_blob(target_blob_file_name)
+                try:
+                    ZODB.blob.rename_or_copy_blob(
+                        blobfilename,
+                        target_blob_file_name,
+                        )
+                finally:
+                    lock.close()
+                had_blobs = True
+
+            if had_blobs:
                 self._check_blob_size(self._blob_data_bytes_loaded)
 
         self._tbuf.clear()
@@ -1724,3 +1717,17 @@
         args = sys.argv[1:]
     blob_dir, target = args
     _check_blob_cache_size(blob_dir, int(target))
+
+def _lock_blob(path):
+    lockfilename = os.path.join(os.path.dirname(path), '.lock')
+    n = 0
+    while 1:
+        try:
+            return zc.lockfile.LockFile(lockfilename)
+        except zc.lockfile.LockError:
+            time.sleep(0.01)
+            n += 1
+            if n > 60000:
+                raise
+        else:
+            break



More information about the Zodb-checkins mailing list