Commit 8e553cc4 authored by Chris McDonough's avatar Chris McDonough

Still-broken undo code that doesn't pdb.set_trace ;-)

It was impossible to commit a transaction that involved a blob that hadn't
had its 'open' method called, because the blob filename is computed during open.
parent e5dbf27c
...@@ -61,20 +61,23 @@ class BlobStorage(ProxyBase): ...@@ -61,20 +61,23 @@ class BlobStorage(ProxyBase):
# something else # something else
self._lock_acquire() self._lock_acquire()
try: # the user may not have called "open" on the blob object,
targetpath = self.fshelper.getPathForOID(oid) # in which case, the blob will not have a filename.
if not os.path.exists(targetpath): if blobfilename is not None:
os.makedirs(targetpath, 0700) try:
targetpath = self.fshelper.getPathForOID(oid)
targetname = self.fshelper.getBlobFilename(oid, serial) if not os.path.exists(targetpath):
os.rename(blobfilename, targetname) os.makedirs(targetpath, 0700)
# XXX if oid already in there, something is really hosed. targetname = self.fshelper.getBlobFilename(oid, serial)
# The underlying storage should have complained anyway os.rename(blobfilename, targetname)
self.dirty_oids.append((oid, serial))
finally: # XXX if oid already in there, something is really hosed.
self._lock_release() # The underlying storage should have complained anyway
return self._tid self.dirty_oids.append((oid, serial))
finally:
self._lock_release()
return self._tid
def tpc_finish(self, *arg, **kw): def tpc_finish(self, *arg, **kw):
""" We need to override the base storage's tpc_finish instead of """ We need to override the base storage's tpc_finish instead of
...@@ -193,29 +196,52 @@ class BlobStorage(ProxyBase): ...@@ -193,29 +196,52 @@ class BlobStorage(ProxyBase):
return orig_size + blob_size return orig_size + blob_size
def undo(self, serial_id, transaction): def undo(self, serial_id, transaction):
import pdb; pdb.set_trace() undo_serial, keys = getProxiedObject(self).undo(serial_id, transaction)
serial, keys = getProxiedObject(self).undo(serial_id, transaction) # serial_id is the transaction id of the txn that we wish to undo.
# "undo_serial" is the transaction id of txn in which the undo is
# performed. "keys" is the list of oids that are involved in the
# undo transaction.
# The serial_id is assumed to be given to us base-64 encoded
# (belying the web UI legacy of the ZODB code :-()
serial_id = base64.decodestring(serial_id+'\n')
self._lock_acquire() self._lock_acquire()
try: try:
# The old serial_id is given in base64 encoding ... # we get all the blob oids on the filesystem related to the
serial_id = base64.decodestring(serial_id+ '\n') # transaction we want to undo.
for oid in self.fshelper.getOIDsForSerial(serial_id): for oid in self.fshelper.getOIDsForSerial(serial_id):
load_result = self.loadBefore(oid, serial_id)
# we want to find the serial id of the previous revision
# of this blob object.
load_result = self.loadBefore(oid, serial_id)
if load_result is None: if load_result is None:
continue # There was no previous revision of this blob
# object. The blob was created in the transaction
data, serial_before, serial_after = load_result # represented by serial_id. We copy the blob data
# to a new file that references the undo
orig_fn = self.fshelper.getBlobFilename(oid, serial_before) # transaction in case a user wishes to undo this
# undo.
orig_fn = self.fshelper.getBlobFilename(oid, serial_id)
new_fn = self.fshelper.getBlobFilename(oid, undo_serial)
else:
# A previous revision of this blob existed before the
# transaction implied by "serial_id". We copy the blob
# data to a new file that references the undo transaction
# in case a user wishes to undo this undo.
data, serial_before, serial_after = load_result
orig_fn = self.fshelper.getBlobFilename(oid, serial_before)
new_fn = self.fshelper.getBlobFilename(oid, undo_serial)
orig = open(orig_fn, "r") orig = open(orig_fn, "r")
new_fn = self.fshelper.getBlobFilename(oid, serial)
new = open(new_fn, "wb") new = open(new_fn, "wb")
utils.cp(orig, new) utils.cp(orig, new)
orig.close() orig.close()
new.close() new.close()
self.dirty_oids.append((oid, serial)) self.dirty_oids.append((oid, undo_serial))
finally: finally:
self._lock_release() self._lock_release()
return serial, keys return undo_serial, keys
...@@ -19,6 +19,7 @@ Connections handle Blobs specially. To demonstrate that, we first need a Blob wi ...@@ -19,6 +19,7 @@ Connections handle Blobs specially. To demonstrate that, we first need a Blob wi
>>> from ZODB.Blobs.interfaces import IBlob >>> from ZODB.Blobs.interfaces import IBlob
>>> from ZODB.Blobs.Blob import Blob >>> from ZODB.Blobs.Blob import Blob
>>> import transaction
>>> blob = Blob() >>> blob = Blob()
>>> data = blob.open("w") >>> data = blob.open("w")
>>> data.write("I'm a happy Blob.") >>> data.write("I'm a happy Blob.")
...@@ -40,9 +41,16 @@ Putting a Blob into a Connection works like every other object: ...@@ -40,9 +41,16 @@ Putting a Blob into a Connection works like every other object:
>>> connection = database.open() >>> connection = database.open()
>>> root = connection.root() >>> root = connection.root()
>>> root['myblob'] = blob >>> root['myblob'] = blob
>>> import transaction
>>> transaction.commit() >>> transaction.commit()
We can also commit a transaction that seats a blob into place without
calling the blob's open method (this currently fails):
>>> nothing = transaction.begin()
>>> anotherblob = Blob()
>>> root['anotherblob'] = anotherblob
>>> nothing = transaction.commit()
Getting stuff out of there works similar: Getting stuff out of there works similar:
>>> connection2 = database.open() >>> connection2 = database.open()
...@@ -65,7 +73,8 @@ You can't put blobs into a database that has uses a Non-Blob-Storage, though: ...@@ -65,7 +73,8 @@ You can't put blobs into a database that has uses a Non-Blob-Storage, though:
... ...
Unsupported: Storing Blobs in <ZODB.MappingStorage.MappingStorage instance at ...> is not supported. Unsupported: Storing Blobs in <ZODB.MappingStorage.MappingStorage instance at ...> is not supported.
While we are testing this, we don't need the storage directory and databases anymore: While we are testing this, we don't need the storage directory and
databases anymore:
>>> import shutil >>> import shutil
>>> shutil.rmtree(blob_dir) >>> shutil.rmtree(blob_dir)
......
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