Commit 45204a84 authored by Jim Fulton's avatar Jim Fulton

Refactored to avoid a race condition between saving a blob to the

cache and cleaning the cache.
parent 50ef95c6
...@@ -1006,15 +1006,7 @@ class ClientStorage(object): ...@@ -1006,15 +1006,7 @@ class ClientStorage(object):
# getting it multiple times even accross separate client # getting it multiple times even accross separate client
# processes on the same machine. We'll use file locking. # processes on the same machine. We'll use file locking.
lockfilename = os.path.join(os.path.dirname(blob_filename), '.lock') lock = _lock_blob(blob_filename)
while 1:
try:
lock = zc.lockfile.LockFile(lockfilename)
except zc.lockfile.LockError:
time.sleep(0.01)
else:
break
try: try:
# We got the lock, so it's our job to download it. First, # 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 # we'll double check that someone didn't download it while we
...@@ -1049,15 +1041,7 @@ class ClientStorage(object): ...@@ -1049,15 +1041,7 @@ class ClientStorage(object):
# Fall through and try again with the protection of the lock. # Fall through and try again with the protection of the lock.
pass pass
lockfilename = os.path.join(os.path.dirname(blob_filename), '.lock') lock = _lock_blob(blob_filename)
while 1:
try:
lock = zc.lockfile.LockFile(lockfilename)
except zc.lockfile.LockError:
time.sleep(.01)
else:
break
try: try:
blob_filename = self.fshelper.getBlobFilename(oid, serial) blob_filename = self.fshelper.getBlobFilename(oid, serial)
if not os.path.exists(blob_filename): if not os.path.exists(blob_filename):
...@@ -1216,14 +1200,23 @@ class ClientStorage(object): ...@@ -1216,14 +1200,23 @@ class ClientStorage(object):
if self.fshelper is not None: if self.fshelper is not None:
blobs = self._tbuf.blobs blobs = self._tbuf.blobs
had_blobs = False
while blobs: while blobs:
oid, blobfilename = blobs.pop() oid, blobfilename = blobs.pop()
self._blob_data_bytes_loaded += os.stat(blobfilename).st_size self._blob_data_bytes_loaded += os.stat(blobfilename).st_size
targetpath = self.fshelper.getPathForOID(oid, create=True) targetpath = self.fshelper.getPathForOID(oid, create=True)
target_blob_file_name = self.fshelper.getBlobFilename(oid, tid)
lock = _lock_blob(target_blob_file_name)
try:
ZODB.blob.rename_or_copy_blob( ZODB.blob.rename_or_copy_blob(
blobfilename, blobfilename,
self.fshelper.getBlobFilename(oid, tid), target_blob_file_name,
) )
finally:
lock.close()
had_blobs = True
if had_blobs:
self._check_blob_size(self._blob_data_bytes_loaded) self._check_blob_size(self._blob_data_bytes_loaded)
self._tbuf.clear() self._tbuf.clear()
...@@ -1724,3 +1717,17 @@ def check_blob_size_script(args=None): ...@@ -1724,3 +1717,17 @@ def check_blob_size_script(args=None):
args = sys.argv[1:] args = sys.argv[1:]
blob_dir, target = args blob_dir, target = args
_check_blob_cache_size(blob_dir, int(target)) _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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment