[Zope-Checkins] CVS: ZODB3/ZEO/tests - ConnectionTests.py:1.4.2.6 testZEO.py:1.54.2.8

Tim Peters tim.one at comcast.net
Mon Aug 4 19:14:07 EDT 2003


Update of /cvs-repository/ZODB3/ZEO/tests
In directory cvs.zope.org:/tmp/cvs-serv24603/ZEO/tests

Modified Files:
      Tag: ZODB3-3_1-branch
	ConnectionTests.py testZEO.py 
Log Message:
Side-porting critical ZEO client fixes from ZODB3-3_1-boston-branch.

+ If a storage times out between the vote and the finish, the ZEO cache
  could get populated with objects that don't make it to the storage
  server.

  A new flag self._midtxn_disconnect gets reset in tpc_begin() and set
  in notifyDisconnected().  If tpc_finish() discovers this flag set, it
  raises a ClientDisconnected error before calling tpc_finish() on the
  server.

+ In tpc_finish() we re-order the calls so that the server's tpc_finish()
  is called (and must succeed) before we update the ZEO client cache.

+ The storage name is now prepended to the sort key, to ensure a
  unique global sort order if storages are named uniquely.

NOTE:  The Berkeley tests are all hosed on Windows in this branch now,
but that was true before this patch.


=== ZODB3/ZEO/tests/ConnectionTests.py 1.4.2.5 => 1.4.2.6 ===
--- ZODB3/ZEO/tests/ConnectionTests.py:1.4.2.5	Wed Jun 11 19:11:32 2003
+++ ZODB3/ZEO/tests/ConnectionTests.py	Mon Aug  4 18:14:00 2003
@@ -26,16 +26,17 @@
 from ZEO.ClientStorage import ClientStorage, ClientDisconnected
 from ZEO.Exceptions import Disconnected
 from ZEO.zrpc.marshal import Marshaller
+from ZEO.zrpc.error import DisconnectedError
 from ZEO.tests.InvalidationTests import InvalidationTests
 
 from ZODB.Transaction import get_transaction, Transaction
-from ZODB.POSException import ReadOnlyError
+from ZODB.POSException import ReadOnlyError, ConflictError
 from ZODB.tests import StorageTestBase
 from ZODB.tests.MinPO import MinPO
 from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle
 
 class DummyDB:
-    def invalidate(self, *args):
+    def invalidate(self, *args, **kws):
         pass
 
 class ConnectionTests(StorageTestBase.StorageTestBase,
@@ -577,3 +578,103 @@
         storage.tpc_begin(txn)
         storage.tpc_abort(txn)
 
+    def checkTimeoutAfterVote(self):
+        raises = self.assertRaises
+        unless = self.failUnless
+        self.shutdownServer()
+        self.startServer(transaction_timeout=1)
+        self._storage = storage = self.openClientStorage()
+        # Assert that the zeo cache is empty
+        unless(not storage._cache._index)
+        # Create the object
+        oid = storage.new_oid()
+        obj = MinPO(7)
+        ZERO = '\0'*8
+        # Now do a store, sleeping before the finish so as to cause a timeout
+        t = Transaction()
+        storage.tpc_begin(t)
+        revid1 = storage.store(oid, ZERO, zodb_pickle(obj), '', t)
+        storage.tpc_vote(t)
+        # Now sleep long enough for the storage to time out
+        time.sleep(3)
+        storage.sync()
+        unless(not storage.is_connected())
+        storage._wait()
+        unless(storage.is_connected())
+        # We expect finish to fail
+        raises(ClientDisconnected, storage.tpc_finish, t)
+        # The cache should still be empty
+        unless(not storage._cache._index)
+        # Load should fail since the object should not be in either the cache
+        # or the server.
+        raises(KeyError, storage.load, oid, '')
+
+    def checkTimeoutProvokingConflicts(self):
+        eq = self.assertEqual
+        raises = self.assertRaises
+        unless = self.failUnless
+        self.shutdownServer()
+        self.startServer(transaction_timeout=1)
+        self._storage = storage = self.openClientStorage()
+        # Assert that the zeo cache is empty
+        unless(not storage._cache._index)
+        # Create the object
+        oid = storage.new_oid()
+        obj = MinPO(7)
+        ZERO = '\0'*8
+        # We need to successfully commit an object now so we have something to
+        # conflict about.
+        t = Transaction()
+        storage.tpc_begin(t)
+        revid1a = storage.store(oid, ZERO, zodb_pickle(obj), '', t)
+        revid1b = storage.tpc_vote(t)
+        revid1 = StorageTestBase.handle_serials(oid, revid1a, revid1b)
+        storage.tpc_finish(t)
+        # Now do a store, sleeping before the finish so as to cause a timeout
+        obj.value = 8
+        t = Transaction()
+        storage.tpc_begin(t)
+        revid2a = storage.store(oid, revid1, zodb_pickle(obj), '', t)
+        revid2b = storage.tpc_vote(t)
+        revid2 = StorageTestBase.handle_serials(oid, revid2a, revid2b)
+        # Now sleep long enough for the storage to time out
+        time.sleep(3)
+        storage.sync()
+        unless(not storage.is_connected())
+        storage._wait()
+        unless(storage.is_connected())
+        # We expect finish to fail
+        raises(ClientDisconnected, storage.tpc_finish, t)
+        # Now we think we've committed the second transaction, but we really
+        # haven't.  A third one should produce a POSKeyError on the server,
+        # which manifests as a ConflictError on the client.
+        obj.value = 9
+        t = Transaction()
+        storage.tpc_begin(t)
+        storage.store(oid, revid2, zodb_pickle(obj), '', t)
+        raises(ConflictError, storage.tpc_vote, t)
+        # Even aborting won't help
+        storage.tpc_abort(t)
+        storage.tpc_finish(t)
+        # Try again
+        obj.value = 10
+        t = Transaction()
+        storage.tpc_begin(t)
+        storage.store(oid, revid2, zodb_pickle(obj), '', t)
+        # Even aborting won't help
+        raises(ConflictError, storage.tpc_vote, t)
+        # Abort this one and try a transaction that should succeed
+        storage.tpc_abort(t)
+        storage.tpc_finish(t)
+        # Now do a store, sleeping before the finish so as to cause a timeout
+        obj.value = 11
+        t = Transaction()
+        storage.tpc_begin(t)
+        revid2a = storage.store(oid, revid1, zodb_pickle(obj), '', t)
+        revid2b = storage.tpc_vote(t)
+        revid2 = StorageTestBase.handle_serials(oid, revid2a, revid2b)
+        storage.tpc_finish(t)
+        # Now load the object and verify that it has a value of 11
+        data, revid = storage.load(oid, '')
+        eq(zodb_unpickle(data), MinPO(11))
+        eq(revid, revid2)


=== ZODB3/ZEO/tests/testZEO.py 1.54.2.7 => 1.54.2.8 ===
--- ZODB3/ZEO/tests/testZEO.py:1.54.2.7	Mon Jul 28 13:53:11 2003
+++ ZODB3/ZEO/tests/testZEO.py	Mon Aug  4 18:14:00 2003
@@ -142,6 +142,11 @@
         if hasattr(ZODB, "__version__"):
             ReadOnlyStorage.ReadOnlyStorage.checkWriteMethods(self)
 
+    def checkSortKey(self):
+        key = '%s:%s' % (self._storage._storage, self._storage._server_addr)
+        self.assertEqual(self._storage.sortKey(), key)
+
+
 class UnixTests(GenericTests):
 
     """Add Unix-specific scaffolding to the generic test suite."""




More information about the Zope-Checkins mailing list