[Zodb-checkins] CVS: ZODB3/ZEO/tests - ConnectionTests.py:1.18 ThreadTests.py:1.7

Jeremy Hylton jeremy@zope.com
Fri, 17 Jan 2003 12:20:09 -0500


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

Modified Files:
	ConnectionTests.py ThreadTests.py 
Log Message:
Change handling of tpc_abort() during disconnection.

Fix likely bug where calling tpc_abort() after a client disconnected
did not properly clear the client's internal state about the
transaction.  The change means that tpc_abort() will never raise a
ClientDisconnected error, even when disconnected.

Added a new test that sort-of covers this case and deleted another
that was testing, in part, that you did get a ClientDisconnected
error.


=== ZODB3/ZEO/tests/ConnectionTests.py 1.17 => 1.18 ===
--- ZODB3/ZEO/tests/ConnectionTests.py:1.17	Wed Jan 15 13:19:16 2003
+++ ZODB3/ZEO/tests/ConnectionTests.py	Fri Jan 17 12:20:04 2003
@@ -282,6 +282,41 @@
         self.assertRaises(ClientDisconnected,
                           self._storage.load, 'fredwash', '')
 
+    def checkDisconnectedAbort(self):
+        self._storage = self.openClientStorage()
+        self._dostore()
+        oids = [self._storage.new_oid() for i in range(5)]
+        txn = Transaction()
+        self._storage.tpc_begin(txn)
+        for oid in oids:
+            data = zodb_pickle(MinPO(oid))
+            self._storage.store(oid, None, data, '', txn)
+        self.shutdownServer()
+        self.assertRaises(ClientDisconnected, self._storage.tpc_vote, txn)
+        self._storage.tpc_abort(txn)
+        self.startServer(create=0)
+        self._storage._wait()
+        self._dostore()
+
+        # This test is supposed to cover the following error, although
+        # I don't have much confidence that it does.  The likely
+        # explanation for the error is that the _tbuf contained
+        # objects that weren't in the _seriald, because the client was
+        # interrupted waiting for tpc_vote() to return.  When the next
+        # transaction committed, it tried to do something with the
+        # bogus _tbuf entries.  The exaplanation is wrong/incomplete,
+        # because tpc_begin() should clear the _tbuf.
+
+        # 2003-01-15T15:44:19 ERROR(200) ZODB A storage error occurred
+        # in the last phase of a two-phase commit.  This shouldn't happen.
+
+        # Traceback (innermost last):
+        # Module ZODB.Transaction, line 359, in _finish_one
+        # Module ZODB.Connection, line 691, in tpc_finish
+        # Module ZEO.ClientStorage, line 679, in tpc_finish
+        # Module ZEO.ClientStorage, line 709, in _update_cache
+        # KeyError: ...
+
     def checkBasicPersistence(self):
         # Verify cached data persists across client storage instances.
 


=== ZODB3/ZEO/tests/ThreadTests.py 1.6 => 1.7 ===
--- ZODB3/ZEO/tests/ThreadTests.py:1.6	Wed Jan 15 13:19:16 2003
+++ ZODB3/ZEO/tests/ThreadTests.py	Fri Jan 17 12:20:04 2003
@@ -73,23 +73,6 @@
             self.gotValueError = 1
 
 
-class AbortsAfterBeginFailsThread(BasicThread):
-    # This class is identical to GetsThroughBeginThread except that it
-    # attempts to tpc_abort() after the tpc_begin() fails.  That will raise a
-    # ClientDisconnected exception which implies that we don't have the lock,
-    # and that's what we really want to test (but it's difficult given the
-    # threading module's API).
-    def run(self):
-        try:
-            self.storage.tpc_begin(self.trans)
-        except ZEO.ClientStorage.ClientStorageError:
-            self.gotValueError = 1
-        try:
-            self.storage.tpc_abort(self.trans)
-        except ClientDisconnected:
-            self.gotDisconnected = 1
-
-
 class ThreadTests:
     # Thread 1 should start a transaction, but not get all the way through it.
     # Main thread should close the connection.  Thread 1 should then get
@@ -127,24 +110,6 @@
         thread2.join()
         self.assertEqual(thread1.gotValueError, 1)
         self.assertEqual(thread2.gotValueError, 1)
-
-    def checkThatFailedBeginDoesNotHaveLock(self):
-        doNextEvent = threading.Event()
-        threadStartedEvent = threading.Event()
-        thread1 = GetsThroughVoteThread(self._storage,
-                                        doNextEvent, threadStartedEvent)
-        thread2 = AbortsAfterBeginFailsThread(self._storage,
-                                              doNextEvent, threadStartedEvent)
-        thread1.start()
-        threadStartedEvent.wait(1)
-        thread2.start()
-        self._storage.close()
-        doNextEvent.set()
-        thread1.join()
-        thread2.join()
-        self.assertEqual(thread1.gotValueError, 1)
-        self.assertEqual(thread2.gotValueError, 1)
-        self.assertEqual(thread2.gotDisconnected, 1)
 
     # Run a bunch of threads doing small and large stores in parallel
     def checkMTStores(self):