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

Jeremy Hylton jeremy@zope.com
Thu, 3 Jan 2002 17:35:26 -0500


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

Modified Files:
      Tag: ZEO-ZRPC-Dev
	zrpc2.py 
Log Message:
Fix problems with reconnecting to server and shutdown.

_thread = None not __thread = None!!!

The __connect() thread must assign None to _thread when it is done in
order to allow future reconnection attempts to succeed.

Exit __connect() thread if the manager is closed.

In close() method, if there is a helper thread attempting to connect
to server, wait() for it before returning.

Add minimal doc string for __connect().

Change poorly named handle_error().  This method name is reserved by
asyncore, but was also being used to log error messages in the rpc.
Add a log_error() and call it from, the rpc code.  Add a new
handle_error() that calls log_error().



=== StandaloneZODB/ZEO/zrpc2.py 1.1.2.15 => 1.1.2.16 ===
                 self.send_reply(msgid, ret)
 
-    def handle_error(self, msg="No error message supplied"):
+    def handle_error(self):
+        self.log_error()
+        self.close()
+
+    def log_error(self, msg="No error message supplied"):
         error = sys.exc_info()
         log(msg, zeolog.ERROR, error=error)
+        del error
 
     def check_method(self, name):
         # XXX minimal security check should go here: Is name exported?
@@ -255,10 +260,10 @@
     
     def return_error(self, msgid, flags, err_type, err_value):
         if flags is None:
-            self.handle_error("Exception raised during decoding")
+            self.log_error("Exception raised during decoding")
             return
         if flags & ASYNC:
-            self.handle_error("Asynchronous call raised exception: %s" % self)
+            self.log_error("Asynchronous call raised exception: %s" % self)
             return
         if type(err_value) is not types.InstanceType:
             err_value = err_type, err_value
@@ -396,9 +401,18 @@
         self.closed = 0
         ThreadedAsync.register_loop_callback(self.set_async)
 
+    def __repr__(self):
+        return "<%s for %s>" % (self.__class__.__name__, self.addr)
+
     def close(self):
         """Prevent ConnectionManager from opening new connections"""
         self.closed = 1
+        self._connect_lock.acquire()
+        try:
+            if self._thread is not None:
+                self._thread.join()
+        finally:
+            self._connect_lock.release()
 
     def register_object(self, obj):
         self.obj = obj
@@ -419,7 +433,7 @@
                 self._thread.start()
         finally:
             self._connect_lock.release()
-        if sync:
+        if sync and self._thread is not None:
             self._thread.join()
 
     def attempt_connect(self):
@@ -427,9 +441,16 @@
         return self.connected
 
     def __connect(self, repeat=1):
+        """Attempt to connect to StorageServer.
+
+        This method should always be called by attempt_connect() or by
+        connect().
+        """
+        
         tries = 0
         t = self.tmin
-        while not self.connected and (repeat or (tries == 0)):
+        while not (self.connected or self.closed) \
+              and (repeat or (tries == 0)):
             tries = tries + 1
             log("Trying to connect to server")
             try:
@@ -448,11 +469,11 @@
                 if self.debug:
                     log("Connected to server", level=zeolog.DEBUG)
                 self.connected = 1
-        if self.connected:
+        if self.connected and not self.closed:
             c = ManagedConnection(s, self.addr, self.obj, self)
             log("Connection created: %s" % c)
             self.obj.notifyConnected(c)
-        self.__thread = None
+        self._thread = None
 
     def _wait(self, t):
         time.sleep(t)