Commit e2308703 authored by Jim Fulton's avatar Jim Fulton

Fixed an undo bug that affects file storages that support blobs in

special cases involving undo of undo of undo of object additions.
parent bce09080
...@@ -984,15 +984,19 @@ class FileStorage( ...@@ -984,15 +984,19 @@ class FileStorage(
else: else:
if self.blob_dir and not p and prev: if self.blob_dir and not p and prev:
up, userial = self._loadBackTxn(h.oid, prev) try:
if ZODB.blob.is_blob_record(up): up, userial = self._loadBackTxn(h.oid, prev)
# We're undoing a blob modification operation. except ZODB.POSException.POSKeyError:
# We have to copy the blob data pass # It was removed, so no need to copy data
tmp = ZODB.utils.mktemp(dir=self.fshelper.temp_dir) else:
ZODB.utils.cp( if ZODB.blob.is_blob_record(up):
self.openCommittedBlobFile(h.oid, userial), # We're undoing a blob modification operation.
open(tmp, 'wb')) # We have to copy the blob data
self._blob_storeblob(h.oid, self._tid, tmp) tmp = ZODB.utils.mktemp(dir=self.fshelper.temp_dir)
ZODB.utils.cp(
self.openCommittedBlobFile(h.oid, userial),
open(tmp, 'wb'))
self._blob_storeblob(h.oid, self._tid, tmp)
new = DataHeader(h.oid, self._tid, ipos, otloc, 0, len(p)) new = DataHeader(h.oid, self._tid, ipos, otloc, 0, len(p))
......
...@@ -27,18 +27,8 @@ from ZODB.tests import RevisionStorage, PersistentStorage, MTStorage ...@@ -27,18 +27,8 @@ from ZODB.tests import RevisionStorage, PersistentStorage, MTStorage
from ZODB.tests import ReadOnlyStorage, RecoveryStorage from ZODB.tests import ReadOnlyStorage, RecoveryStorage
from ZODB.tests.StorageTestBase import MinPO, zodb_pickle from ZODB.tests.StorageTestBase import MinPO, zodb_pickle
class BaseFileStorageTests(StorageTestBase.StorageTestBase):
def open(self, **kwargs):
self._storage = ZODB.FileStorage.FileStorage('FileStorageTests.fs',
**kwargs)
def setUp(self):
StorageTestBase.StorageTestBase.setUp(self)
self.open(create=1)
class FileStorageTests( class FileStorageTests(
BaseFileStorageTests, StorageTestBase.StorageTestBase,
BasicStorage.BasicStorage, BasicStorage.BasicStorage,
TransactionalUndoStorage.TransactionalUndoStorage, TransactionalUndoStorage.TransactionalUndoStorage,
RevisionStorage.RevisionStorage, RevisionStorage.RevisionStorage,
...@@ -55,6 +45,14 @@ class FileStorageTests( ...@@ -55,6 +45,14 @@ class FileStorageTests(
ReadOnlyStorage.ReadOnlyStorage ReadOnlyStorage.ReadOnlyStorage
): ):
def open(self, **kwargs):
self._storage = ZODB.FileStorage.FileStorage('FileStorageTests.fs',
**kwargs)
def setUp(self):
StorageTestBase.StorageTestBase.setUp(self)
self.open(create=1)
def checkLongMetadata(self): def checkLongMetadata(self):
s = "X" * 75000 s = "X" * 75000
try: try:
...@@ -287,6 +285,13 @@ class FileStorageTests( ...@@ -287,6 +285,13 @@ class FileStorageTests(
else: else:
self.assertNotEqual(next_oid, None) self.assertNotEqual(next_oid, None)
class FileStorageTestsWithBlobsEnabled(FileStorageTests):
def open(self, **kwargs):
if 'blob_dir' not in kwargs:
kwargs = kwargs.copy()
kwargs['blob_dir'] = 'blobs'
return FileStorageTests.open(self, **kwargs)
class FileStorageRecoveryTest( class FileStorageRecoveryTest(
StorageTestBase.StorageTestBase, StorageTestBase.StorageTestBase,
...@@ -301,7 +306,6 @@ class FileStorageRecoveryTest( ...@@ -301,7 +306,6 @@ class FileStorageRecoveryTest(
def tearDown(self): def tearDown(self):
self._dst.close() self._dst.close()
StorageTestBase.StorageTestBase.tearDown(self) StorageTestBase.StorageTestBase.tearDown(self)
def new_dest(self): def new_dest(self):
return ZODB.FileStorage.FileStorage('Dest.fs') return ZODB.FileStorage.FileStorage('Dest.fs')
...@@ -332,23 +336,6 @@ class FileStorageNoRestoreRecoveryTest(FileStorageRecoveryTest): ...@@ -332,23 +336,6 @@ class FileStorageNoRestoreRecoveryTest(FileStorageRecoveryTest):
pass pass
class SlowFileStorageTest(BaseFileStorageTests):
def check10Kstores(self):
# The _get_cached_serial() method has a special case
# every 8000 calls. Make sure it gets minimal coverage.
oids = [[self._storage.new_oid(), None] for i in range(100)]
for i in range(100):
t = transaction.Transaction()
self._storage.tpc_begin(t)
for j in range(100):
o = MinPO(j)
oid, revid = oids[j]
serial = self._storage.store(oid, revid, zodb_pickle(o), "", t)
oids[j][1] = serial
self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
# Raise an exception if the tids in FileStorage fs aren't # Raise an exception if the tids in FileStorage fs aren't
# strictly increasing. # strictly increasing.
def checkIncreasingTids(fs): def checkIncreasingTids(fs):
...@@ -494,7 +481,7 @@ Of course, calling lastInvalidations on an empty storage refturns no data: ...@@ -494,7 +481,7 @@ Of course, calling lastInvalidations on an empty storage refturns no data:
def deal_with_finish_failures(): def deal_with_finish_failures():
r""" r"""
It's really bad to get errors in FileStorage's _finish method, as It's really bad to get errors in FileStorage's _finish method, as
that can cause the file storage to be in an inconsistent that can cause the file storage to be in an inconsistent
state. The data file will be fine, but the internal data state. The data file will be fine, but the internal data
...@@ -523,7 +510,7 @@ def deal_with_finish_failures(): ...@@ -523,7 +510,7 @@ def deal_with_finish_failures():
... ...
TypeError: <lambda>() takes no arguments (1 given) TypeError: <lambda>() takes no arguments (1 given)
>>> print handler >>> print handler
ZODB.FileStorage CRITICAL ZODB.FileStorage CRITICAL
Failure in _finish. Closing. Failure in _finish. Closing.
...@@ -559,7 +546,7 @@ def pack_with_open_blob_files(): ...@@ -559,7 +546,7 @@ def pack_with_open_blob_files():
>>> conn1.add(conn1.root()[1]) >>> conn1.add(conn1.root()[1])
>>> conn1.root()[1].open('w').write('some data') >>> conn1.root()[1].open('w').write('some data')
>>> tm1.commit() >>> tm1.commit()
>>> tm2 = transaction.TransactionManager() >>> tm2 = transaction.TransactionManager()
>>> conn2 = db.open(tm2) >>> conn2 = db.open(tm2)
>>> f = conn1.root()[1].open() >>> f = conn1.root()[1].open()
...@@ -586,7 +573,8 @@ def test_suite(): ...@@ -586,7 +573,8 @@ def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
for klass in [FileStorageTests, Corruption.FileStorageCorruptTests, for klass in [FileStorageTests, Corruption.FileStorageCorruptTests,
FileStorageRecoveryTest, FileStorageNoRestoreRecoveryTest, FileStorageRecoveryTest, FileStorageNoRestoreRecoveryTest,
SlowFileStorageTest]: FileStorageTestsWithBlobsEnabled,
]:
suite.addTest(unittest.makeSuite(klass, "check")) suite.addTest(unittest.makeSuite(klass, "check"))
suite.addTest(doctest.DocTestSuite( suite.addTest(doctest.DocTestSuite(
setUp=zope.testing.setupstack.setUpDirectory, setUp=zope.testing.setupstack.setUpDirectory,
......
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