[Zope-Checkins] CVS: ZODB3/ZEO - ClientStorage.py:1.73.2.26.2.1

Barry Warsaw barry@zope.com
Fri, 1 Aug 2003 16:13:13 -0400


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

Modified Files:
      Tag: ZODB3-3_1-boston-branch
	ClientStorage.py 
Log Message:
Fixing a bug discovered via code inspection (and other means <wink>)
in ClientStorage's tpc_finish().  If a storage times out between the
vote and the finish, the zeo cache would have gotten populated with
objects that didn't make it to the storage server.

Specifically, added a new flag called self._midtxn_disconnect which
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, or populating the
cache.

Also, 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.


=== ZODB3/ZEO/ClientStorage.py 1.73.2.26 => 1.73.2.26.2.1 ===
--- ZODB3/ZEO/ClientStorage.py:1.73.2.26	Thu Jun 12 16:36:51 2003
+++ ZODB3/ZEO/ClientStorage.py	Fri Aug  1 16:13:08 2003
@@ -226,6 +226,9 @@
         self._conn_is_read_only = 0
         self._storage = storage
         self._read_only_fallback = read_only_fallback
+        # Flag tracking disconnections in the middle of a transaction.  This
+        # is reset in tpc_begin() and set in notifyDisconnected().
+        self._midtxn_disconnect = 0
         # _server_addr is used by sortKey()
         self._server_addr = None
         self._tfile = None
@@ -505,6 +508,7 @@
         self._connection = None
         self._ready.clear()
         self._server = disconnected_stub
+        self._midtxn_disconnect = 1
 
     def __len__(self):
         """Return the size of the storage."""
@@ -731,6 +735,7 @@
         if self._is_read_only:
             raise POSException.ReadOnlyError()
         self._tpc_cond.acquire()
+        self._midtxn_disconnect = 0
         while self._transaction is not None:
             # It is allowable for a client to call two tpc_begins in a
             # row with the same transaction, and the second of these
@@ -804,6 +809,12 @@
             return
         self._load_lock.acquire()
         try:
+            if self._midtxn_disconnect:
+                raise ClientDisconnected(
+                    'Calling tpc_finish() on a disconnected transaction')
+
+            self._server.tpc_finish(self._serial)
+
             self._lock.acquire()  # for atomic processing of invalidations
             try:
                 self._update_cache()
@@ -811,8 +822,6 @@
                     f()
             finally:
                 self._lock.release()
-
-            self._server.tpc_finish(self._serial)
 
             r = self._check_serials()
             assert r is None or len(r) == 0, "unhandled serialnos: %s" % r