Le jeudi 16 décembre 2010 17:19:33, Jim Fulton a écrit : > Cool. I'll review this for 3.11 and it or somethink like it will go > into that release.
bump :) Attached are: - a stand-alone change to tests/TransactionalUndoStorage.py (it should be acceptable to apply it even without considering the main feature change of my patch) - the main patch, updated a bit: - fix case where Connection._creating is not a dict (it was a list on older ZODB versions - although it shouldn't matter for trunk inclusion) - fix serials of newly created objects (obj._p_changed is None, so serial was not set) I verified there is no regression in "setup.py test", but I get 2 failures (both with an without my changes), one on ZEO/tests/zeo-fan-out.test and another on ZEO.tests.testZEO.client_has_newer_data_than_server . Regards, -- Vincent Pelletier ERP5 - open source ERP/CRM for flexible enterprises
From 9d266460b66d6a852c2072eb46c0e5cdd99413d8 Mon Sep 17 00:00:00 2001 From: Vincent Pelletier <vinc...@nexedi.com> Date: Fri, 10 Dec 2010 08:30:35 +0000 Subject: [RFC 1/2] The number of entries doesn't matter as long as both OIDs are present. --- src/ZODB/tests/TransactionalUndoStorage.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/ZODB/tests/TransactionalUndoStorage.py b/src/ZODB/tests/TransactionalUndoStorage.py index 121dc6c..35cad35 100644 --- a/src/ZODB/tests/TransactionalUndoStorage.py +++ b/src/ZODB/tests/TransactionalUndoStorage.py @@ -289,7 +289,7 @@ class TransactionalUndoStorage: oids = self._begin_undos_vote(t, tid, tid1) self._storage.tpc_finish(t) # We get the finalization stuff called an extra time: - eq(len(oids), 4) + eq(len(set(oids)), 2) unless(oid1 in oids) unless(oid2 in oids) data, revid1 = self._storage.load(oid1, '') -- 1.7.8.3
From 1a293975f758ca33bc18f456c737f1b45d5bb03a Mon Sep 17 00:00:00 2001 From: Vincent Pelletier <vinc...@nexedi.com> Date: Tue, 7 Feb 2012 16:24:20 +0100 Subject: [RFC 2/2] Allow serial to be returned as late as tpc_finish. This makes it possible for storage to only allocate it inside tpc_finish, removing the requirement to serialise 2PC's second phase phase (tpc_vote to tpc_finish/tpc_abort). --- src/ZODB/Connection.py | 11 +++++++- src/ZODB/interfaces.py | 6 +++- src/ZODB/tests/BasicStorage.py | 4 ++- src/ZODB/tests/MTStorage.py | 4 ++- src/ZODB/tests/RevisionStorage.py | 4 ++- src/ZODB/tests/StorageTestBase.py | 10 ++++--- src/ZODB/tests/TransactionalUndoStorage.py | 36 +++++++++++++++++----------- 7 files changed, 51 insertions(+), 24 deletions(-) diff --git a/src/ZODB/Connection.py b/src/ZODB/Connection.py index fa74bc3..200dc5b 100644 --- a/src/ZODB/Connection.py +++ b/src/ZODB/Connection.py @@ -803,7 +803,16 @@ class Connection(ExportImport, object): # to be able to read any updated data until we've had a chance # to send an invalidation message to all of the other # connections! - self._storage.tpc_finish(transaction, callback) + serial = self._storage.tpc_finish(transaction, callback) + if serial is not None: + assert isinstance(serial, str), repr(serial) + for oid_iterator in (self._modified, self._creating): + for oid in oid_iterator: + obj = self._cache.get(oid, None) + # Ignore missing objects and don't update ghosts. + if obj is not None and obj._p_changed is not None: + obj._p_changed = 0 + obj._p_serial = serial self._tpc_cleanup() def sortKey(self): diff --git a/src/ZODB/interfaces.py b/src/ZODB/interfaces.py index 44ded35..db5c525 100644 --- a/src/ZODB/interfaces.py +++ b/src/ZODB/interfaces.py @@ -776,6 +776,10 @@ class IStorage(Interface): called while the storage transaction lock is held. It takes the new transaction id generated by the transaction. + The return value can be either None or a serial giving new + serial for objects whose ids were passed to previous store calls + in the same transaction, and for which no serial was returned + from either store or tpc_vote for objects passed to store. """ def tpc_vote(transaction): @@ -794,8 +798,6 @@ class IStorage(Interface): The return value can be either None or a sequence of object-id and serial pairs giving new serials for objects who's ids were passed to previous store calls in the same transaction. - After the tpc_vote call, new serials must have been returned, - either from tpc_vote or store for objects passed to store. A serial returned in a sequence of oid/serial pairs, may be the special value ZODB.ConflictResolution.ResolvedSerial to diff --git a/src/ZODB/tests/BasicStorage.py b/src/ZODB/tests/BasicStorage.py index 8e72272..61bc801 100644 --- a/src/ZODB/tests/BasicStorage.py +++ b/src/ZODB/tests/BasicStorage.py @@ -72,8 +72,10 @@ class BasicStorage: r1 = self._storage.store(oid, None, zodb_pickle(MinPO(11)), '', txn) r2 = self._storage.tpc_vote(txn) - self._storage.tpc_finish(txn) + serial = self._storage.tpc_finish(txn) newrevid = handle_serials(oid, r1, r2) + if newrevid is None and serial is not None: + newrevid = serial data, revid = self._storage.load(oid, '') value = zodb_unpickle(data) eq(value, MinPO(11)) diff --git a/src/ZODB/tests/MTStorage.py b/src/ZODB/tests/MTStorage.py index e01c802..b57de28 100644 --- a/src/ZODB/tests/MTStorage.py +++ b/src/ZODB/tests/MTStorage.py @@ -155,10 +155,12 @@ class StorageClientThread(TestThread): r2 = self.storage.tpc_vote(t) self.pause() - self.storage.tpc_finish(t) + serial = self.storage.tpc_finish(t) self.pause() revid = handle_serials(oid, r1, r2) + if serial is not None and revid is None: + revid = serial self.oids[oid] = revid class ExtStorageClientThread(StorageClientThread): diff --git a/src/ZODB/tests/RevisionStorage.py b/src/ZODB/tests/RevisionStorage.py index 9113757..ddd2dde 100644 --- a/src/ZODB/tests/RevisionStorage.py +++ b/src/ZODB/tests/RevisionStorage.py @@ -150,10 +150,12 @@ class RevisionStorage: # Finish the transaction r2 = self._storage.tpc_vote(t) newrevid = handle_serials(oid, r1, r2) - self._storage.tpc_finish(t) + serial = self._storage.tpc_finish(t) except: self._storage.tpc_abort(t) raise + if serial is not None and newrevid is None: + newrevid = serial return newrevid revid1 = helper(1, None, 1) revid2 = helper(2, revid1, 2) diff --git a/src/ZODB/tests/StorageTestBase.py b/src/ZODB/tests/StorageTestBase.py index 9737ec4..43f29ed 100644 --- a/src/ZODB/tests/StorageTestBase.py +++ b/src/ZODB/tests/StorageTestBase.py @@ -134,7 +134,7 @@ def handle_serials(oid, *args): A helper for function _handle_all_serials(). """ - return handle_all_serials(oid, *args)[oid] + return handle_all_serials(oid, *args).get(oid) def import_helper(name): __import__(name) @@ -191,7 +191,9 @@ class StorageTestBase(ZODB.tests.util.TestCase): # Finish the transaction r2 = self._storage.tpc_vote(t) revid = handle_serials(oid, r1, r2) - self._storage.tpc_finish(t) + serial = self._storage.tpc_finish(t) + if serial is not None and revid is None: + revid = serial except: self._storage.tpc_abort(t) raise @@ -211,8 +213,8 @@ class StorageTestBase(ZODB.tests.util.TestCase): self._storage.tpc_begin(t) undo_result = self._storage.undo(tid, t) vote_result = self._storage.tpc_vote(t) - self._storage.tpc_finish(t) - if expected_oids is not None: + serial = self._storage.tpc_finish(t) + if expected_oids is not None and serial is None: oids = undo_result and undo_result[1] or [] oids.extend(oid for (oid, _) in vote_result or ()) self.assertEqual(len(oids), len(expected_oids), repr(oids)) diff --git a/src/ZODB/tests/TransactionalUndoStorage.py b/src/ZODB/tests/TransactionalUndoStorage.py index 35cad35..3730348 100644 --- a/src/ZODB/tests/TransactionalUndoStorage.py +++ b/src/ZODB/tests/TransactionalUndoStorage.py @@ -75,6 +75,12 @@ class TransactionalUndoStorage: def _transaction_newserial(self, oid): return self.__serials[oid] + def _transaction_finish(self, t, oid_list): + tid = self._storage.tpc_finish(t) + if tid is not None: + for oid in oid_list: + self.__serials[oid] = tid + def _multi_obj_transaction(self, objs): newrevs = {} t = Transaction() @@ -84,7 +90,7 @@ class TransactionalUndoStorage: self._transaction_store(oid, rev, data, '', t) newrevs[oid] = None self._transaction_vote(t) - self._storage.tpc_finish(t) + self._transaction_finish(t, [x[0] for x in objs]) for oid in newrevs.keys(): newrevs[oid] = self._transaction_newserial(oid) return newrevs @@ -217,9 +223,9 @@ class TransactionalUndoStorage: self._transaction_store(oid2, revid2, p51, '', t) # Finish the transaction self._transaction_vote(t) + self._transaction_finish(t, [oid1, oid2]) revid1 = self._transaction_newserial(oid1) revid2 = self._transaction_newserial(oid2) - self._storage.tpc_finish(t) eq(revid1, revid2) # Update those same two objects t = Transaction() @@ -229,9 +235,9 @@ class TransactionalUndoStorage: self._transaction_store(oid2, revid2, p52, '', t) # Finish the transaction self._transaction_vote(t) + self._transaction_finish(t, [oid1, oid2]) revid1 = self._transaction_newserial(oid1) revid2 = self._transaction_newserial(oid2) - self._storage.tpc_finish(t) eq(revid1, revid2) # Make sure the objects have the current value data, revid1 = self._storage.load(oid1, '') @@ -287,11 +293,12 @@ class TransactionalUndoStorage: tid1 = info[1]['id'] t = Transaction() oids = self._begin_undos_vote(t, tid, tid1) - self._storage.tpc_finish(t) + serial = self._storage.tpc_finish(t) # We get the finalization stuff called an extra time: - eq(len(set(oids)), 2) - unless(oid1 in oids) - unless(oid2 in oids) + if serial is None: + eq(len(set(oids)), 2) + unless(oid1 in oids) + unless(oid2 in oids) data, revid1 = self._storage.load(oid1, '') eq(zodb_unpickle(data), MinPO(30)) data, revid2 = self._storage.load(oid2, '') @@ -325,7 +332,7 @@ class TransactionalUndoStorage: self._transaction_store(oid2, revid2, p52, '', t) # Finish the transaction self._transaction_vote(t) - self._storage.tpc_finish(t) + self._transaction_finish(t, [oid1, oid2]) revid1 = self._transaction_newserial(oid1) revid2 = self._transaction_newserial(oid2) eq(revid1, revid2) @@ -345,7 +352,7 @@ class TransactionalUndoStorage: self._transaction_store(oid2, revid2, p53, '', t) # Finish the transaction self._transaction_vote(t) - self._storage.tpc_finish(t) + self._transaction_finish(t, [oid1, oid2]) revid1 = self._transaction_newserial(oid1) revid2 = self._transaction_newserial(oid2) eq(revid1, revid2) @@ -357,10 +364,11 @@ class TransactionalUndoStorage: tid = info[1]['id'] t = Transaction() oids = self._begin_undos_vote(t, tid) - self._storage.tpc_finish(t) - eq(len(oids), 1) - self.failUnless(oid1 in oids) - self.failUnless(not oid2 in oids) + serial = self._storage.tpc_finish(t) + if serial is None: + eq(len(oids), 1) + self.failUnless(oid1 in oids) + self.failUnless(not oid2 in oids) data, revid1 = self._storage.load(oid1, '') eq(zodb_unpickle(data), MinPO(33)) data, revid2 = self._storage.load(oid2, '') @@ -396,7 +404,7 @@ class TransactionalUndoStorage: self._transaction_store(oid1, revid1, p81, '', t) self._transaction_store(oid2, revid2, p91, '', t) self._transaction_vote(t) - self._storage.tpc_finish(t) + self._transaction_finish(t, [oid1, oid2]) revid1 = self._transaction_newserial(oid1) revid2 = self._transaction_newserial(oid2) eq(revid1, revid2) -- 1.7.8.3
_______________________________________________ For more information about ZODB, see http://zodb.org/ ZODB-Dev mailing list - ZODB-Dev@zope.org https://mail.zope.org/mailman/listinfo/zodb-dev