[Zodb-checkins] CVS: ZODB3/ZEO/zrpc - client.py:1.9

Guido van Rossum guido@python.org
Thu, 12 Sep 2002 00:02:19 -0400


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

Modified Files:
	client.py 
Log Message:
A bunch of renamings and other small changes to make the code a little
more understandable.

Got rid of the Connected() exception -- connect(), now renamed to
try_connect(), returns a 1/0 result instead of raising Connected() to
indicate success.


=== ZODB3/ZEO/zrpc/client.py 1.8 => 1.9 ===
--- ZODB3/ZEO/zrpc/client.py:1.8	Wed Sep 11 15:20:50 2002
+++ ZODB3/ZEO/zrpc/client.py	Thu Sep 12 00:02:18 2002
@@ -29,8 +29,8 @@
 class ConnectionManager:
     """Keeps a connection up over time"""
 
-    def __init__(self, addr, client, tmin=1, tmax=180):
-        self.set_addr(addr)
+    def __init__(self, addrs, client, tmin=1, tmax=180):
+        self.addrlist = self._parse_addrs(addrs)
         self.client = client
         self.tmin = tmin
         self.tmax = tmax
@@ -46,26 +46,27 @@
         ThreadedAsync.register_loop_callback(self.set_async)
 
     def __repr__(self):
-        return "<%s for %s>" % (self.__class__.__name__, self.addr)
+        return "<%s for %s>" % (self.__class__.__name__, self.addrlist)
 
-    def set_addr(self, addr):
-        "Set one or more addresses to use for server."
+    def _parse_addrs(self, addrs):
+        # Return a list of (addr_type, addr) pairs.
 
         # For backwards compatibility (and simplicity?) the
-        # constructor accepts a single address in the addr argument --
+        # constructor accepts a single address in the addrs argument --
         # a string for a Unix domain socket or a 2-tuple with a
         # hostname and port.  It can also accept a list of such addresses.
 
-        addr_type = self._guess_type(addr)
+        addr_type = self._guess_type(addrs)
         if addr_type is not None:
-            self.addr = [(addr_type, addr)]
+            return [(addr_type, addrs)]
         else:
-            self.addr = []
-            for a in addr:
-                addr_type = self._guess_type(a)
+            addrlist = []
+            for addr in addrs:
+                addr_type = self._guess_type(addr)
                 if addr_type is None:
                     raise ValueError, "unknown address in list: %s" % repr(a)
-                self.addr.append((addr_type, a))
+                addrlist.append((addr_type, addr))
+            return addrlist
 
     def _guess_type(self, addr):
         if isinstance(addr, types.StringType):
@@ -146,7 +147,8 @@
             t = self.thread
             if t is None:
                 log("starting thread to connect to server")
-                self.thread = t = ConnectThread(self, self.client, self.addr,
+                self.thread = t = ConnectThread(self, self.client,
+                                                self.addrlist,
                                                 self.tmin, self.tmax)
                 t.start()
         finally:
@@ -175,11 +177,6 @@
         if not self.closed:
             self.connect()
 
-class Connected(Exception):
-    # helper for non-local exit
-    def __init__(self, sock):
-        self.sock = sock
-
 # When trying to do a connect on a non-blocking socket, some outcomes
 # are expected.  Set _CONNECT_IN_PROGRESS to the errno value(s) expected
 # when an initial connect can't complete immediately.  Set _CONNECT_OK
@@ -209,11 +206,11 @@
     # We don't expect clients to call any methods of this Thread other
     # than close() and those defined by the Thread API.
 
-    def __init__(self, mgr, client, addrs, tmin, tmax):
-        self.__super_init(name="Connect(%s)" % addrs)
+    def __init__(self, mgr, client, addrlist, tmin, tmax):
+        self.__super_init(name="Connect(%s)" % addrlist)
         self.mgr = mgr
         self.client = client
-        self.addrs = addrs
+        self.addrlist = addrlist
         self.tmin = tmin
         self.tmax = tmax
         self.stopped = 0
@@ -248,7 +245,7 @@
             s.close()
 
     def attempt_connects(self):
-        """Try connecting to all self.addrs addresses.
+        """Try connecting to all self.addrlist addresses.
 
         If at least one succeeds, pick a success arbitrarily, close all other
         successes (if any), and return true.  If none succeed, return false.
@@ -256,49 +253,50 @@
 
         self.sockets = {}  # {open socket:  connection address}
 
-        log("attempting connection on %d sockets" % len(self.addrs))
-        try:
-            for domain, addr in self.addrs:
-                if __debug__:
-                    log("attempt connection to %s" % repr(addr),
-                        level=zLOG.DEBUG)
-                try:
-                    s = socket.socket(domain, socket.SOCK_STREAM)
-                except socket.error, err:
-                    log("Failed to create socket with domain=%s: %s" % (
-                        domain, err), level=zLOG.ERROR)
-                    continue
-                s.setblocking(0)
-                self.sockets[s] = addr
-                # connect() raises Connected iff it succeeds
-                # XXX can still block for a while if addr requires DNS
-                self.connect(s)
-
-            # next wait until they actually connect
-            while self.sockets:
-                if self.stopped:
-                    self.close_sockets()
-                    return 0
-                try:
-                    sockets = self.sockets.keys()
-                    r, w, x = select.select([], sockets, sockets, 1.0)
-                except select.error:
-                    continue
-                for s in x:
-                    del self.sockets[s]
-                    s.close()
-                for s in w:
-                    # connect() raises Connected iff it succeeds
-                    self.connect(s)
-        except Connected, container:
-            s = container.sock
+        log("attempting connection on %d sockets" % len(self.addrlist))
+        ok = 0
+        for domain, addr in self.addrlist:
+            if __debug__:
+                log("attempt connection to %s" % repr(addr),
+                    level=zLOG.DEBUG)
+            try:
+                s = socket.socket(domain, socket.SOCK_STREAM)
+            except socket.error, err:
+                log("Failed to create socket with domain=%s: %s" % (
+                    domain, err), level=zLOG.ERROR)
+                continue
+            s.setblocking(0)
+            self.sockets[s] = addr
+            # XXX can still block for a while if addr requires DNS
+            if self.try_connect(s):
+                ok = 1
+                break
+
+        # next wait until they actually connect
+        while not ok and self.sockets:
+            if self.stopped:
+                self.close_sockets()
+                return 0
+            try:
+                sockets = self.sockets.keys()
+                r, w, x = select.select([], sockets, sockets, 1.0)
+            except select.error:
+                continue
+            for s in x:
+                del self.sockets[s]
+                s.close()
+            for s in w:
+                if self.try_connect(s):
+                    ok = 1
+                    break
+
+        if ok:
             del self.sockets[s] # don't close the newly connected socket
             self.close_sockets()
-            return 1
-        return 0
+        return ok
 
-    def connect(self, s):
-        """Call s.connect_ex(addr); raise Connected iff connection succeeds.
+    def try_connect(self, s):
+        """Call s.connect_ex(addr); return true iff connection succeeds.
 
         We have to handle several possible return values from
         connect_ex().  If the socket is connected and the initial ZEO
@@ -323,13 +321,13 @@
         else:
             log("connect_ex(%s) == %s" % (addr, e))
             if e in _CONNECT_IN_PROGRESS:
-                return
+                return 0
             elif e in _CONNECT_OK:
                 # special cases to deal with winsock oddities
                 if sys.platform.startswith("win") and e == 0:
 
                     # It appears that winsock isn't behaving as
-                    # expected on Win2k.  It's possible for connect()
+                    # expected on Win2k.  It's possible for connect_ex()
                     # to return 0, but the connection to have failed.
                     # In particular, in situations where I expect to
                     # get a Connection refused (10061), I'm seeing
@@ -339,7 +337,7 @@
 
                     r, w, x = select.select([s], [s], [s], 0.1)
                     if not (r or w or x):
-                        return
+                        return 0
                     if x:
                         # see comment at the end of the function
                         s.close()
@@ -347,7 +345,7 @@
                 c = self.test_connection(s, addr)
                 if c:
                     log("connected to %s" % repr(addr), level=zLOG.DEBUG)
-                    raise Connected(s)
+                    return 1
             else:
                 log("error connecting to %s: %s" % (addr, errno.errorcode[e]),
                     level=zLOG.DEBUG)
@@ -357,6 +355,7 @@
         # sockets.
         s.close()
         del self.sockets[s]
+        return 0
 
     def test_connection(self, s, addr):
         # Establish a connection at the zrpc level and call the