[Zodb-checkins] SVN: ZODB/trunk/src/ZODB/ Fixed multiple undo in a
transaction.
Shane Hathaway
shane at zope.com
Fri Feb 3 01:07:48 EST 2006
Log message for revision 41550:
Fixed multiple undo in a transaction.
For multiple undo to succeed, the undo operations have to be
performed in a specific order. The order was not being retained
by ZODB and was instead semi-random (the order depended on the
id() function.) Now undo operations (as well as all
ResourceManagers) are sorted by creation order.
Changed:
U ZODB/trunk/src/ZODB/DB.py
U ZODB/trunk/src/ZODB/tests/testZODB.py
-=-
Modified: ZODB/trunk/src/ZODB/DB.py
===================================================================
--- ZODB/trunk/src/ZODB/DB.py 2006-02-03 00:50:51 UTC (rev 41549)
+++ ZODB/trunk/src/ZODB/DB.py 2006-02-03 06:07:47 UTC (rev 41550)
@@ -679,6 +679,9 @@
def versionEmpty(self, version):
return self._storage.versionEmpty(version)
+resource_counter_lock = threading.Lock()
+resource_counter = 0
+
class ResourceManager(object):
"""Transaction participation for a version or undo resource."""
@@ -689,8 +692,20 @@
self.tpc_finish = self._db._storage.tpc_finish
self.tpc_abort = self._db._storage.tpc_abort
+ # Get a number from a simple thread-safe counter, then
+ # increment it, for the purpose of sorting ResourceManagers by
+ # creation order. This ensures that multiple ResourceManagers
+ # within a transaction commit in a predictable sequence.
+ resource_counter_lock.acquire()
+ try:
+ global resource_counter
+ self._count = resource_counter
+ resource_counter += 1
+ finally:
+ resource_counter_lock.release()
+
def sortKey(self):
- return "%s:%s" % (self._db._storage.sortKey(), id(self))
+ return "%s:%016x" % (self._db._storage.sortKey(), self._count)
def tpc_begin(self, txn, sub=False):
if sub:
Modified: ZODB/trunk/src/ZODB/tests/testZODB.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testZODB.py 2006-02-03 00:50:51 UTC (rev 41549)
+++ ZODB/trunk/src/ZODB/tests/testZODB.py 2006-02-03 06:07:47 UTC (rev 41550)
@@ -728,6 +728,42 @@
cn.close()
cn2.close()
+ def checkMultipleUndoInOneTransaction(self):
+ # Verify that it's possible to perform multiple undo
+ # operations within a transaction. If ZODB performs the undo
+ # operations in a nondeterministic order, this test will often
+ # fail.
+
+ conn = self._db.open()
+ try:
+ root = conn.root()
+
+ # Add transactions that set root["state"] to (0..5)
+ for state_num in range(6):
+ transaction.begin()
+ root['state'] = state_num
+ transaction.get().note('root["state"] = %d' % state_num)
+ transaction.commit()
+
+ # Undo all but the first. Note that no work is actually
+ # performed yet.
+ transaction.begin()
+ log = self._db.undoLog()
+ for i in range(5):
+ self._db.undo(log[i]['id'])
+ transaction.get().note('undo states 1 through 5')
+
+ # Now attempt all those undo operations.
+ transaction.commit()
+
+ # Sanity check: we should be back to the first state.
+ self.assertEqual(root['state'], 0)
+ finally:
+ transaction.abort()
+ conn.close()
+
+
+
class PoisonedError(Exception):
pass
More information about the Zodb-checkins
mailing list