Commit 6a3a3773 authored by Christian Theune's avatar Christian Theune

- added testing and fixes for optimistic savepoint support

parent 02955468
......@@ -21,6 +21,8 @@ We need a database with a blob supporting storage:
>>> from ZODB.Blobs.BlobStorage import BlobStorage
>>> from ZODB.DB import DB
>>> import transaction
>>> import tempfile
>>> tempfile.tempdir = "/home/ctheune/blobtemp"
>>> from tempfile import mkdtemp
>>> base_storage = MappingStorage("test")
>>> blob_dir = mkdtemp()
......@@ -177,6 +179,14 @@ connections should result in a write conflict error.
...
ConflictError: database conflict error (oid 0x01, class ZODB.Blobs.Blob.Blob)
After the conflict, the winning transaction's result is visible on both
connections:
>>> root3['blob1'].open('r').read()
'this is blob 1woot!this is from connection 3'
>>> root2['blob1'].open('r').read()
'this is blob 1woot!this is from connection 3'
BlobStorages implementation of getSize() includes the blob data and adds it to
the underlying storages result of getSize():
......@@ -185,6 +195,48 @@ the underlying storages result of getSize():
>>> blob_size - underlying_size
91L
Savepoints and Blobs
--------------------
We do support optimistic savepoints :
>>> connection5 = database.open()
>>> root5 = connection5.root()
>>> blob = Blob()
>>> blob_fh = blob.open("wb")
>>> blob_fh.write("I'm a happy blob.")
>>> blob_fh.close()
>>> root5['blob'] = blob
>>> transaction.commit()
>>> root5['blob'].open("rb").read()
"I'm a happy blob."
>>> blob_fh = root5['blob'].open("a")
>>> blob_fh.write(" And I'm singing.")
>>> blob_fh.close()
>>> root5['blob'].open("rb").read()
"I'm a happy blob. And I'm singing."
>>> savepoint = transaction.savepoint(optimistic=True)
>>> root5['blob'].open("rb").read()
"I'm a happy blob. And I'm singing."
>>> transaction.get().commit()
We do not support non-optimistic savepoints:
>>> blob_fh = root5['blob'].open("a")
>>> blob_fh.write(" And the weather is beautiful.")
>>> blob_fh.close()
>>> root5['blob'].open("rb").read()
"I'm a happy blob. And I'm singing. And the weather is beautiful."
>>> savepoint = transaction.savepoint() # doctest: +ELLIPSIS
Traceback (most recent call last):
...
TypeError: ('Savepoints unsupported', <MultiObjectResourceAdapter for <ZODB.Blobs.Blob.BlobDataManager instance at ...> at ...>)
Teardown
--------
We don't need the storage directory and databases anymore:
>>> import shutil
......@@ -192,4 +244,3 @@ We don't need the storage directory and databases anymore:
>>> tm1.get().abort()
>>> tm2.get().abort()
>>> database.close()
......@@ -21,6 +21,7 @@ import tempfile
import threading
import warnings
import os
import shutil
from time import time
from persistent import PickleCache
......@@ -1090,6 +1091,11 @@ class Connection(ExportImport, object):
else:
s = self._storage.storeBlob(oid, serial, data, blobfilename,
self._version, transaction)
# we invalidate the object here in order to ensure
# that that the next attribute access of its name
# unghostify it, which will cause its blob data
# to be reattached "cleanly"
self.invalidate(s, {oid:True})
self._handle_serial(s, oid, change=False)
src.close()
......@@ -1139,6 +1145,8 @@ BLOB_DIRTY = "store"
class TmpStore:
"""A storage-like thing to support savepoints."""
implements(IBlobStorage)
def __init__(self, base_version, storage):
self._storage = storage
for method in (
......@@ -1149,7 +1157,8 @@ class TmpStore:
self._base_version = base_version
self._file = tempfile.TemporaryFile()
self._blobdir = tempfile.mkdtemp()
self._blobdir = tempfile.mkdtemp() # XXX this needs to go to the
# storage dependent blob area
# position: current file position
# _tpos: file position at last commit point
self.position = 0L
......@@ -1162,6 +1171,7 @@ class TmpStore:
def close(self):
self._file.close()
shutil.rmtree(self._blobdir)
def load(self, oid, version):
pos = self.index.get(oid)
......@@ -1195,7 +1205,6 @@ class TmpStore:
def storeBlob(self, oid, serial, data, blobfilename, version,
transaction):
# XXX we need to clean up after ourselves!
serial = self.store(oid, serial, data, version, transaction)
assert isinstance(serial, str) # XXX in theory serials could be
# something else
......
......@@ -193,3 +193,4 @@ However, using a savepoint invalidates any savepoints that come after it:
InvalidSavepointRollbackError
>>> transaction.abort()
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