Commit 4a87e726 authored by Jim Fulton's avatar Jim Fulton

Fixed bug:

  When committing transactions involving blobs to ClientStorages with
  non-shared blob directories, a failure could occur in tpc_finish if
  there was insufficient disk space to copy the blob file or if the
  file wasn't available.  https://bugs.launchpad.net/zodb/+bug/224169

Now link/copy file when storeBlob is called.
parent a4a3c368
...@@ -918,33 +918,29 @@ class ClientStorage(object): ...@@ -918,33 +918,29 @@ class ClientStorage(object):
def storeBlob(self, oid, serial, data, blobfilename, version, txn): def storeBlob(self, oid, serial, data, blobfilename, version, txn):
"""Storage API: store a blob object.""" """Storage API: store a blob object."""
assert not version assert not version
serials = self.store(oid, serial, data, '', txn)
if self.shared_blob_dir:
self._storeBlob_shared(oid, serial, data, blobfilename, txn)
else:
self._server.storeBlob(oid, serial, data, blobfilename, txn)
self._tbuf.storeBlob(oid, blobfilename)
return serials
def _storeBlob_shared(self, oid, serial, data, filename, txn): # Grab the file right away. That way, if we don't have enough
# First, move the blob into the blob directory # room for a copy, we'll know now rather than in tpc_finish.
# Also, this releaves the client of having to manage the file
# (or the directory contianing it).
self.fshelper.getPathForOID(oid, create=True) self.fshelper.getPathForOID(oid, create=True)
fd, target = self.fshelper.blob_mkstemp(oid, serial) fd, target = self.fshelper.blob_mkstemp(oid, serial)
os.close(fd) os.close(fd)
if sys.platform == 'win32': # It's a bit odd (and impossible on windows) to rename over
# On windows, we can't rename to an existing file. We'll # an existing file. We'll use the temporary file name as a base.
# use a slightly different file name. We keep the old one target += '-'
# until we're done to avoid conflicts. Then remove the old name. ZODB.blob.rename_or_copy_blob(blobfilename, target)
target += 'w' os.remove(target[:-1])
ZODB.blob.rename_or_copy_blob(filename, target)
os.remove(target[:-1])
else:
ZODB.blob.rename_or_copy_blob(filename, target)
# Now tell the server where we put it serials = self.store(oid, serial, data, '', txn)
self._server.storeBlobShared( if self.shared_blob_dir:
oid, serial, data, os.path.basename(target), id(txn)) self._server.storeBlobShared(
oid, serial, data, os.path.basename(target), id(txn))
else:
self._server.storeBlob(oid, serial, data, target, txn)
self._tbuf.storeBlob(oid, target)
return serials
def receiveBlobStart(self, oid, serial): def receiveBlobStart(self, oid, serial):
blob_filename = self.fshelper.getBlobFilename(oid, serial) blob_filename = self.fshelper.getBlobFilename(oid, serial)
......
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