1515
1616"""
1717import sys
18+
1819try :
1920 from time import monotonic as now
2021except ImportError :
2728 CancelledError ,
2829 KazooException ,
2930 LockTimeout ,
30- NoNodeError
31+ NoNodeError ,
3132)
3233from kazoo .protocol .states import KazooState
3334from kazoo .retry import (
3435 ForceRetryError ,
3536 KazooRetry ,
36- RetryFailedError
37+ RetryFailedError ,
3738)
3839
3940
@@ -80,20 +81,33 @@ class Lock(object):
8081
8182 # Node names which exclude this contender when present at a lower
8283 # sequence number. Involved in read/write locks.
83- _EXCLUDE_NAMES = ["__lock__" , "-lock-" ]
84+ _EXCLUDE_NAMES = ["__lock__" ]
8485
85- def __init__ (self , client , path , identifier = None ):
86+ def __init__ (
87+ self , client , path , identifier = None , additional_lock_patterns = ()
88+ ):
8689 """Create a Kazoo lock.
8790
8891 :param client: A :class:`~kazoo.client.KazooClient` instance.
8992 :param path: The lock path to use.
90- :param identifier: Name to use for this lock contender. This
91- can be useful for querying to see who the
92- current lock contenders are.
93-
93+ :param identifier: Name to use for this lock contender. This can be
94+ useful for querying to see who the current lock
95+ contenders are.
96+ :param additional_lock_patterns: Strings that will be used to
97+ identify other znode in the path
98+ that should be considered contenders
99+ for this lock.
100+ Use this for cross-implementation
101+ compatibility.
102+
103+ .. versionadded:: 2.7.1
104+ The additional_lock_patterns option.
94105 """
95106 self .client = client
96107 self .path = path
108+ self ._exclude_names = set (
109+ self ._EXCLUDE_NAMES + list (additional_lock_patterns )
110+ )
97111
98112 # some data is written to the node. this can be queried via
99113 # contenders() to see who is contending for the lock
@@ -113,8 +127,9 @@ def __init__(self, client, path, identifier=None):
113127 self .is_acquired = False
114128 self .assured_path = False
115129 self .cancelled = False
116- self ._retry = KazooRetry (max_tries = None ,
117- sleep_func = client .handler .sleep_func )
130+ self ._retry = KazooRetry (
131+ max_tries = None , sleep_func = client .handler .sleep_func
132+ )
118133 self ._lock = client .handler .lock_object ()
119134
120135 def _ensure_path (self ):
@@ -179,9 +194,12 @@ def _acquire_lock():
179194 try :
180195 gotten = False
181196 try :
182- gotten = retry (self ._inner_acquire ,
183- blocking = blocking , timeout = timeout ,
184- ephemeral = ephemeral )
197+ gotten = retry (
198+ self ._inner_acquire ,
199+ blocking = blocking ,
200+ timeout = timeout ,
201+ ephemeral = ephemeral ,
202+ )
185203 except RetryFailedError :
186204 pass
187205 except KazooException :
@@ -222,8 +240,9 @@ def _inner_acquire(self, blocking, timeout, ephemeral=True):
222240 self .create_tried = True
223241
224242 if not node :
225- node = self .client .create (self .create_path , self .data ,
226- ephemeral = ephemeral , sequence = True )
243+ node = self .client .create (
244+ self .create_path , self .data , ephemeral = ephemeral , sequence = True
245+ )
227246 # strip off path to node
228247 node = node [len (self .path ) + 1 :]
229248
@@ -263,14 +282,16 @@ def _inner_acquire(self, blocking, timeout, ephemeral=True):
263282 else :
264283 self .wake_event .wait (timeout )
265284 if not self .wake_event .isSet ():
266- raise LockTimeout ("Failed to acquire lock on %s after "
267- "%s seconds" % (self .path , timeout ))
285+ raise LockTimeout (
286+ "Failed to acquire lock on %s after %s seconds"
287+ % (self .path , timeout )
288+ )
268289 finally :
269290 self .client .remove_listener (self ._watch_session )
270291
271292 def predecessor (self , children , index ):
272293 for c in reversed (children [:index ]):
273- if any (n in c for n in self ._EXCLUDE_NAMES ):
294+ if any (n in c for n in self ._exclude_names ):
274295 return c
275296 return None
276297
@@ -289,12 +310,13 @@ def _get_sorted_children(self):
289310 # (eg. in case of a lease), just sort them last ('~' sorts after all
290311 # ASCII digits).
291312 def _seq (c ):
292- for name in [ "__lock__" , "-lock-" , "__rlock__" ] :
313+ for name in self . _exclude_names :
293314 idx = c .find (name )
294315 if idx != - 1 :
295316 return c [idx + len (name ):]
296317 # Sort unknown node names eg. "lease_holder" last.
297318 return '~'
319+
298320 children .sort (key = _seq )
299321 return children
300322
@@ -391,8 +413,9 @@ class WriteLock(Lock):
391413 shared lock.
392414
393415 """
416+
394417 _NODE_NAME = "__lock__"
395- _EXCLUDE_NAMES = ["__lock__" , "-lock-" , " __rlock__" ]
418+ _EXCLUDE_NAMES = ["__lock__" , "__rlock__" ]
396419
397420
398421class ReadLock (Lock ):
@@ -420,8 +443,9 @@ class ReadLock(Lock):
420443 shared lock.
421444
422445 """
446+
423447 _NODE_NAME = "__rlock__"
424- _EXCLUDE_NAMES = ["__lock__" , "-lock-" ]
448+ _EXCLUDE_NAMES = ["__lock__" ]
425449
426450
427451class Semaphore (object ):
@@ -458,6 +482,7 @@ class Semaphore(object):
458482 The max_leases check.
459483
460484 """
485+
461486 def __init__ (self , client , path , identifier = None , max_leases = 1 ):
462487 """Create a Kazoo Lock
463488
@@ -509,8 +534,8 @@ def _ensure_path(self):
509534 else :
510535 if leases != self .max_leases :
511536 raise ValueError (
512- "Inconsistent max leases: %s, expected: %s" %
513- (leases , self .max_leases )
537+ "Inconsistent max leases: %s, expected: %s"
538+ % (leases , self .max_leases )
514539 )
515540 else :
516541 self .client .set (self .path , str (self .max_leases ).encode ('utf-8' ))
@@ -548,7 +573,8 @@ def acquire(self, blocking=True, timeout=None):
548573
549574 try :
550575 self .is_acquired = self .client .retry (
551- self ._inner_acquire , blocking = blocking , timeout = timeout )
576+ self ._inner_acquire , blocking = blocking , timeout = timeout
577+ )
552578 except KazooException :
553579 # if we did ultimately fail, attempt to clean up
554580 self ._best_effort_cleanup ()
@@ -590,8 +616,9 @@ def _inner_acquire(self, blocking, timeout=None):
590616 self .wake_event .wait (w .leftover ())
591617 if not self .wake_event .isSet ():
592618 raise LockTimeout (
593- "Failed to acquire semaphore on %s "
594- "after %s seconds" % (self .path , timeout ))
619+ "Failed to acquire semaphore on %s"
620+ " after %s seconds" % (self .path , timeout )
621+ )
595622 else :
596623 return False
597624 finally :
@@ -612,8 +639,9 @@ def _get_lease(self, data=None):
612639 # Get a list of the current potential lock holders. If they change,
613640 # notify our wake_event object. This is used to unblock a blocking
614641 # self._inner_acquire call.
615- children = self .client .get_children (self .path ,
616- self ._watch_lease_change )
642+ children = self .client .get_children (
643+ self .path , self ._watch_lease_change
644+ )
617645
618646 # If there are leases available, acquire one
619647 if len (children ) < self .max_leases :
0 commit comments