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

Reply via email to