4343from collections import defaultdict , OrderedDict
4444import random
4545import re
46+ from itertools import chain
4647from typing import Dict , Iterable , List , Optional , Tuple , Type , Union
4748
4849from .api .binary import get_binary_type , put_binary_type
5758 BinaryTypeError , CacheError , ReconnectError , SQLError , connection_errors ,
5859)
5960from .utils import (
60- capitalize , entity_id , schema_id , process_delimiter , select_version ,
61+ capitalize , entity_id , schema_id , process_delimiter ,
6162 status_to_exception , is_iterable ,
6263)
6364from .binary import GenericObjectMeta
@@ -131,7 +132,14 @@ def get_protocol_version(self) -> Optional[Tuple]:
131132
132133 @property
133134 def partition_aware (self ):
134- return self ._partition_aware
135+ return self ._partition_aware and self .partition_awareness_supported_by_protocol
136+
137+ @property
138+ def partition_awareness_supported_by_protocol (self ):
139+ # TODO: Need to re-factor this. I believe, we need separate class or
140+ # set of functions to work with protocol versions without manually
141+ # comparing versions with just some random tuples
142+ return self .protocol_version is not None and self .protocol_version >= (1 , 4 , 0 )
135143
136144 def connect (self , * args ):
137145 """
@@ -158,23 +166,20 @@ def connect(self, *args):
158166 # the following code is quite twisted, because the protocol version
159167 # is initially unknown
160168
161- # TODO: open first node in foregroung , others − in background
169+ # TODO: open first node in foreground , others − in background
162170 for i , node in enumerate (nodes ):
163171 host , port = node
164172 conn = Connection (self , ** self ._connection_args )
165173 conn .host = host
166174 conn .port = port
167175
168176 try :
169- if (
170- self .protocol_version is None
171- or self .protocol_version >= (1 , 4 , 0 )
172- ):
177+ if self .protocol_version is None or self .partition_aware :
173178 # open connection before adding to the pool
174179 conn .connect (host , port )
175180
176181 # now we have the protocol version
177- if self .protocol_version < ( 1 , 4 , 0 ) :
182+ if not self .partition_aware :
178183 # do not try to open more nodes
179184 self ._current_node = i
180185 else :
@@ -186,10 +191,7 @@ def connect(self, *args):
186191
187192 except connection_errors :
188193 conn ._fail ()
189- if (
190- self .protocol_version
191- and self .protocol_version >= (1 , 4 , 0 )
192- ):
194+ if self .partition_aware :
193195 # schedule the reconnection
194196 conn .reconnect ()
195197
@@ -204,7 +206,6 @@ def close(self):
204206 self ._nodes .clear ()
205207
206208 @property
207- @select_version
208209 def random_node (self ) -> Connection :
209210 """
210211 Returns random usable node.
@@ -213,46 +214,44 @@ def random_node(self) -> Connection:
213214 extend the `pygridgain` capabilities (with additional testing,
214215 logging, examining connections, et c.) you probably should not use it.
215216 """
216- try :
217- return random .choice (
218- list (n for n in self ._nodes if n .alive )
219- )
220- except IndexError :
221- # cannot choose from an empty sequence
222- raise ReconnectError ('Can not reconnect: out of nodes.' ) from None
223-
224- def random_node_130 (self ):
225- # it actually returns the next usable node, but the name stands for
226- # the code unification reason
227- node = self ._nodes [self ._current_node ]
228- if node .alive :
229- return node
230-
231- # close current (supposedly failed) node
232- self ._nodes [self ._current_node ].close ()
233-
234- # advance the node index
235- self ._current_node += 1
236- if self ._current_node >= len (self ._nodes ):
237- self ._current_node = 0
238-
239- # prepare the list of node indexes to try to connect to
240- seq = list (range (len (self ._nodes )))
241- seq = seq [self ._current_node :] + seq [:self ._current_node ]
242-
243- for i in seq :
244- node = self ._nodes [i ]
217+ if self .partition_aware :
218+ # if partition awareness is used just pick a random connected node
245219 try :
246- node .connect (node .host , node .port )
247- except connection_errors :
248- pass
249- else :
220+ return random .choice (
221+ list (n for n in self ._nodes if n .alive )
222+ )
223+ except IndexError :
224+ # cannot choose from an empty sequence
225+ raise ReconnectError ('Can not reconnect: out of nodes.' ) from None
226+ else :
227+ # if partition awareness is not used then just return the current
228+ # node if it's alive or the next usable node if connection with the
229+ # current is broken
230+ node = self ._nodes [self ._current_node ]
231+ if node .alive :
250232 return node
251233
252- # no nodes left
253- raise ReconnectError ('Can not reconnect: out of nodes.' )
254-
255- random_node_120 = random_node_130
234+ # close current (supposedly failed) node
235+ self ._nodes [self ._current_node ].close ()
236+
237+ # advance the node index
238+ self ._current_node += 1
239+ if self ._current_node >= len (self ._nodes ):
240+ self ._current_node = 0
241+
242+ # prepare the list of node indexes to try to connect to
243+ num_nodes = len (self ._nodes )
244+ for i in chain (range (self ._current_node , num_nodes ), range (self ._current_node )):
245+ node = self ._nodes [i ]
246+ try :
247+ node .connect (node .host , node .port )
248+ except connection_errors :
249+ pass
250+ else :
251+ return node
252+
253+ # no nodes left
254+ raise ReconnectError ('Can not reconnect: out of nodes.' )
256255
257256 @status_to_exception (BinaryTypeError )
258257 def get_binary_type (self , binary_type : Union [str , int ]) -> dict :
0 commit comments