[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