[Zodb-checkins] SVN: ZODB/trunk/src/ZEO/ Fixed a threading bug.

Jim Fulton jim at zope.com
Wed Feb 3 17:09:56 EST 2010


Log message for revision 108740:
  Fixed a threading bug.
  

Changed:
  U   ZODB/trunk/src/ZEO/StorageServer.py
  U   ZODB/trunk/src/ZEO/zrpc/connection.py

-=-
Modified: ZODB/trunk/src/ZEO/StorageServer.py
===================================================================
--- ZODB/trunk/src/ZEO/StorageServer.py	2010-02-03 22:09:53 UTC (rev 108739)
+++ ZODB/trunk/src/ZEO/StorageServer.py	2010-02-03 22:09:56 UTC (rev 108740)
@@ -1346,8 +1346,21 @@
         self.rpc.callAsync('endVerify')
 
     def invalidateTransaction(self, tid, args):
-        self.rpc.callAsync('invalidateTransaction', tid, args)
+        # Note that this method is *always* called from a different
+        # thread than self.rpc's async thread. It is the only method
+        # for which this is true and requires special consideration!
 
+        # callAsyncNoSend is important here because:
+        # - callAsyncNoPoll isn't appropriate because
+        #   the network thread may not wake up for a long time,
+        #   delaying invalidations for too long. (This is demonstrateed
+        #   by a test failure.)
+        # - callAsync isn't appropriate because (on the server) it tries
+        #   to write to the socket.  If self.rpc's network thread also
+        #   tries to write at the ame time, we can run into problems
+        #   because handle_write isn't thread safe.
+        self.rpc.callAsyncNoSend('invalidateTransaction', tid, args)
+
     def serialnos(self, arg):
         self.rpc.callAsyncNoPoll('serialnos', arg)
 

Modified: ZODB/trunk/src/ZEO/zrpc/connection.py
===================================================================
--- ZODB/trunk/src/ZEO/zrpc/connection.py	2010-02-03 22:09:53 UTC (rev 108739)
+++ ZODB/trunk/src/ZEO/zrpc/connection.py	2010-02-03 22:09:56 UTC (rev 108740)
@@ -535,6 +535,15 @@
             raise DisconnectedError()
         self.send_call(method, args, 1)
 
+    def callAsyncNoSend(self, method, *args):
+        # Like CallAsync but doesn't poll.  This exists so that we can
+        # send invalidations atomically to all clients without
+        # allowing any client to sneak in a load request.
+        if self.closed:
+            raise DisconnectedError()
+        self.send_call(method, args, 1)
+        self.call_from_thread()
+
     def callAsyncIterator(self, iterator):
         """Queue a sequence of calls using an iterator
 



More information about the Zodb-checkins mailing list