Commit 80879e0b authored by Jeremy Hylton's avatar Jeremy Hylton

Don't use self._transaction.

It's not thread-safe to store a Transaction() object in an instance
variable without some sort of locking.  Nor is it desirable to use the
same transaction object for more than one transaction.

So get rid of all uses of self._transaction and replace with a local
variable.
parent 01224caa
...@@ -19,14 +19,15 @@ ZERO = '\0'*8 ...@@ -19,14 +19,15 @@ ZERO = '\0'*8
class BasicStorage: class BasicStorage:
def checkBasics(self): def checkBasics(self):
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
# This should simply return # This should simply return
self._storage.tpc_begin(self._transaction) self._storage.tpc_begin(t)
# Aborting is easy # Aborting is easy
self._storage.tpc_abort(self._transaction) self._storage.tpc_abort(t)
# Test a few expected exceptions when we're doing operations giving a # Test a few expected exceptions when we're doing operations giving a
# different Transaction object than the one we've begun on. # different Transaction object than the one we've begun on.
self._storage.tpc_begin(self._transaction) self._storage.tpc_begin(t)
self.assertRaises( self.assertRaises(
POSException.StorageTransactionError, POSException.StorageTransactionError,
self._storage.store, self._storage.store,
...@@ -65,7 +66,7 @@ class BasicStorage: ...@@ -65,7 +66,7 @@ class BasicStorage:
POSException.StorageTransactionError, POSException.StorageTransactionError,
self._storage.store, self._storage.store,
0, 1, 2, 3, Transaction()) 0, 1, 2, 3, Transaction())
self._storage.tpc_abort(self._transaction) self._storage.tpc_abort(t)
def checkSerialIsNoneForInitialRevision(self): def checkSerialIsNoneForInitialRevision(self):
eq = self.assertEqual eq = self.assertEqual
...@@ -125,7 +126,6 @@ class BasicStorage: ...@@ -125,7 +126,6 @@ class BasicStorage:
# Now abort this transaction # Now abort this transaction
self._storage.tpc_abort(self._transaction) self._storage.tpc_abort(self._transaction)
# Now start all over again # Now start all over again
self._transaction = Transaction()
oid = self._storage.new_oid() oid = self._storage.new_oid()
self._dostore(oid=oid, data=MinPO(6)) self._dostore(oid=oid, data=MinPO(6))
...@@ -133,14 +133,13 @@ class BasicStorage: ...@@ -133,14 +133,13 @@ class BasicStorage:
oid1 = self._storage.new_oid() oid1 = self._storage.new_oid()
revid1 = self._dostore(oid=oid1, data=MinPO(-2)) revid1 = self._dostore(oid=oid1, data=MinPO(-2))
oid = self._storage.new_oid() oid = self._storage.new_oid()
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), self._storage.tpc_begin(t)
'', self._transaction) self._storage.store(oid, ZERO, zodb_pickle(MinPO(5)), '', t)
# Now abort this transaction # Now abort this transaction
self._storage.tpc_vote(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_abort(self._transaction) self._storage.tpc_abort(t)
# Now start all over again # Now start all over again
self._transaction = Transaction()
oid = self._storage.new_oid() oid = self._storage.new_oid()
revid = self._dostore(oid=oid, data=MinPO(6)) revid = self._dostore(oid=oid, data=MinPO(6))
......
...@@ -144,9 +144,10 @@ class ConflictResolvingTransUndoStorage: ...@@ -144,9 +144,10 @@ class ConflictResolvingTransUndoStorage:
# Start the undo # Start the undo
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[1]['id'] tid = info[1]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_finish(self._transaction) self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(t)
def checkUndoUnresolvable(self): def checkUndoUnresolvable(self):
# This test is based on checkNotUndoable in the # This test is based on checkNotUndoable in the
...@@ -164,9 +165,9 @@ class ConflictResolvingTransUndoStorage: ...@@ -164,9 +165,9 @@ class ConflictResolvingTransUndoStorage:
# Start the undo # Start the undo
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[1]['id'] tid = info[1]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
self.assertRaises(UndoError, self._storage.tpc_begin(t)
self._storage.transactionalUndo, self.assertRaises(UndoError, self._storage.transactionalUndo,
tid, self._transaction) tid, t)
self._storage.tpc_abort(self._transaction) self._storage.tpc_abort(t)
...@@ -4,6 +4,7 @@ Any storage that supports the history() method should be able to pass ...@@ -4,6 +4,7 @@ Any storage that supports the history() method should be able to pass
all these tests. all these tests.
""" """
from ZODB.Transaction import Transaction
from ZODB.tests.MinPO import MinPO from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_unpickle from ZODB.tests.StorageTestBase import zodb_unpickle
...@@ -111,10 +112,11 @@ class HistoryStorage: ...@@ -111,10 +112,11 @@ class HistoryStorage:
revid6 = self._dostore(oid, revid=revid5, data=MinPO(16), revid6 = self._dostore(oid, revid=revid5, data=MinPO(16),
version=version) version=version)
# Now commit the version # Now commit the version
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.commitVersion(version, '', self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.commitVersion(version, '', t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
# After consultation with Jim, we agreed that the semantics of # After consultation with Jim, we agreed that the semantics of
# revision id's after a version commit is that the committed object # revision id's after a version commit is that the committed object
# gets a new serial number (a.k.a. revision id). Note that # gets a new serial number (a.k.a. revision id). Note that
...@@ -168,10 +170,11 @@ class HistoryStorage: ...@@ -168,10 +170,11 @@ class HistoryStorage:
revid6 = self._dostore(oid, revid=revid5, data=MinPO(16), revid6 = self._dostore(oid, revid=revid5, data=MinPO(16),
version=version) version=version)
# Now commit the version # Now commit the version
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.abortVersion(version, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.abortVersion(version, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
# After consultation with Jim, we agreed that the semantics of # After consultation with Jim, we agreed that the semantics of
# revision id's after a version commit is that the committed object # revision id's after a version commit is that the committed object
# gets a new serial number (a.k.a. revision id). Note that # gets a new serial number (a.k.a. revision id). Note that
......
...@@ -147,14 +147,15 @@ class StorageTestBase(unittest.TestCase): ...@@ -147,14 +147,15 @@ class StorageTestBase(unittest.TestCase):
if version is None: if version is None:
version = '' version = ''
# Begin the transaction # Begin the transaction
self._transaction = Transaction() t = Transaction()
self._storage.tpc_begin(self._transaction) self._storage.tpc_begin(t)
self._transaction = t
# Store an object # Store an object
r1 = self._storage.store(oid, revid, data, version, r1 = self._storage.store(oid, revid, data, version, t)
self._transaction)
# Finish the transaction # Finish the transaction
r2 = self._storage.tpc_vote(self._transaction) r2 = self._storage.tpc_vote(t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_finish(t)
self._transaction = None
return handle_serials(oid, r1, r2) return handle_serials(oid, r1, r2)
def _dostoreNP(self, oid=None, revid=None, data=None, version=None): def _dostoreNP(self, oid=None, revid=None, data=None, version=None):
......
...@@ -67,13 +67,13 @@ class SynchronizedStorage: ...@@ -67,13 +67,13 @@ class SynchronizedStorage:
apply(self.assertRaises, args) apply(self.assertRaises, args)
def verifyWrongTrans(self, callable, *args): def verifyWrongTrans(self, callable, *args):
self._storage.tpc_begin(self._transaction) self._storage.tpc_begin(Transaction())
args = (StorageTransactionError, callable) + args args = (StorageTransactionError, callable) + args
apply(self.assertRaises, args) apply(self.assertRaises, args)
def checkAbortVersionNotCommitting(self): def checkAbortVersionNotCommitting(self):
self.verifyNotCommitting(self._storage.abortVersion, self.verifyNotCommitting(self._storage.abortVersion,
VERSION, self._transaction) VERSION, Transaction())
def checkAbortVersionWrongTrans(self): def checkAbortVersionWrongTrans(self):
self.verifyWrongTrans(self._storage.abortVersion, self.verifyWrongTrans(self._storage.abortVersion,
...@@ -81,7 +81,7 @@ class SynchronizedStorage: ...@@ -81,7 +81,7 @@ class SynchronizedStorage:
def checkCommitVersionNotCommitting(self): def checkCommitVersionNotCommitting(self):
self.verifyNotCommitting(self._storage.commitVersion, self.verifyNotCommitting(self._storage.commitVersion,
VERSION, "", self._transaction) VERSION, "", Transaction())
def checkCommitVersionWrongTrans(self): def checkCommitVersionWrongTrans(self):
self.verifyWrongTrans(self._storage.commitVersion, self.verifyWrongTrans(self._storage.commitVersion,
...@@ -90,7 +90,7 @@ class SynchronizedStorage: ...@@ -90,7 +90,7 @@ class SynchronizedStorage:
def checkStoreNotCommitting(self): def checkStoreNotCommitting(self):
self.verifyNotCommitting(self._storage.store, self.verifyNotCommitting(self._storage.store,
OID, SERIALNO, "", "", self._transaction) OID, SERIALNO, "", "", Transaction())
def checkStoreWrongTrans(self): def checkStoreWrongTrans(self):
self.verifyWrongTrans(self._storage.store, self.verifyWrongTrans(self._storage.store,
...@@ -107,18 +107,19 @@ class SynchronizedStorage: ...@@ -107,18 +107,19 @@ class SynchronizedStorage:
self._storage.tpc_abort(Transaction()) self._storage.tpc_abort(Transaction())
def checkAbortWrongTrans(self): def checkAbortWrongTrans(self):
self._storage.tpc_begin(self._transaction) self._storage.tpc_begin(Transaction())
self._storage.tpc_abort(Transaction()) self._storage.tpc_abort(Transaction())
def checkFinishNotCommitting(self): def checkFinishNotCommitting(self):
self._storage.tpc_finish(Transaction()) self._storage.tpc_finish(Transaction())
def checkFinishWrongTrans(self): def checkFinishWrongTrans(self):
self._storage.tpc_begin(self._transaction) self._storage.tpc_begin(Transaction())
self._storage.tpc_finish(Transaction()) self._storage.tpc_finish(Transaction())
def checkBeginCommitting(self): def checkBeginCommitting(self):
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_begin(t)
# XXX how to check undo? # XXX how to check undo?
...@@ -5,6 +5,7 @@ Any storage that supports transactionalUndo() must pass these tests. ...@@ -5,6 +5,7 @@ Any storage that supports transactionalUndo() must pass these tests.
import types import types
from ZODB import POSException from ZODB import POSException
from ZODB.Transaction import Transaction
from ZODB.tests.MinPO import MinPO from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle
...@@ -37,13 +38,14 @@ class TransactionalUndoStorage: ...@@ -37,13 +38,14 @@ class TransactionalUndoStorage:
def _multi_obj_transaction(self, objs): def _multi_obj_transaction(self, objs):
newrevs = {} newrevs = {}
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
self._transaction_begin() self._transaction_begin()
for oid, rev, data in objs: for oid, rev, data in objs:
self._transaction_store(oid, rev, data, '', self._transaction) self._transaction_store(oid, rev, data, '', t)
newrevs[oid] = None newrevs[oid] = None
self._transaction_vote(self._transaction) self._transaction_vote(t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_finish(t)
for oid in newrevs.keys(): for oid in newrevs.keys():
newrevs[oid] = self._transaction_newserial(oid) newrevs[oid] = self._transaction_newserial(oid)
return newrevs return newrevs
...@@ -58,11 +60,12 @@ class TransactionalUndoStorage: ...@@ -58,11 +60,12 @@ class TransactionalUndoStorage:
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
# Now start an undo transaction # Now start an undo transaction
self._transaction.note('undo1') t = Transaction()
self._storage.tpc_begin(self._transaction) t.note('undo1')
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid) eq(oids[0], oid)
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
...@@ -70,11 +73,12 @@ class TransactionalUndoStorage: ...@@ -70,11 +73,12 @@ class TransactionalUndoStorage:
# Do another one # Do another one
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[2]['id'] tid = info[2]['id']
self._transaction.note('undo2') t = Transaction()
self._storage.tpc_begin(self._transaction) t.note('undo2')
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid) eq(oids[0], oid)
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
...@@ -82,11 +86,12 @@ class TransactionalUndoStorage: ...@@ -82,11 +86,12 @@ class TransactionalUndoStorage:
# Try to undo the first record # Try to undo the first record
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[4]['id'] tid = info[4]['id']
self._transaction.note('undo3') t = Transaction()
self._storage.tpc_begin(self._transaction) t.note('undo3')
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid) eq(oids[0], oid)
...@@ -96,10 +101,11 @@ class TransactionalUndoStorage: ...@@ -96,10 +101,11 @@ class TransactionalUndoStorage:
# And now let's try to redo the object's creation # And now let's try to redo the object's creation
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid) eq(oids[0], oid)
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
...@@ -113,10 +119,11 @@ class TransactionalUndoStorage: ...@@ -113,10 +119,11 @@ class TransactionalUndoStorage:
# Undo the last transaction # Undo the last transaction
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid) eq(oids[0], oid)
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
...@@ -125,10 +132,11 @@ class TransactionalUndoStorage: ...@@ -125,10 +132,11 @@ class TransactionalUndoStorage:
# creation. Let's undo the object creation. # creation. Let's undo the object creation.
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[2]['id'] tid = info[2]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid) eq(oids[0], oid)
self.assertRaises(KeyError, self._storage.load, oid, '') self.assertRaises(KeyError, self._storage.load, oid, '')
...@@ -141,10 +149,11 @@ class TransactionalUndoStorage: ...@@ -141,10 +149,11 @@ class TransactionalUndoStorage:
# Undo the last transaction # Undo the last transaction
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid) eq(oids[0], oid)
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
...@@ -153,10 +162,11 @@ class TransactionalUndoStorage: ...@@ -153,10 +162,11 @@ class TransactionalUndoStorage:
# creation. Let's redo the last undo # creation. Let's redo the last undo
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid) eq(oids[0], oid)
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
...@@ -171,26 +181,28 @@ class TransactionalUndoStorage: ...@@ -171,26 +181,28 @@ class TransactionalUndoStorage:
oid2 = self._storage.new_oid() oid2 = self._storage.new_oid()
revid1 = revid2 = ZERO revid1 = revid2 = ZERO
# Store two objects in the same transaction # Store two objects in the same transaction
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
self._transaction_begin() self._transaction_begin()
self._transaction_store(oid1, revid1, p31, '', self._transaction) self._transaction_store(oid1, revid1, p31, '', t)
self._transaction_store(oid2, revid2, p51, '', self._transaction) self._transaction_store(oid2, revid2, p51, '', t)
# Finish the transaction # Finish the transaction
self._transaction_vote(self._transaction) self._transaction_vote(t)
revid1 = self._transaction_newserial(oid1) revid1 = self._transaction_newserial(oid1)
revid2 = self._transaction_newserial(oid2) revid2 = self._transaction_newserial(oid2)
self._storage.tpc_finish(self._transaction) self._storage.tpc_finish(t)
eq(revid1, revid2) eq(revid1, revid2)
# Update those same two objects # Update those same two objects
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
self._transaction_begin() self._transaction_begin()
self._transaction_store(oid1, revid1, p32, '', self._transaction) self._transaction_store(oid1, revid1, p32, '', t)
self._transaction_store(oid2, revid2, p52, '', self._transaction) self._transaction_store(oid2, revid2, p52, '', t)
# Finish the transaction # Finish the transaction
self._transaction_vote(self._transaction) self._transaction_vote(t)
revid1 = self._transaction_newserial(oid1) revid1 = self._transaction_newserial(oid1)
revid2 = self._transaction_newserial(oid2) revid2 = self._transaction_newserial(oid2)
self._storage.tpc_finish(self._transaction) self._storage.tpc_finish(t)
eq(revid1, revid2) eq(revid1, revid2)
# Make sure the objects have the current value # Make sure the objects have the current value
data, revid1 = self._storage.load(oid1, '') data, revid1 = self._storage.load(oid1, '')
...@@ -200,10 +212,11 @@ class TransactionalUndoStorage: ...@@ -200,10 +212,11 @@ class TransactionalUndoStorage:
# Now attempt to undo the transaction containing two objects # Now attempt to undo the transaction containing two objects
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 2) eq(len(oids), 2)
self.failUnless(oid1 in oids) self.failUnless(oid1 in oids)
self.failUnless(oid2 in oids) self.failUnless(oid2 in oids)
...@@ -249,14 +262,15 @@ class TransactionalUndoStorage: ...@@ -249,14 +262,15 @@ class TransactionalUndoStorage:
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
tid1 = info[1]['id'] tid1 = info[1]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
oids1 = self._storage.transactionalUndo(tid1, self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_vote(self._transaction) oids1 = self._storage.transactionalUndo(tid1, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
# We get the finalization stuff called an extra time: # We get the finalization stuff called an extra time:
## self._storage.tpc_vote(self._transaction) ## self._storage.tpc_vote(t)
## self._storage.tpc_finish(self._transaction) ## self._storage.tpc_finish(t)
eq(len(oids), 2) eq(len(oids), 2)
eq(len(oids1), 2) eq(len(oids1), 2)
unless(oid1 in oids) unless(oid1 in oids)
...@@ -268,10 +282,11 @@ class TransactionalUndoStorage: ...@@ -268,10 +282,11 @@ class TransactionalUndoStorage:
# Now try to undo the one we just did to undo, whew # Now try to undo the one we just did to undo, whew
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 2) eq(len(oids), 2)
unless(oid1 in oids) unless(oid1 in oids)
unless(oid2 in oids) unless(oid2 in oids)
...@@ -292,23 +307,25 @@ class TransactionalUndoStorage: ...@@ -292,23 +307,25 @@ class TransactionalUndoStorage:
revid1 = self._dostore(oid1, data=p31, already_pickled=1) revid1 = self._dostore(oid1, data=p31, already_pickled=1)
revid2 = self._dostore(oid2, data=p51, already_pickled=1) revid2 = self._dostore(oid2, data=p51, already_pickled=1)
# Update those same two objects # Update those same two objects
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
self._transaction_begin() self._transaction_begin()
self._transaction_store(oid1, revid1, p32, '', self._transaction) self._transaction_store(oid1, revid1, p32, '', t)
self._transaction_store(oid2, revid2, p52, '', self._transaction) self._transaction_store(oid2, revid2, p52, '', t)
# Finish the transaction # Finish the transaction
self._transaction_vote(self._transaction) self._transaction_vote(t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_finish(t)
revid1 = self._transaction_newserial(oid1) revid1 = self._transaction_newserial(oid1)
revid2 = self._transaction_newserial(oid2) revid2 = self._transaction_newserial(oid2)
eq(revid1, revid2) eq(revid1, revid2)
# Now attempt to undo the transaction containing two objects # Now attempt to undo the transaction containing two objects
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[0]['id'] tid = info[0]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 2) eq(len(oids), 2)
self.failUnless(oid1 in oids) self.failUnless(oid1 in oids)
self.failUnless(oid2 in oids) self.failUnless(oid2 in oids)
...@@ -318,13 +335,14 @@ class TransactionalUndoStorage: ...@@ -318,13 +335,14 @@ class TransactionalUndoStorage:
eq(zodb_unpickle(data), MinPO(51)) eq(zodb_unpickle(data), MinPO(51))
# Like the above, but this time, the second transaction contains only # Like the above, but this time, the second transaction contains only
# one object. # one object.
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
self._transaction_begin() self._transaction_begin()
self._transaction_store(oid1, revid1, p33, '', self._transaction) self._transaction_store(oid1, revid1, p33, '', t)
self._transaction_store(oid2, revid2, p53, '', self._transaction) self._transaction_store(oid2, revid2, p53, '', t)
# Finish the transaction # Finish the transaction
self._transaction_vote(self._transaction) self._transaction_vote(t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_finish(t)
revid1 = self._transaction_newserial(oid1) revid1 = self._transaction_newserial(oid1)
revid2 = self._transaction_newserial(oid2) revid2 = self._transaction_newserial(oid2)
eq(revid1, revid2) eq(revid1, revid2)
...@@ -334,10 +352,11 @@ class TransactionalUndoStorage: ...@@ -334,10 +352,11 @@ class TransactionalUndoStorage:
# Now attempt to undo the transaction containing two objects # Now attempt to undo the transaction containing two objects
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[1]['id'] tid = info[1]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
self.failUnless(oid1 in oids) self.failUnless(oid1 in oids)
self.failUnless(not oid2 in oids) self.failUnless(not oid2 in oids)
...@@ -357,11 +376,12 @@ class TransactionalUndoStorage: ...@@ -357,11 +376,12 @@ class TransactionalUndoStorage:
# Start the undo # Start the undo
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[1]['id'] tid = info[1]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
self.assertRaises(POSException.UndoError, self.assertRaises(POSException.UndoError,
self._storage.transactionalUndo, self._storage.transactionalUndo,
tid, self._transaction) tid, t)
self._storage.tpc_abort(self._transaction) self._storage.tpc_abort(t)
# Now have more fun: object1 and object2 are in the same transaction, # Now have more fun: object1 and object2 are in the same transaction,
# which we'll try to undo to, but one of them has since modified in # which we'll try to undo to, but one of them has since modified in
# different transaction, so the undo should fail. # different transaction, so the undo should fail.
...@@ -372,12 +392,13 @@ class TransactionalUndoStorage: ...@@ -372,12 +392,13 @@ class TransactionalUndoStorage:
p81, p82, p91, p92 = map(zodb_pickle, p81, p82, p91, p92 = map(zodb_pickle,
map(MinPO, (81, 82, 91, 92))) map(MinPO, (81, 82, 91, 92)))
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
self._transaction_begin() self._transaction_begin()
self._transaction_store(oid1, revid1, p81, '', self._transaction) self._transaction_store(oid1, revid1, p81, '', t)
self._transaction_store(oid2, revid2, p91, '', self._transaction) self._transaction_store(oid2, revid2, p91, '', t)
self._transaction_vote(self._transaction) self._transaction_vote(t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_finish(t)
revid1 = self._transaction_newserial(oid1) revid1 = self._transaction_newserial(oid1)
revid2 = self._transaction_newserial(oid2) revid2 = self._transaction_newserial(oid2)
eq(revid1, revid2) eq(revid1, revid2)
...@@ -394,8 +415,9 @@ class TransactionalUndoStorage: ...@@ -394,8 +415,9 @@ class TransactionalUndoStorage:
self.assertNotEqual(revid2, revid_22) self.assertNotEqual(revid2, revid_22)
info = self._storage.undoInfo() info = self._storage.undoInfo()
tid = info[1]['id'] tid = info[1]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
self.assertRaises(POSException.UndoError, self.assertRaises(POSException.UndoError,
self._storage.transactionalUndo, self._storage.transactionalUndo,
tid, self._transaction) tid, t)
self._storage.tpc_abort(self._transaction) self._storage.tpc_abort(t)
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# that supports both transactionalUndo() and versions must pass these tests. # that supports both transactionalUndo() and versions must pass these tests.
from ZODB import POSException from ZODB import POSException
from ZODB.Transaction import Transaction
from ZODB.tests.MinPO import MinPO from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_unpickle from ZODB.tests.StorageTestBase import zodb_unpickle
...@@ -11,14 +12,17 @@ class TransactionalUndoVersionStorage: ...@@ -11,14 +12,17 @@ class TransactionalUndoVersionStorage:
oid = self._storage.new_oid() oid = self._storage.new_oid()
version = 'one' version = 'one'
revid_a = self._dostore(oid, data=MinPO(91)) revid_a = self._dostore(oid, data=MinPO(91))
revid_b = self._dostore(oid, revid=revid_a, data=MinPO(92), version=version) revid_b = self._dostore(oid, revid=revid_a, data=MinPO(92),
revid_c = self._dostore(oid, revid=revid_b, data=MinPO(93), version=version) version=version)
revid_c = self._dostore(oid, revid=revid_b, data=MinPO(93),
version=version)
info=self._storage.undoInfo() info=self._storage.undoInfo()
tid=info[0]['id'] tid=info[0]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
assert len(oids) == 1 assert len(oids) == 1
assert oids[0] == oid assert oids[0] == oid
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
...@@ -28,10 +32,11 @@ class TransactionalUndoVersionStorage: ...@@ -28,10 +32,11 @@ class TransactionalUndoVersionStorage:
assert revid > revid_b and revid > revid_c assert revid > revid_b and revid > revid_c
assert zodb_unpickle(data) == MinPO(92) assert zodb_unpickle(data) == MinPO(92)
# Now commit the version... # Now commit the version...
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.commitVersion(version, '', self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.commitVersion(version, '', t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
assert len(oids) == 1 assert len(oids) == 1
assert oids[0] == oid assert oids[0] == oid
...@@ -46,10 +51,11 @@ class TransactionalUndoVersionStorage: ...@@ -46,10 +51,11 @@ class TransactionalUndoVersionStorage:
# ...and undo the commit # ...and undo the commit
info=self._storage.undoInfo() info=self._storage.undoInfo()
tid=info[0]['id'] tid=info[0]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
assert len(oids) == 1 assert len(oids) == 1
assert oids[0] == oid assert oids[0] == oid
data, revid = self._storage.load(oid, version) data, revid = self._storage.load(oid, version)
...@@ -57,10 +63,11 @@ class TransactionalUndoVersionStorage: ...@@ -57,10 +63,11 @@ class TransactionalUndoVersionStorage:
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
assert zodb_unpickle(data) == MinPO(91) assert zodb_unpickle(data) == MinPO(91)
# Now abort the version # Now abort the version
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.abortVersion(version, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.abortVersion(version, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
assert len(oids) == 1 assert len(oids) == 1
assert oids[0] == oid assert oids[0] == oid
# The object should not exist in the version now, but it should exist # The object should not exist in the version now, but it should exist
...@@ -76,10 +83,11 @@ class TransactionalUndoVersionStorage: ...@@ -76,10 +83,11 @@ class TransactionalUndoVersionStorage:
# Now undo the abort # Now undo the abort
info=self._storage.undoInfo() info=self._storage.undoInfo()
tid=info[0]['id'] tid=info[0]['id']
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.transactionalUndo(tid, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.transactionalUndo(tid, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
assert len(oids) == 1 assert len(oids) == 1
assert oids[0] == oid assert oids[0] == oid
# And the object should be back in versions 'one' and '' # And the object should be back in versions 'one' and ''
......
...@@ -8,6 +8,7 @@ Any storage that supports versions should be able to pass all these tests. ...@@ -8,6 +8,7 @@ Any storage that supports versions should be able to pass all these tests.
# code. Barry and Jeremy didn't understand versions then. # code. Barry and Jeremy didn't understand versions then.
from ZODB import POSException from ZODB import POSException
from ZODB.Transaction import Transaction
from ZODB.tests.MinPO import MinPO from ZODB.tests.MinPO import MinPO
from ZODB.tests.StorageTestBase import zodb_unpickle from ZODB.tests.StorageTestBase import zodb_unpickle
...@@ -144,10 +145,11 @@ class VersionStorage: ...@@ -144,10 +145,11 @@ class VersionStorage:
## s1 = self._storage.getSerial(oid) ## s1 = self._storage.getSerial(oid)
# Now abort the version -- must be done in a transaction # Now abort the version -- must be done in a transaction
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.abortVersion(version, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.abortVersion(version, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
## s2 = self._storage.getSerial(oid) ## s2 = self._storage.getSerial(oid)
## eq(s1, s2) # or self.assert(s2 > s1) ? ## eq(s1, s2) # or self.assert(s2 > s1) ?
eq(len(oids), 1) eq(len(oids), 1)
...@@ -159,14 +161,15 @@ class VersionStorage: ...@@ -159,14 +161,15 @@ class VersionStorage:
eq = self.assertEqual eq = self.assertEqual
oid, version = self._setup_version() oid, version = self._setup_version()
# Now abort a bogus version # Now abort a bogus version
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
#JF# The spec is silent on what happens if you abort or commit #JF# The spec is silent on what happens if you abort or commit
#JF# a non-existent version. FileStorage consideres this a noop. #JF# a non-existent version. FileStorage consideres this a noop.
#JF# We can change the spec, but until we do .... #JF# We can change the spec, but until we do ....
#JF# self.assertRaises(POSException.VersionError, #JF# self.assertRaises(POSException.VersionError,
#JF# self._storage.abortVersion, #JF# self._storage.abortVersion,
#JF# 'bogus', self._transaction) #JF# 'bogus', t)
# And try to abort the empty version # And try to abort the empty version
if (hasattr(self._storage, 'supportsTransactionalUndo') if (hasattr(self._storage, 'supportsTransactionalUndo')
...@@ -174,12 +177,12 @@ class VersionStorage: ...@@ -174,12 +177,12 @@ class VersionStorage:
# XXX FileStorage used to be broken on this one # XXX FileStorage used to be broken on this one
self.assertRaises(POSException.VersionError, self.assertRaises(POSException.VersionError,
self._storage.abortVersion, self._storage.abortVersion,
'', self._transaction) '', t)
# But now we really try to abort the version # But now we really try to abort the version
oids = self._storage.abortVersion(version, self._transaction) oids = self._storage.abortVersion(version, t)
self._storage.tpc_vote(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid) eq(oids[0], oid)
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
...@@ -194,19 +197,21 @@ class VersionStorage: ...@@ -194,19 +197,21 @@ class VersionStorage:
oid1, version1 = self._setup_version('one') oid1, version1 = self._setup_version('one')
data, revid1 = self._storage.load(oid1, version1) data, revid1 = self._storage.load(oid1, version1)
eq(zodb_unpickle(data), MinPO(54)) eq(zodb_unpickle(data), MinPO(54))
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
self.assertRaises(POSException.VersionCommitError, self.assertRaises(POSException.VersionCommitError,
self._storage.commitVersion, self._storage.commitVersion,
'one', 'one', self._transaction) 'one', 'one', t)
def checkModifyAfterAbortVersion(self): def checkModifyAfterAbortVersion(self):
eq = self.assertEqual eq = self.assertEqual
oid, version = self._setup_version() oid, version = self._setup_version()
# Now abort the version # Now abort the version
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.abortVersion(version, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.abortVersion(version, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
# Load the object's current state (which gets us the revid) # Load the object's current state (which gets us the revid)
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
# And modify it a few times # And modify it a few times
...@@ -225,10 +230,11 @@ class VersionStorage: ...@@ -225,10 +230,11 @@ class VersionStorage:
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
eq(zodb_unpickle(data), MinPO(51)) eq(zodb_unpickle(data), MinPO(51))
# Try committing this version to the empty version # Try committing this version to the empty version
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.commitVersion(version, '', self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.commitVersion(version, '', t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
eq(zodb_unpickle(data), MinPO(54)) eq(zodb_unpickle(data), MinPO(54))
...@@ -251,11 +257,12 @@ class VersionStorage: ...@@ -251,11 +257,12 @@ class VersionStorage:
eq(zodb_unpickle(data), MinPO(51)) eq(zodb_unpickle(data), MinPO(51))
# Okay, now let's commit object1 to version2 # Okay, now let's commit object1 to version2
self._storage.tpc_begin(self._transaction) t = Transaction()
self._storage.tpc_begin(t)
oids = self._storage.commitVersion(version1, version2, oids = self._storage.commitVersion(version1, version2,
self._transaction) t)
self._storage.tpc_vote(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid1) eq(oids[0], oid1)
data, revid = self._storage.load(oid1, version2) data, revid = self._storage.load(oid1, version2)
...@@ -286,10 +293,11 @@ class VersionStorage: ...@@ -286,10 +293,11 @@ class VersionStorage:
eq(zodb_unpickle(data), MinPO(51)) eq(zodb_unpickle(data), MinPO(51))
# First, let's abort version1 # First, let's abort version1
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.abortVersion(version1, self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.abortVersion(version1, t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid1) eq(oids[0], oid1)
data, revid = self._storage.load(oid1, '') data, revid = self._storage.load(oid1, '')
...@@ -310,10 +318,11 @@ class VersionStorage: ...@@ -310,10 +318,11 @@ class VersionStorage:
data, revid = self._storage.load(oid2, version2) data, revid = self._storage.load(oid2, version2)
eq(zodb_unpickle(data), MinPO(54)) eq(zodb_unpickle(data), MinPO(54))
# Okay, now let's commit version2 back to the trunk # Okay, now let's commit version2 back to the trunk
self._storage.tpc_begin(self._transaction) t = Transaction()
oids = self._storage.commitVersion(version2, '', self._transaction) self._storage.tpc_begin(t)
self._storage.tpc_vote(self._transaction) oids = self._storage.commitVersion(version2, '', t)
self._storage.tpc_finish(self._transaction) self._storage.tpc_vote(t)
self._storage.tpc_finish(t)
eq(len(oids), 1) eq(len(oids), 1)
eq(oids[0], oid2) eq(oids[0], oid2)
data, revid = self._storage.load(oid1, '') data, revid = self._storage.load(oid1, '')
......
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