66"""
77from kazoo .exceptions import BadVersionError
88from kazoo .retry import ForceRetryError
9-
9+ import struct
1010
1111class Counter (object ):
1212 """Kazoo Counter
@@ -19,6 +19,12 @@ class Counter(object):
1919 `type(counter.default)(value)` both using an ascii encoding. As
2020 such other data types might be used for the counter value.
2121
22+ If you would like to support clients updating the same znode path using
23+ either kazoo's counter recipe or curator's SharedCount recipe, you will
24+ need to enable the support_curator flag. This flag limits
25+ support to integers only and does not use ascii encoding as described
26+ above.
27+
2228 Counter changes can raise
2329 :class:`~kazoo.exceptions.BadVersionError` if the retry policy
2430 wasn't able to apply a change.
@@ -42,22 +48,35 @@ class Counter(object):
4248 counter.pre_value == 1.0
4349 counter.post_value == 3.0
4450
51+ counter = zk.Counter("/curator", support_curator=True)
52+ counter += 2
53+ counter -= 1
54+ counter.value == 1
55+ counter.pre_value == 2
56+ counter.post_value == 1
57+
4558 """
46- def __init__ (self , client , path , default = 0 ):
59+ def __init__ (self , client , path , default = 0 , support_curator = False ):
4760 """Create a Kazoo Counter
4861
4962 :param client: A :class:`~kazoo.client.KazooClient` instance.
5063 :param path: The counter path to use.
51- :param default: The default value.
64+ :param default: The default value to use for new counter paths.
65+ :param support_curator: Enable if support for curator's SharedCount
66+ recipe is desired.
5267
5368 """
5469 self .client = client
5570 self .path = path
5671 self .default = default
5772 self .default_type = type (default )
73+ self .support_curator = support_curator
5874 self ._ensured_path = False
5975 self .pre_value = None
6076 self .post_value = None
77+ if self .support_curator and not isinstance (self .default , int ):
78+ raise TypeError ("when support_curator is enabled the default "
79+ "type must be an int" )
6180
6281 def _ensure_node (self ):
6382 if not self ._ensured_path :
@@ -68,7 +87,10 @@ def _ensure_node(self):
6887 def _value (self ):
6988 self ._ensure_node ()
7089 old , stat = self .client .get (self .path )
71- old = old .decode ('ascii' ) if old != b'' else self .default
90+ if self .support_curator :
91+ old = struct .unpack (">i" , old )[0 ] if old != b'' else self .default
92+ else :
93+ old = old .decode ('ascii' ) if old != b'' else self .default
7294 version = stat .version
7395 data = self .default_type (old )
7496 return data , version
@@ -86,7 +108,10 @@ def _change(self, value):
86108 def _inner_change (self , value ):
87109 self .pre_value , version = self ._value ()
88110 post_value = self .pre_value + value
89- data = repr (post_value ).encode ('ascii' )
111+ if self .support_curator :
112+ data = struct .pack (">i" , post_value )
113+ else :
114+ data = repr (post_value ).encode ('ascii' )
90115 try :
91116 self .client .set (self .path , data , version = version )
92117 except BadVersionError : # pragma: nocover
0 commit comments