Commit 4e92bbdc authored by Gary Poster's avatar Gary Poster

fix bug with MVCC and blobs.

parent acee9cf4
...@@ -53,6 +53,9 @@ Blobs ...@@ -53,6 +53,9 @@ Blobs
- (3.9.0a1) Fixed bug #129921: getSize() function in BlobStorage could not - (3.9.0a1) Fixed bug #129921: getSize() function in BlobStorage could not
deal with garbage files deal with garbage files
- (unreleased, after 3.9.0a1) Fixed bug in which MVCC would not work for
blobs.
BTrees BTrees
------ ------
......
...@@ -894,6 +894,12 @@ class Connection(ExportImport, object): ...@@ -894,6 +894,12 @@ class Connection(ExportImport, object):
assert self._txn_time <= end, (u64(self._txn_time), u64(end)) assert self._txn_time <= end, (u64(self._txn_time), u64(end))
self._reader.setGhostState(obj, data) self._reader.setGhostState(obj, data)
obj._p_serial = start obj._p_serial = start
# MVCC Blob support
if isinstance(obj, Blob):
obj._p_blob_uncommitted = None
obj._p_blob_committed = self._storage.loadBlob(obj._p_oid, start)
return True return True
def _handle_independent(self, obj): def _handle_independent(self, obj):
......
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
Connection support for Blobs tests Connection support for Blobs tests
================================== ==================================
Connections handle Blobs specially. To demonstrate that, we first need a Blob with some data: Connections handle Blobs specially. To demonstrate that, we first need a Blob
with some data:
>>> from ZODB.interfaces import IBlob >>> from ZODB.interfaces import IBlob
>>> from ZODB.blob import Blob >>> from ZODB.blob import Blob
...@@ -25,13 +26,16 @@ Connections handle Blobs specially. To demonstrate that, we first need a Blob wi ...@@ -25,13 +26,16 @@ Connections handle Blobs specially. To demonstrate that, we first need a Blob wi
>>> data.write("I'm a happy Blob.") >>> data.write("I'm a happy Blob.")
>>> data.close() >>> data.close()
We also need a database with a blob supporting storage: We also need a database with a blob supporting storage. (We're going to use
FileStorage rather than MappingStorage here because we will want ``loadBefore``
for one of our examples.)
>>> from ZODB.MappingStorage import MappingStorage >>> import ZODB.FileStorage
>>> from ZODB.blob import BlobStorage >>> from ZODB.blob import BlobStorage
>>> from ZODB.DB import DB >>> from ZODB.DB import DB
>>> from tempfile import mkdtemp >>> from tempfile import mkdtemp
>>> base_storage = MappingStorage("test") >>> base_storage = ZODB.FileStorage.FileStorage(
... 'BlobTests.fs', create=True)
>>> blob_dir = mkdtemp() >>> blob_dir = mkdtemp()
>>> blob_storage = BlobStorage(blob_dir, base_storage) >>> blob_storage = BlobStorage(blob_dir, base_storage)
>>> database = DB(blob_storage) >>> database = DB(blob_storage)
...@@ -51,31 +55,55 @@ calling the blob's open method: ...@@ -51,31 +55,55 @@ calling the blob's open method:
>>> root['anotherblob'] = anotherblob >>> root['anotherblob'] = anotherblob
>>> nothing = transaction.commit() >>> nothing = transaction.commit()
Getting stuff out of there works similar: Getting stuff out of there works similarly:
>>> connection2 = database.open() >>> transaction2 = transaction.TransactionManager()
>>> connection2 = database.open(transaction_manager=transaction2)
>>> root = connection2.root() >>> root = connection2.root()
>>> blob2 = root['myblob'] >>> blob2 = root['myblob']
>>> IBlob.providedBy(blob2) >>> IBlob.providedBy(blob2)
True True
>>> blob2.open("r").read() >>> blob2.open("r").read()
"I'm a happy Blob." "I'm a happy Blob."
>>> transaction2.abort()
MVCC also works.
>>> transaction3 = transaction.TransactionManager()
>>> connection3 = database.open(transaction_manager=transaction3)
>>> f = connection.root()['myblob'].open('w')
>>> f.write('I am an ecstatic Blob.')
>>> f.close()
>>> transaction.commit()
>>> connection3.root()['myblob'].open('r').read()
"I'm a happy Blob."
>>> transaction2.abort()
>>> transaction3.abort()
>>> connection2.close()
>>> connection3.close()
You can't put blobs into a database that has uses a Non-Blob-Storage, though: You can't put blobs into a database that has uses a Non-Blob-Storage, though:
>>> from ZODB.MappingStorage import MappingStorage
>>> no_blob_storage = MappingStorage() >>> no_blob_storage = MappingStorage()
>>> database2 = DB(no_blob_storage) >>> database2 = DB(no_blob_storage)
>>> connection3 = database2.open() >>> connection2 = database2.open(transaction_manager=transaction2)
>>> root = connection3.root() >>> root = connection2.root()
>>> root['myblob'] = Blob() >>> root['myblob'] = Blob()
>>> transaction.commit() # doctest: +ELLIPSIS >>> transaction2.commit() # doctest: +ELLIPSIS
Traceback (most recent call last): Traceback (most recent call last):
... ...
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 >>> transaction2.abort()
databases anymore: >>> connection2.close()
After testing this, we don't need the storage directory and databases anymore:
>>> transaction.abort() >>> transaction.abort()
>>> connection.close()
>>> database.close() >>> database.close()
>>> database2.close() >>> database2.close()
>>> blob_storage.close()
>>> base_storage.cleanup()
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