33import re
44import struct
55import binascii
6+ from io import BytesIO
67
78
89class Gtid (object ):
@@ -16,17 +17,18 @@ def parse_interval(interval):
1617 else :
1718 return (int (m .group (1 )), int (m .group (2 )))
1819
19-
2020 @staticmethod
2121 def parse (gtid ):
22- m = re .search ('^([0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12})((?::[0-9-]+)+)$' , gtid )
22+ m = re .search ('^([0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12})'
23+ '((?::[0-9-]+)+)$' , gtid )
2324 if not m :
2425 raise ValueError ('GTID format is incorrect: %r' % (gtid , ))
2526
2627 sid = m .group (1 )
2728 intervals = m .group (2 )
2829
29- intervals_parsed = [Gtid .parse_interval (x ) for x in intervals .split (':' )[1 :]]
30+ intervals_parsed = [Gtid .parse_interval (x )
31+ for x in intervals .split (':' )[1 :]]
3032
3133 return (sid , intervals_parsed )
3234
@@ -39,18 +41,18 @@ def __init__(self, gtid):
3941 def __str__ (self ):
4042 return '%s:%s' % (self .sid ,
4143 ':' .join (('%d-%s' % x ) if isinstance (x , tuple )
42- else str (x )
43- for x in self .intervals ))
44+ else str (x )
45+ for x in self .intervals ))
4446
4547 def __repr__ (self ):
4648 return '<Gtid "%s">' % self
4749
4850 @property
4951 def encoded_length (self ):
50- return (16 + # sid
51- 8 + # n_intervals
52- 2 * # stop/start
53- 8 * # stop/start mark encoded as int64
52+ return (16 + # sid
53+ 8 + # n_intervals
54+ 2 * # stop/start
55+ 8 * # stop/start mark encoded as int64
5456 len (self .intervals ))
5557
5658 def encode (self ):
@@ -79,25 +81,72 @@ def encode(self):
7981
8082 return buffer
8183
84+ @classmethod
85+ def decode (cls , payload ):
86+ assert isinstance (payload , BytesIO ), \
87+ 'payload is expected to be a BytesIO'
88+ sid = b''
89+ sid = sid + binascii .hexlify (payload .read (4 ))
90+ sid = sid + b'-'
91+ sid = sid + binascii .hexlify (payload .read (2 ))
92+ sid = sid + b'-'
93+ sid = sid + binascii .hexlify (payload .read (2 ))
94+ sid = sid + b'-'
95+ sid = sid + binascii .hexlify (payload .read (2 ))
96+ sid = sid + b'-'
97+ sid = sid + binascii .hexlify (payload .read (6 ))
98+
99+ (n_intervals ,) = struct .unpack ('<Q' , payload .read (8 ))
100+ intervals = []
101+ for i in range (0 , n_intervals ):
102+ start , end = struct .unpack ('<QQ' , payload .read (16 ))
103+ if end == start + 1 :
104+ intervals .append (start )
105+ else :
106+ intervals .append ((start , end ))
107+
108+ return cls ('%s:%s' % (sid .decode ('ascii' ), ':' .join ([
109+ '%d-%d' % x
110+ if isinstance (x , tuple )
111+ else '%d' % x
112+ for x in intervals ])))
113+
82114
83115class GtidSet (object ):
84116 def __init__ (self , gtid_set ):
117+ def _to_gtid (element ):
118+ if isinstance (element , Gtid ):
119+ return element
120+ return Gtid (element .strip (' \n ' ))
121+
85122 if not gtid_set :
86123 self .gtids = []
124+ elif isinstance (gtid_set , (list , set )):
125+ self .gtids = [_to_gtid (x ) for x in gtid_set ]
87126 else :
88127 self .gtids = [Gtid (x .strip (' \n ' )) for x in gtid_set .split (',' )]
89128
90129 def __str__ (self ):
91130 return ',' .join (str (x ) for x in self .gtids )
92131
93132 def __repr__ (self ):
94- return '<GtidSet "%s" ' % ',' . join ( repr ( x ) for x in self .gtids )
133+ return '<GtidSet %r> ' % self .gtids
95134
96135 @property
97136 def encoded_length (self ):
98- return (8 + # n_sids
137+ return (8 + # n_sids
99138 sum (x .encoded_length for x in self .gtids ))
100139
101140 def encoded (self ):
102141 return b'' + (struct .pack ('<Q' , len (self .gtids )) +
103- b'' .join (x .encode () for x in self .gtids ))
142+ b'' .join (x .encode () for x in self .gtids ))
143+
144+ encode = encoded
145+
146+ @classmethod
147+ def decode (cls , payload ):
148+ assert isinstance (payload , BytesIO ), \
149+ 'payload is expected to be a BytesIO'
150+ (n_sid ,) = struct .unpack ('<Q' , payload .read (8 ))
151+
152+ return cls ([Gtid .decode (payload ) for _ in range (0 , n_sid )])
0 commit comments