[Zodb-checkins] CVS: ZODB3/ZEO/zrpc - connection.py:1.38.2.4

Jeremy Hylton jeremy at zope.com
Tue Apr 29 17:36:41 EDT 2003


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

Modified Files:
      Tag: ZODB3-3_1-branch
	connection.py 
Log Message:
Backport assorted fixes.

Allow empty tuple as return value.
Fix pending() to do reads and writes.
Add _deferred_call() and _deferred_wait() for testing.


=== ZODB3/ZEO/zrpc/connection.py 1.38.2.3 => 1.38.2.4 ===
--- ZODB3/ZEO/zrpc/connection.py:1.38.2.3	Thu Dec 19 12:44:04 2002
+++ ZODB3/ZEO/zrpc/connection.py	Tue Apr 29 16:36:41 2003
@@ -323,7 +323,7 @@
             raise DisconnectedError()
         msgid = self.send_call(method, args, 0)
         r_flags, r_args = self.wait(msgid)
-        if (isinstance(r_args, types.TupleType)
+        if (isinstance(r_args, types.TupleType) and len(r_args) > 1
             and type(r_args[0]) == types.ClassType
             and issubclass(r_args[0], Exception)):
             inst = r_args[1]
@@ -331,6 +331,29 @@
         else:
             return r_args
 
+    # For testing purposes, it is useful to begin a synchronous call
+    # but not block waiting for its response.  Since these methods are
+    # used for testing they can assume they are not in async mode and
+    # call asyncore.poll() directly to get the message out without
+    # also waiting for the reply.
+
+    def _deferred_call(self, method, *args):
+        if self.closed:
+            raise DisconnectedError()
+        msgid = self.send_call(method, args, 0)
+        asyncore.poll(0.01, self._map)
+        return msgid
+
+    def _deferred_wait(self, msgid):
+        r_flags, r_args = self.wait(msgid)
+        if (isinstance(r_args, types.TupleType)
+            and type(r_args[0]) == types.ClassType
+            and issubclass(r_args[0], Exception)):
+            inst = r_args[1]
+            raise inst # error raised by server
+        else:
+            return r_args
+        
     def callAsync(self, method, *args):
         if self.closed:
             raise DisconnectedError()
@@ -359,7 +382,7 @@
     def _pull_trigger(self, tryagain=10):
         try:
             self.trigger.pull_trigger()
-        except OSError, e:
+        except OSError:
             self.trigger.close()
             self.trigger = trigger()
             if tryagain > 0:
@@ -419,7 +442,7 @@
         else:
             asyncore.poll(0.0, self._map)
 
-    def pending(self):
+    def pending(self, timeout=0):
         """Invoke mainloop until any pending messages are handled."""
         if __debug__:
             self.log("pending(), async=%d" % self.is_async(), level=zLOG.TRACE)
@@ -427,26 +450,50 @@
             return
         # Inline the asyncore poll() function to know whether any input
         # was actually read.  Repeat until no input is ready.
-        # XXX This only does reads.
-        r_in = [self._fileno]
-        w_in = []
+
+        # Pending does reads and writes.  In the case of server
+        # startup, we may need to write out zeoVerify() messages.
+        # Always check for read status, but don't check for write status
+        # only there is output to do.  Only continue in this loop as
+        # long as there is data to read.
+        r = r_in = [self._fileno]
         x_in = []
-        while 1:
+        while r and not self.closed:
+            if self.writable():
+                w_in = [self._fileno]
+            else:
+                w_in = []
             try:
-                r, w, x = select.select(r_in, w_in, x_in, 0)
+                r, w, x = select.select(r_in, w_in, x_in, timeout)
             except select.error, err:
                 if err[0] == errno.EINTR:
+                    timeout = 0
                     continue
                 else:
                     raise
-            if not r:
-                break
-            try:
-                self.handle_read_event()
-            except asyncore.ExitNow:
-                raise
-            except:
-                self.handle_error()
+            else:
+                # Make sure any subsequent select does not block.  The
+                # loop is only intended to make sure all incoming data is
+                # returned.
+
+                # XXX What if the server sends a lot of invalidations,
+                # such that pending never finishes?  Seems unlikely, but
+                # not impossible.
+                timeout = 0
+            if r:
+                try:
+                    self.handle_read_event()
+                except asyncore.ExitNow:
+                    raise
+                except:
+                    self.handle_error()
+            if w:
+                try:
+                    self.handle_write_event()
+                except asyncore.ExitNow:
+                    raise
+                except:
+                    self.handle_error()
 
 class ManagedServerConnection(Connection):
     """Server-side Connection subclass."""




More information about the Zodb-checkins mailing list