@@ -229,34 +229,91 @@ type PreviousGTIDsEvent struct {
229229 GTIDSets string
230230}
231231
232+ type GtidFormat int
233+
234+ const (
235+ GtidFormatClassic = iota
236+ GtidFormatTagged
237+ )
238+
239+ // Decode the number of sids (source identifiers) and if it is using
240+ // tagged GTIDs or classic (non-tagged) GTIDs.
241+ //
242+ // Note that each gtid tag increases the sidno here, so a single UUID
243+ // might turn up multiple times if there are multipl tags.
244+ //
245+ // see also:
246+ // decode_nsids_format in mysql/mysql-server
247+ // https://github.com/mysql/mysql-server/blob/61a3a1d8ef15512396b4c2af46e922a19bf2b174/sql/rpl_gtid_set.cc#L1363-L1378
248+ func decodeSid (data []byte ) (format GtidFormat , sidnr uint64 ) {
249+ if data [7 ] == 1 {
250+ format = GtidFormatTagged
251+ }
252+
253+ if format == GtidFormatTagged {
254+ masked := make ([]byte , 8 )
255+ copy (masked , data [1 :7 ])
256+ sidnr = binary .LittleEndian .Uint64 (masked )
257+ return
258+ }
259+ sidnr = binary .LittleEndian .Uint64 (data [:8 ])
260+ return
261+ }
262+
232263func (e * PreviousGTIDsEvent ) Decode (data []byte ) error {
233264 pos := 0
234- uuidCount := binary .LittleEndian .Uint16 (data [pos : pos + 8 ])
265+
266+ format , uuidCount := decodeSid (data )
235267 pos += 8
236268
237269 previousGTIDSets := make ([]string , uuidCount )
238- for i := range previousGTIDSets {
270+
271+ currentSetnr := 0
272+ var buf strings.Builder
273+ for range previousGTIDSets {
239274 uuid := e .decodeUuid (data [pos : pos + 16 ])
240275 pos += 16
276+ var tag string
277+ if format == GtidFormatTagged {
278+ tagLength := int (data [pos ]) / 2
279+ pos += 1
280+ if tagLength > 0 { // 0 == no tag, >0 == tag
281+ tag = string (data [pos : pos + tagLength ])
282+ pos += tagLength
283+ }
284+ }
285+
286+ if len (tag ) > 0 {
287+ buf .WriteString (":" )
288+ buf .WriteString (tag )
289+ } else {
290+ if currentSetnr != 0 {
291+ buf .WriteString ("," )
292+ }
293+ buf .WriteString (uuid )
294+ currentSetnr += 1
295+ }
296+
241297 sliceCount := binary .LittleEndian .Uint16 (data [pos : pos + 8 ])
242298 pos += 8
243- intervals := make ([]string , sliceCount )
244- for i := range intervals {
299+ for range sliceCount {
300+ buf .WriteString (":" )
301+
245302 start := e .decodeInterval (data [pos : pos + 8 ])
246303 pos += 8
247304 stop := e .decodeInterval (data [pos : pos + 8 ])
248305 pos += 8
249- interval := ""
250306 if stop == start + 1 {
251- interval = fmt .Sprintf ( "%d" , start )
307+ fmt .Fprintf ( & buf , "%d" , start )
252308 } else {
253- interval = fmt .Sprintf ( "%d-%d" , start , stop - 1 )
309+ fmt .Fprintf ( & buf , "%d-%d" , start , stop - 1 )
254310 }
255- intervals [i ] = interval
256311 }
257- previousGTIDSets [i ] = fmt .Sprintf ("%s:%s" , uuid , strings .Join (intervals , ":" ))
312+ if len (tag ) == 0 {
313+ currentSetnr += 1
314+ }
258315 }
259- e .GTIDSets = strings . Join ( previousGTIDSets , "," )
316+ e .GTIDSets = buf . String ( )
260317 return nil
261318}
262319
0 commit comments