[Zodb-checkins] CVS: Packages/ZEO - zrpc.py:1.13

Jim Fulton jim@digicool.com
Tue, 27 Mar 2001 18:43:33 -0500 (EST)


Update of /cvs-repository/Packages/ZEO
In directory korak:/tmp/cvs-serv13952

Modified Files:
	zrpc.py 
Log Message:
It is no longer necessary to symbolically link cPickle or
ZServer. ZServer is no longer necessary at all.

Fixed a race condition in __call__.

If an exception raised on the server which could not be
unpickled on the client could cause the client connection to
fail. 



--- Updated File zrpc.py in package Packages/ZEO --
--- zrpc.py	2001/02/23 17:57:50	1.12
+++ zrpc.py	2001/03/27 23:43:32	1.13
@@ -87,8 +87,8 @@
 
 __version__ = "$Revision$"[11:-2]
 
-from ZODB.cPickle import loads
-from ZODB import cPickle
+from cPickle import loads
+import cPickle
 from thread import allocate_lock
 from smac import SizedMessageAsyncConnection
 import socket, string, struct, asyncore, sys, time, select
@@ -102,6 +102,9 @@
 pickler.fast=1 # Don't use the memo
 dump=pickler.dump
 
+class UnUnPickleableError(Exception):
+    "Couldn't unpickle a remote exception"
+
 class asyncRPC(SizedMessageAsyncConnection):
 
     __map=0
@@ -119,6 +122,10 @@
         self.__r=None
         l.acquire()
 
+        l=allocate_lock() # Response lock used to wait for call results
+        self.__call_la=l.acquire
+        self.__call_lr=l.release
+
     def connect(self, tryonce=1, log_type='client'):
         t=self._tmin
         connection = self._connection
@@ -152,7 +159,7 @@
                 return 1
 
     def finishConnect(self, s):
-        SizedMessageAsyncConnection.__init__(self, s, s.getpeername(), {})
+        SizedMessageAsyncConnection.__init__(self, s, '', {})
 
     # we are our own socket map!
     def keys(self): return (self._fileno,)
@@ -190,30 +197,37 @@
 
          
     def __call__(self, *args):
-        args=dump(args,1)
-        self.message_output(args)
-
-        if self.__map: self.__Wakeup() # You dumb bastard
-        else: self.readLoop()
-
-        while 1:
-            r=self._read()
-            c=r[:1]
-            if c=='R':
-                if r=='RN.': return None # Common case!
-                return loads(r[1:])
-            if c=='E':
-                r=loads(r[1:])
-                if type(r) is TupleType: raise r[0], r[1]
-                raise r
-            oob=self._outOfBand
-            if oob is not None:
-                r=r[1:]
-                if r=='N.': r=None # Common case!
-                else: r=loads(r)
-                oob(c, r)
-            else:
-                raise UnrecognizedResult, r
+        self.__call_la()
+        try:
+            self._last_args=args=dump(args,1)
+            self.message_output(args)
+
+            if self.__map: self.__Wakeup() # You dumb bastard
+            else: self.readLoop()
+
+            while 1:
+                r=self._read()
+                c=r[:1]
+                if c=='R':
+                    if r=='RN.': return None # Common case!
+                    return loads(r[1:])
+                if c=='E':
+                    try: r=loads(r[1:])
+                    except:
+                        raise UnUnPickleableError(r[1:])
+                    if type(r) is TupleType: raise r[0], r[1]
+                    raise r
+                oob=self._outOfBand
+                if oob is not None:
+                    r=r[1:]
+                    if r=='N.': r=None # Common case!
+                    else: r=loads(r)
+                    oob(c, r)
+                else:
+                    raise UnrecognizedResult, r
+        finally:
+            self._last_args=''
+            self.__call_lr()
 
     def sendMessage(self, *args):
         self.message_output(dump(args,1))