7
7
import time
8
8
import errno
9
9
import socket
10
+ import copy
10
11
try :
11
12
import ssl
12
13
is_ssl_supported = True
55
56
REQUEST_TYPE_ERROR ,
56
57
IPROTO_GREETING_SIZE ,
57
58
ITERATOR_EQ ,
58
- ITERATOR_ALL
59
+ ITERATOR_ALL ,
60
+ IPROTO_CHUNK
59
61
)
60
62
from tarantool .error import (
61
63
Error ,
@@ -151,55 +153,56 @@ def connect(self):
151
153
raise NotImplementedError
152
154
153
155
@abc .abstractmethod
154
- def call (self , func_name , * args ):
156
+ def call (self , func_name , * args , on_push = None , on_push_ctx = None ):
155
157
"""
156
158
Reference implementation: :meth:`~tarantool.Connection.call`.
157
159
"""
158
160
159
161
raise NotImplementedError
160
162
161
163
@abc .abstractmethod
162
- def eval (self , expr , * args ):
164
+ def eval (self , expr , * args , on_push = None , on_push_ctx = None ):
163
165
"""
164
166
Reference implementation: :meth:`~tarantool.Connection.eval`.
165
167
"""
166
168
167
169
raise NotImplementedError
168
170
169
171
@abc .abstractmethod
170
- def replace (self , space_name , values ):
172
+ def replace (self , space_name , values , on_push = None , on_push_ctx = None ):
171
173
"""
172
174
Reference implementation: :meth:`~tarantool.Connection.replace`.
173
175
"""
174
176
175
177
raise NotImplementedError
176
178
177
179
@abc .abstractmethod
178
- def insert (self , space_name , values ):
180
+ def insert (self , space_name , values , on_push = None , on_push_ctx = None ):
179
181
"""
180
182
Reference implementation: :meth:`~tarantool.Connection.insert`.
181
183
"""
182
184
183
185
raise NotImplementedError
184
186
185
187
@abc .abstractmethod
186
- def delete (self , space_name , key , * , index = None ):
188
+ def delete (self , space_name , key , * , index = None , on_push = None , on_push_ctx = None ):
187
189
"""
188
190
Reference implementation: :meth:`~tarantool.Connection.delete`.
189
191
"""
190
192
191
193
raise NotImplementedError
192
194
193
195
@abc .abstractmethod
194
- def upsert (self , space_name , tuple_value , op_list , * , index = None ):
196
+ def upsert (self , space_name , tuple_value , op_list , * , index = None ,
197
+ on_push = None , on_push_ctx = None ):
195
198
"""
196
199
Reference implementation: :meth:`~tarantool.Connection.upsert`.
197
200
"""
198
201
199
202
raise NotImplementedError
200
203
201
204
@abc .abstractmethod
202
- def update (self , space_name , key , op_list , * , index = None ):
205
+ def update (self , space_name , key , op_list , * , index = None , on_push = None , on_push_ctx = None ):
203
206
"""
204
207
Reference implementation: :meth:`~tarantool.Connection.update`.
205
208
"""
@@ -216,7 +219,7 @@ def ping(self, notime):
216
219
217
220
@abc .abstractmethod
218
221
def select (self , space_name , key , * , offset = None , limit = None ,
219
- index = None , iterator = None ):
222
+ index = None , iterator = None , on_push = None , on_push_ctx = None ):
220
223
"""
221
224
Reference implementation: :meth:`~tarantool.Connection.select`.
222
225
"""
@@ -748,7 +751,7 @@ def _read_response(self):
748
751
# Read the packet
749
752
return self ._recv (length )
750
753
751
- def _send_request_wo_reconnect (self , request ):
754
+ def _send_request_wo_reconnect (self , request , on_push = None , on_push_ctx = None ):
752
755
"""
753
756
Send request without trying to reconnect.
754
757
Reload schema, if required.
@@ -767,12 +770,30 @@ def _send_request_wo_reconnect(self, request):
767
770
768
771
assert isinstance (request , Request )
769
772
773
+ # Flag for detecting the last message as out-of-band.
774
+ iproto_chunk_detected = False
775
+
770
776
response = None
771
777
while True :
772
778
try :
773
- self ._socket .sendall (bytes (request ))
779
+ if not iproto_chunk_detected :
780
+ # If the last received message is out-of-band,
781
+ # the request will not be sent.
782
+ self ._socket .sendall (bytes (request ))
774
783
response = request .response_class (self , self ._read_response ())
775
- break
784
+ if response ._code == IPROTO_CHUNK :
785
+ # Сase of receiving an out-of-band message.
786
+ if callable (on_push ):
787
+ # Callback function with data from out-of-band
788
+ # message is being called.
789
+ # The callback result can be written to on_push_ctx.
790
+ on_push (response ._data , on_push_ctx )
791
+ iproto_chunk_detected = True
792
+ # Receiving the next message.
793
+ continue
794
+ else :
795
+ # Сase of receiving main message.
796
+ break
776
797
except SchemaReloadException as e :
777
798
self .update_schema (e .schema_version )
778
799
continue
@@ -851,7 +872,7 @@ def check(): # Check that connection is alive
851
872
self .wrap_socket_ssl ()
852
873
self .handshake ()
853
874
854
- def _send_request (self , request ):
875
+ def _send_request (self , request , on_push = None , on_push_ctx = None ):
855
876
"""
856
877
Send a request to the server through the socket.
857
878
@@ -872,7 +893,7 @@ def _send_request(self, request):
872
893
873
894
self ._opt_reconnect ()
874
895
875
- return self ._send_request_wo_reconnect (request )
896
+ return self ._send_request_wo_reconnect (request , on_push , on_push_ctx )
876
897
877
898
def load_schema (self ):
878
899
"""
@@ -914,7 +935,7 @@ def flush_schema(self):
914
935
self .schema .flush ()
915
936
self .load_schema ()
916
937
917
- def call (self , func_name , * args ):
938
+ def call (self , func_name , * args , on_push = None , on_push_ctx = None ):
918
939
"""
919
940
Execute a CALL request: call a stored Lua function.
920
941
@@ -930,6 +951,10 @@ def call(self, func_name, *args):
930
951
:exc:`~tarantool.error.SchemaError`,
931
952
:exc:`~tarantool.error.NetworkError`,
932
953
:exc:`~tarantool.error.SslError`
954
+
955
+ !!!
956
+ TODO: write docs
957
+ !!!
933
958
"""
934
959
935
960
assert isinstance (func_name , str )
@@ -939,10 +964,10 @@ def call(self, func_name, *args):
939
964
args = args [0 ]
940
965
941
966
request = RequestCall (self , func_name , args , self .call_16 )
942
- response = self ._send_request (request )
967
+ response = self ._send_request (request , on_push , on_push_ctx )
943
968
return response
944
969
945
- def eval (self , expr , * args ):
970
+ def eval (self , expr , * args , on_push = None , on_push_ctx = None ):
946
971
"""
947
972
Execute an EVAL request: evaluate a Lua expression.
948
973
@@ -968,10 +993,10 @@ def eval(self, expr, *args):
968
993
args = args [0 ]
969
994
970
995
request = RequestEval (self , expr , args )
971
- response = self ._send_request (request )
996
+ response = self ._send_request (request , on_push , on_push_ctx )
972
997
return response
973
998
974
- def replace (self , space_name , values ):
999
+ def replace (self , space_name , values , on_push = None , on_push_ctx = None ):
975
1000
"""
976
1001
Execute a REPLACE request: `replace`_ a tuple in the space.
977
1002
Doesn't throw an error if there is no tuple with the specified
@@ -997,7 +1022,7 @@ def replace(self, space_name, values):
997
1022
if isinstance (space_name , str ):
998
1023
space_name = self .schema .get_space (space_name ).sid
999
1024
request = RequestReplace (self , space_name , values )
1000
- return self ._send_request (request )
1025
+ return self ._send_request (request , on_push , on_push_ctx )
1001
1026
1002
1027
def authenticate (self , user , password ):
1003
1028
"""
@@ -1149,7 +1174,7 @@ def subscribe(self, cluster_uuid, server_uuid, vclock=None):
1149
1174
return
1150
1175
self .close () # close connection after SUBSCRIBE
1151
1176
1152
- def insert (self , space_name , values ):
1177
+ def insert (self , space_name , values , on_push = None , on_push_ctx = None ):
1153
1178
"""
1154
1179
Execute an INSERT request: `insert`_ a tuple to the space.
1155
1180
Throws an error if there is already a tuple with the same
@@ -1175,9 +1200,9 @@ def insert(self, space_name, values):
1175
1200
if isinstance (space_name , str ):
1176
1201
space_name = self .schema .get_space (space_name ).sid
1177
1202
request = RequestInsert (self , space_name , values )
1178
- return self ._send_request (request )
1203
+ return self ._send_request (request , on_push , on_push_ctx )
1179
1204
1180
- def delete (self , space_name , key , * , index = 0 ):
1205
+ def delete (self , space_name , key , * , index = 0 , on_push = None , on_push_ctx = None ):
1181
1206
"""
1182
1207
Execute a DELETE request: `delete`_ a tuple in the space.
1183
1208
@@ -1208,9 +1233,9 @@ def delete(self, space_name, key, *, index=0):
1208
1233
if isinstance (index , str ):
1209
1234
index = self .schema .get_index (space_name , index ).iid
1210
1235
request = RequestDelete (self , space_name , index , key )
1211
- return self ._send_request (request )
1236
+ return self ._send_request (request , on_push , on_push_ctx )
1212
1237
1213
- def upsert (self , space_name , tuple_value , op_list , * , index = 0 ):
1238
+ def upsert (self , space_name , tuple_value , op_list , * , index = 0 , on_push = None , on_push_ctx = None ):
1214
1239
"""
1215
1240
Execute an UPSERT request: `upsert`_ a tuple to the space.
1216
1241
@@ -1259,9 +1284,9 @@ def upsert(self, space_name, tuple_value, op_list, *, index=0):
1259
1284
op_list = self ._ops_process (space_name , op_list )
1260
1285
request = RequestUpsert (self , space_name , index , tuple_value ,
1261
1286
op_list )
1262
- return self ._send_request (request )
1287
+ return self ._send_request (request , on_push , on_push_ctx )
1263
1288
1264
- def update (self , space_name , key , op_list , * , index = 0 ):
1289
+ def update (self , space_name , key , op_list , * , index = 0 , on_push = None , on_push_ctx = None ):
1265
1290
"""
1266
1291
Execute an UPDATE request: `update`_ a tuple in the space.
1267
1292
@@ -1338,7 +1363,7 @@ def update(self, space_name, key, op_list, *, index=0):
1338
1363
index = self .schema .get_index (space_name , index ).iid
1339
1364
op_list = self ._ops_process (space_name , op_list )
1340
1365
request = RequestUpdate (self , space_name , index , key , op_list )
1341
- return self ._send_request (request )
1366
+ return self ._send_request (request , on_push , on_push_ctx )
1342
1367
1343
1368
def ping (self , notime = False ):
1344
1369
"""
@@ -1368,7 +1393,7 @@ def ping(self, notime=False):
1368
1393
return "Success"
1369
1394
return t1 - t0
1370
1395
1371
- def select (self , space_name , key = None , * , offset = 0 , limit = 0xffffffff , index = 0 , iterator = None ):
1396
+ def select (self , space_name , key = None , * , offset = 0 , limit = 0xffffffff , index = 0 , iterator = None , on_push = None , on_push_ctx = None ):
1372
1397
"""
1373
1398
Execute a SELECT request: `select`_ a tuple from the space.
1374
1399
@@ -1524,7 +1549,7 @@ def select(self, space_name, key=None, *, offset=0, limit=0xffffffff, index=0, i
1524
1549
index = self .schema .get_index (space_name , index ).iid
1525
1550
request = RequestSelect (self , space_name , index , key , offset ,
1526
1551
limit , iterator )
1527
- response = self ._send_request (request )
1552
+ response = self ._send_request (request , on_push , on_push_ctx )
1528
1553
return response
1529
1554
1530
1555
def space (self , space_name ):
0 commit comments