[Zodb-checkins] CVS: StandaloneZODB/ZEO - zrpc2.py:1.3.2.3

Jeremy Hylton jeremy@zope.com
Tue, 15 Jan 2002 17:38:41 -0500


Update of /cvs-repository/StandaloneZODB/ZEO
In directory cvs.zope.org:/tmp/cvs-serv12065

Modified Files:
      Tag: Standby-branch
	zrpc2.py 
Log Message:
Rework the is_async() logic to actually work in cases where it is true.

Implement the various classes that care using thr_async variable -- to
avoid confusion with other async things like
SizedMessageAsyncConnection and asynchronous messages.

As a comment in the Connection constructor explains:
    # A Connection either uses asyncore directly or relies on an
    # asyncore mainloop running in a separate thread.  If
    # thr_async is true, then the mainloop is running in a
    # separate thread.  If thr_async is true, then the asyncore
    # trigger (self.trigger) is used to notify that thread of
    # activity on the current thread.

Make sure that ManagedConnection sets thr_async and trigger properly,
based on the ConnectionManager.




=== StandaloneZODB/ZEO/zrpc2.py 1.3.2.2 => 1.3.2.3 ===
 
     def __init__(self, sock, addr, obj=None):
-        self.msgid = 0
         self.obj = obj
         self.marshal = Marshaller()
         self.closed = 0
-        self.async = 0
-        self.trigger = None
-        # The reply lock is used to block when a synchronous call is
-        # waiting for a response
+        self.msgid = 0
         self.__super_init(sock, addr)
-        self._map = {self._fileno: self}
+        # A Connection either uses asyncore directly or relies on an
+        # asyncore mainloop running in a separate thread.  If
+        # thr_async is true, then the mainloop is running in a
+        # separate thread.  If thr_async is true, then the asyncore
+        # trigger (self.trigger) is used to notify that thread of
+        # activity on the current thread.
+        self.thr_async = 0
+        self.trigger = None
         self._prepare_async()
+        self._map = {self._fileno: self}
         self.__call_lock = thread.allocate_lock()
+        # The reply lock is used to block when a synchronous call is
+        # waiting for a response
         self.__reply_lock = thread.allocate_lock()
         self.__reply_lock.acquire()
+        # If the object implements the Handler interface (XXX checked
+        # by isinstance), it wants to know who the caller is.
         if isinstance(obj, Handler):
             self.set_caller = 1
         else:
             self.set_caller = 0
 
     def __repr__(self):
-        return "<%s %s>" % (self.__class__.__name__, self.addr)
+        return "<%s %s %s>" % (self.__class__.__name__, self.addr,
+                               hex(id(self)))
 
     def close(self):
         if self.closed:
@@ -338,7 +347,7 @@
         pass # XXX what is this supposed to do?
 
     def _prepare_async(self):
-        self._async = 0
+        self.thr_async = 0
         ThreadedAsync.register_loop_callback(self.set_async)
         # XXX If we are not in async mode, this will cause dead
         # Connections to be leaked.
@@ -346,18 +355,21 @@
     def set_async(self, map):
         # XXX do we need a lock around this?  I'm not sure there is
         # any harm to a race with _do_io().
-        self._async = 1
         self.trigger = trigger.trigger()
+        self.thr_async = 1
 
     def is_async(self):
-        return self._async
+        if self.thr_async:
+            return 1
+        else:
+            return 0
             
     def _do_io(self, wait=0): # XXX need better name
         # XXX invariant? lock must be held when calling with wait==1
         # otherwise, in non-async mode, there will be no poll
 
         if __debug__:
-            log("_do_io(wait=%d), async=%d" % (wait, self.is_async()),
+            log("_do_io(wait=%d), async=%s" % (wait, self.is_async()),
                 level=zLOG.DEBUG)
         if self.is_async():
             self.trigger.pull_trigger()
@@ -406,7 +418,7 @@
         self._thread = None
         self._connect_lock = threading.Lock()
         self.trigger = None
-        self.async = 0
+        self.thr_async = 0
         self.closed = 0
         ThreadedAsync.register_loop_callback(self.set_async)
 
@@ -464,8 +476,8 @@
 
     def set_async(self, map):
         # XXX need each connection started with async==0 to have a callback
-        self.async = 1 # XXX needs to be set on the Connection
         self.trigger = trigger.trigger()
+        self.thr_async = 1 # XXX needs to be set on the Connection
 
     def connect(self, sync=0):
         if self.connected == 1:
@@ -594,7 +606,9 @@
             self.connection = c
             return 1
         except:
-            # XXX zLOG the error
+            zLOG.LOG(_label, zLOG.ERROR,
+                     "error connecting to server: %s" % str(addr),
+                     error=sys.exc_info())
             c.close()
         return 0
 
@@ -622,29 +636,30 @@
 
     def __init__(self, sock, addr, obj, mgr):
         self.__mgr = mgr
-        if self.__mgr.async:
-            self.__async = 1
-            self.trigger = self.__mgr.trigger
-        else:
-            self.__async = None
         self.__super_init(sock, addr, obj)
+        self.check_mgr_async()
 
     def close_trigger(self):
         # the manager should actually close the trigger
         del self.trigger
 
     def _prepare_async(self):
-        # Don't do the register_loop_callback that the superclass does
+        # Don't do the register_loop_callback; the manager handles it
         pass
 
+    def check_mgr_async(self):
+        if not self.thr_async and self.__mgr.thr_async:
+            assert self.__mgr.trigger is not None, \
+                   "manager (%s) has no trigger" % self.__mgr
+            self.thr_async = 1
+            self.trigger = self.__mgr.trigger
+            return 1
+        return 0
+
     def is_async(self):
-        if self.__async:
+        if self.thr_async:
             return 1
-        async = self.__mgr.async
-        if async:
-            self.__async = 1
-            self.trigger = self.__mgr.trigger
-        return async
+        return self.check_mgr_async()
 
     def close(self):
         self.__super_close()
@@ -726,4 +741,3 @@
         return r
 
     raise ZRPCError("Unsafe global: %s.%s" % (module, name))
-