@@ -77,10 +77,11 @@ def __init__(self, host, port,
77
77
else :
78
78
self .schema = Schema (schema )
79
79
self ._socket = None
80
+ self .connected = False
80
81
if connect_now :
81
82
self .connect ()
82
83
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 )
84
85
self ._recv = self ._recv_type (self ._libc .recv )
85
86
86
87
def close (self ):
@@ -101,6 +102,7 @@ def connect(self):
101
102
102
103
try :
103
104
# If old socket already exists - close it and re-create
105
+ self .connected = True
104
106
if self ._socket :
105
107
self ._socket .close ()
106
108
self ._socket = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
@@ -110,6 +112,7 @@ def connect(self):
110
112
# Otherwise the timeout exception will rised, even if the server does not listen
111
113
self ._socket .settimeout (self .socket_timeout )
112
114
except socket .error as e :
115
+ self .connected = False
113
116
raise NetworkError (e )
114
117
115
118
def _read_response (self ):
@@ -157,19 +160,33 @@ def _send_request_wo_reconnect(self, request, space_name = None, field_defs = No
157
160
raise DatabaseError (response .return_code , response .return_message )
158
161
159
162
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
+
160
174
attempt = 0
175
+ last_errno = 0
161
176
if not self ._socket :
162
177
self .connect ()
163
178
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 :
167
181
break
168
182
time .sleep (self .reconnect_delay )
169
- self .connect ()
183
+ try :
184
+ self .connect ()
185
+ except NetworkError as e :
186
+ last_errno = e .errno
170
187
warn ("Reconnect attempt %d of %d" % (attempt , self .reconnect_max_attempts ), NetworkWarning )
171
188
if attempt == self .reconnect_max_attempts :
172
- raise
189
+ raise socket . error (( last_errno , errno . errorcode [ last_errno ]))
173
190
attempt += 1
174
191
175
192
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):
247
264
:type values: tuple
248
265
:param return_tuple: True indicates that it is required to return the inserted tuple back
249
266
:type return_tuple: bool
250
-
267
+
251
268
:rtype: `Response` instance
252
269
'''
253
270
if return_tuple is None :
@@ -399,7 +416,7 @@ def select(self, space_name, values=None, **kwargs):
399
416
:type limit: int
400
417
401
418
:rtype: `Response` instance
402
-
419
+
403
420
Select one single record (from space=0 and using index=0)
404
421
>>> select(0, 0, 1)
405
422
0 commit comments