@@ -77,10 +77,11 @@ def __init__(self, host, port,
7777 else :
7878 self .schema = Schema (schema )
7979 self ._socket = None
80+ self .connected = False
8081 if connect_now :
8182 self .connect ()
8283 self ._libc = ctypes .CDLL (ctypes .util .find_library ('c' ), use_errno = True )
83- self ._recv_type = ctypes .CFUNCTYPE (ctypes .c_ssize_t , * [ ctypes .c_int , ctypes .c_void_p , ctypes .c_ssize_t , ctypes .c_int ] , use_errno = True )
84+ self ._recv_type = ctypes .CFUNCTYPE (ctypes .c_ssize_t , ctypes .c_int , ctypes .c_void_p , ctypes .c_ssize_t , ctypes .c_int , use_errno = True )
8485 self ._recv = self ._recv_type (self ._libc .recv )
8586
8687 def close (self ):
@@ -101,6 +102,7 @@ def connect(self):
101102
102103 try :
103104 # If old socket already exists - close it and re-create
105+ self .connected = True
104106 if self ._socket :
105107 self ._socket .close ()
106108 self ._socket = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
@@ -110,6 +112,7 @@ def connect(self):
110112 # Otherwise the timeout exception will rised, even if the server does not listen
111113 self ._socket .settimeout (self .socket_timeout )
112114 except socket .error as e :
115+ self .connected = False
113116 raise NetworkError (e )
114117
115118 def _read_response (self ):
@@ -157,19 +160,33 @@ def _send_request_wo_reconnect(self, request, space_name = None, field_defs = No
157160 raise DatabaseError (response .return_code , response .return_message )
158161
159162 def _opt_reconnect (self ):
163+ '''\
164+ Check that connection is alive using low-level recv from libc(ctypes)
165+ **Due to bug in python - timeout is internal python construction.
166+ '''
167+ def check (): # Check that connection is alive
168+ rc = self ._recv (self ._socket .fileno (), '' , 0 , socket .MSG_DONTWAIT )
169+ if ctypes .get_errno () == errno .EAGAIN :
170+ ctypes .set_errno (0 )
171+ return errno .EAGAIN
172+ return ctypes .get_errno ()
173+
160174 attempt = 0
175+ last_errno = 0
161176 if not self ._socket :
162177 self .connect ()
163178 while True :
164- rc = self ._recv (self ._socket .fileno (), '' , 0 , socket .MSG_DONTWAIT )
165- if ctypes .get_errno () == errno .EAGAIN :
166- ctypes .set_errno (0 )
179+ last_errno = check ()
180+ if self .connected and last_errno == errno .EAGAIN :
167181 break
168182 time .sleep (self .reconnect_delay )
169- self .connect ()
183+ try :
184+ self .connect ()
185+ except NetworkError as e :
186+ last_errno = e .errno
170187 warn ("Reconnect attempt %d of %d" % (attempt , self .reconnect_max_attempts ), NetworkWarning )
171188 if attempt == self .reconnect_max_attempts :
172- raise
189+ raise socket . error (( last_errno , errno . errorcode [ last_errno ]))
173190 attempt += 1
174191
175192 def _send_request (self , request , space_name = None , field_defs = None , default_type = None ):
@@ -247,7 +264,7 @@ def replace(self, space_name, values, return_tuple=None):
247264 :type values: tuple
248265 :param return_tuple: True indicates that it is required to return the inserted tuple back
249266 :type return_tuple: bool
250-
267+
251268 :rtype: `Response` instance
252269 '''
253270 if return_tuple is None :
@@ -399,7 +416,7 @@ def select(self, space_name, values=None, **kwargs):
399416 :type limit: int
400417
401418 :rtype: `Response` instance
402-
419+
403420 Select one single record (from space=0 and using index=0)
404421 >>> select(0, 0, 1)
405422
0 commit comments