[Neo-report] r2286 vincent - in /trunk/neo: ./ client/ tests/client/

nobody at svn.erp5.org nobody at svn.erp5.org
Thu Sep 2 19:28:59 CEST 2010


Author: vincent
Date: Thu Sep  2 19:28:59 2010
New Revision: 2286

Log:
Make Storage.load generate a network barrier to master node.

This makes sure all invalidations about loaded object up to its actual load
have been received by client, and forwarded to ZODB.
This fixes a potential problem of a transaction being able to see objects
committed by another transaction after it started itself.

Modified:
    trunk/neo/client/app.py
    trunk/neo/handler.py
    trunk/neo/protocol.py
    trunk/neo/tests/client/testClientApp.py

Modified: trunk/neo/client/app.py
==============================================================================
--- trunk/neo/client/app.py [iso-8859-1] (original)
+++ trunk/neo/client/app.py [iso-8859-1] Thu Sep  2 19:28:59 2010
@@ -550,7 +550,15 @@ class Application(object):
             finally:
                 self._cache_lock_release()
             # Otherwise get it from storage node
-            return self._load(oid, cache=1)[:2]
+            result = self._load(oid, cache=1)[:2]
+            # Start a network barrier, so we get all invalidations *after* we
+            # received data. This ensures we get any invalidation message that
+            # would have been about the version we loaded.
+            # Those invalidations are checked at ZODB level, so it decides if
+            # loaded data can be handed to current transaction or if a separate
+            # loadBefore call is required.
+            self._askPrimary(Packets.AskBarrier())
+            return result
         finally:
             self._load_lock_release()
 

Modified: trunk/neo/handler.py
==============================================================================
--- trunk/neo/handler.py [iso-8859-1] (original)
+++ trunk/neo/handler.py [iso-8859-1] Thu Sep  2 19:28:59 2010
@@ -347,6 +347,12 @@ class EventHandler(object):
     def answerHasLock(self, conn, oid, status):
         raise UnexpectedPacketError
 
+    def askBarrier(self, conn):
+        conn.answer(Packets.AnswerBarrier())
+
+    def answerBarrier(self, conn):
+        pass
+
     # Error packet handlers.
 
     def error(self, conn, code, message):
@@ -460,6 +466,8 @@ class EventHandler(object):
         d[Packets.AnswerObjectUndoSerial] = self.answerObjectUndoSerial
         d[Packets.AskHasLock] = self.askHasLock
         d[Packets.AnswerHasLock] = self.answerHasLock
+        d[Packets.AskBarrier] = self.askBarrier
+        d[Packets.AnswerBarrier] = self.answerBarrier
 
         return d
 

Modified: trunk/neo/protocol.py
==============================================================================
--- trunk/neo/protocol.py [iso-8859-1] (original)
+++ trunk/neo/protocol.py [iso-8859-1] Thu Sep  2 19:28:59 2010
@@ -1623,6 +1623,17 @@ class AnswerHasLock(Packet):
         oid, state = unpack(self._header_format, body)
         return (oid, _decodeLockState(state))
 
+class AskBarrier(Packet):
+    """
+    Initates a "network barrier", allowing the node sending this packet to know
+    when all packets sent previously on the same connection have been handled
+    by its peer.
+    """
+    pass
+
+class AnswerBarrier(Packet):
+    pass
+
 class Error(Packet):
     """
     Error is a special type of message, because this can be sent against
@@ -1858,6 +1869,10 @@ class PacketRegistry(dict):
             0x0036,
             AskObjectHistoryFrom,
             AnswerObjectHistoryFrom)
+    AskBarrier, AnswerBarrier = register(
+            0x037,
+            AskBarrier,
+            AnswerBarrier)
 
 # build a "singleton"
 Packets = PacketRegistry()

Modified: trunk/neo/tests/client/testClientApp.py
==============================================================================
--- trunk/neo/tests/client/testClientApp.py [iso-8859-1] (original)
+++ trunk/neo/tests/client/testClientApp.py [iso-8859-1] Thu Sep  2 19:28:59 2010
@@ -261,6 +261,12 @@ class ClientApplicationTests(NeoTestBase
         })
         app.cp = Mock({ 'getConnForCell' : conn})
         app.local_var.asked_object = an_object[:-1]
+        answer_barrier = Packets.AnswerBarrier()
+        answer_barrier.setId(1)
+        app.master_conn = Mock({
+            'getNextId': 1,
+            'fakeReceived': answer_barrier,
+        })
         result = app.load(oid)
         self.assertEquals(result, ('OBJ', tid1))
         self.checkAskObject(conn)





More information about the Neo-report mailing list