Skip to content

Commit ae9811e

Browse files
author
ljluestc
committed
ParseUUIDSet
1 parent f53dd22 commit ae9811e

File tree

3 files changed

+482
-298
lines changed

3 files changed

+482
-298
lines changed

mysql/mysql_gtid.go

Lines changed: 69 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -207,31 +207,61 @@ type UUIDSet struct {
207207
Intervals IntervalSlice
208208
}
209209

210-
func ParseUUIDSet(str string) (*UUIDSet, error) {
211-
str = strings.TrimSpace(str)
212-
sep := strings.Split(str, ":")
213-
if len(sep) < 2 {
214-
return nil, errors.Errorf("invalid GTID format, must UUID:interval[:interval]")
215-
}
216-
217-
var err error
218-
s := new(UUIDSet)
219-
if s.SID, err = uuid.Parse(sep[0]); err != nil {
220-
return nil, errors.Trace(err)
221-
}
222-
223-
// Handle interval
224-
for i := 1; i < len(sep); i++ {
225-
if in, err := parseInterval(sep[i]); err != nil {
226-
return nil, errors.Trace(err)
227-
} else {
228-
s.Intervals = append(s.Intervals, in)
229-
}
230-
}
231-
232-
s.Intervals = s.Intervals.Normalize()
233-
234-
return s, nil
210+
// ParseUUIDSet parses a GTID set string into a map of UUIDSet structs keyed by their SID.
211+
// Supports multi-UUID sets like "uuid1:1-10,uuid2:5-15".
212+
func ParseUUIDSet(s string) (map[string]*UUIDSet, error) {
213+
if s == "" {
214+
return nil, nil
215+
}
216+
217+
uuidSets := strings.Split(strings.TrimSpace(s), ",")
218+
if len(uuidSets) == 0 {
219+
return nil, fmt.Errorf("empty UUID set")
220+
}
221+
222+
result := make(map[string]*UUIDSet)
223+
for _, set := range uuidSets {
224+
set = strings.TrimSpace(set)
225+
if set == "" {
226+
continue
227+
}
228+
229+
parts := strings.SplitN(set, ":", 2)
230+
if len(parts) != 2 {
231+
return nil, fmt.Errorf("invalid UUID set format: %s", set)
232+
}
233+
234+
sid, err := uuid.Parse(parts[0])
235+
if err != nil {
236+
return nil, fmt.Errorf("invalid UUID: %s", parts[0])
237+
}
238+
239+
// Check if this SID already exists in the map
240+
uuidSet, exists := result[sid.String()]
241+
if !exists {
242+
uuidSet = &UUIDSet{SID: sid}
243+
result[sid.String()] = uuidSet
244+
}
245+
246+
intervals := strings.Split(parts[1], ":")
247+
for _, intervalStr := range intervals {
248+
interval, err := parseInterval(intervalStr)
249+
if err != nil {
250+
return nil, fmt.Errorf("invalid interval in UUID set %s: %v", set, err)
251+
}
252+
uuidSet.Intervals = append(uuidSet.Intervals, interval)
253+
}
254+
255+
if len(uuidSet.Intervals) == 0 {
256+
return nil, fmt.Errorf("no valid intervals in UUID set: %s", set)
257+
}
258+
uuidSet.Intervals = uuidSet.Intervals.Normalize() // Normalize intervals after adding
259+
}
260+
261+
if len(result) == 0 {
262+
return nil, fmt.Errorf("no valid UUID sets parsed from: %s", s)
263+
}
264+
return result, nil
235265
}
236266

237267
func NewUUIDSet(sid uuid.UUID, in ...Interval) *UUIDSet {
@@ -398,23 +428,20 @@ type MysqlGTIDSet struct {
398428
var _ GTIDSet = &MysqlGTIDSet{}
399429

400430
func ParseMysqlGTIDSet(str string) (GTIDSet, error) {
401-
s := new(MysqlGTIDSet)
402-
s.Sets = make(map[string]*UUIDSet)
403-
if str == "" {
404-
return s, nil
405-
}
406-
407-
sp := strings.Split(str, ",")
408-
409-
// todo, handle redundant same uuid
410-
for i := 0; i < len(sp); i++ {
411-
if set, err := ParseUUIDSet(sp[i]); err != nil {
412-
return nil, errors.Trace(err)
413-
} else {
414-
s.AddSet(set)
415-
}
416-
}
417-
return s, nil
431+
s := new(MysqlGTIDSet)
432+
s.Sets = make(map[string]*UUIDSet)
433+
if str == "" {
434+
return s, nil
435+
}
436+
437+
sets, err := ParseUUIDSet(str) // Use the updated ParseUUIDSet
438+
if err != nil {
439+
return nil, errors.Trace(err)
440+
}
441+
for sid, set := range sets {
442+
s.Sets[sid] = set
443+
}
444+
return s, nil
418445
}
419446

420447
func DecodeMysqlGTIDSet(data []byte) (*MysqlGTIDSet, error) {

mysql/mysql_gtid_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package mysql
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"github.com/google/uuid"
8+
)
9+
10+
func TestParseUUIDSet(t *testing.T) {
11+
tests := []struct {
12+
input string
13+
expected map[string]*UUIDSet
14+
wantErr bool
15+
}{
16+
{
17+
input: "0b8beec9-911e-11e9-9f7b-8a057645f3f6:1-1175877800",
18+
expected: map[string]*UUIDSet{
19+
"0b8beec9-911e-11e9-9f7b-8a057645f3f6": {
20+
SID: uuid.Must(uuid.Parse("0b8beec9-911e-11e9-9f7b-8a057645f3f6")),
21+
Intervals: []Interval{{Start: 1, Stop: 1175877801}}, // Stop is Start+1 for single intervals
22+
},
23+
},
24+
wantErr: false,
25+
},
26+
{
27+
input: "0b8beec9-911e-11e9-9f7b-8a057645f3f6:1-1175877800,246e88bd-0288-11e8-9cee-230cd2fc765b:1-592884032",
28+
expected: map[string]*UUIDSet{
29+
"0b8beec9-911e-11e9-9f7b-8a057645f3f6": {
30+
SID: uuid.Must(uuid.Parse("0b8beec9-911e-11e9-9f7b-8a057645f3f6")),
31+
Intervals: []Interval{{Start: 1, Stop: 1175877801}},
32+
},
33+
"246e88bd-0288-11e8-9cee-230cd2fc765b": {
34+
SID: uuid.Must(uuid.Parse("246e88bd-0288-11e8-9cee-230cd2fc765b")),
35+
Intervals: []Interval{{Start: 1, Stop: 592884033}},
36+
},
37+
},
38+
wantErr: false,
39+
},
40+
{
41+
input: "invalid",
42+
wantErr: true,
43+
},
44+
{
45+
input: "",
46+
expected: nil,
47+
wantErr: false,
48+
},
49+
}
50+
51+
for _, tt := range tests {
52+
t.Run(tt.input, func(t *testing.T) {
53+
got, err := ParseUUIDSet(tt.input)
54+
if (err != nil) != tt.wantErr {
55+
t.Errorf("ParseUUIDSet() error = %v, wantErr %v", err, tt.wantErr)
56+
return
57+
}
58+
if !reflect.DeepEqual(got, tt.expected) {
59+
t.Errorf("ParseUUIDSet() = %v, want %v", got, tt.expected)
60+
}
61+
})
62+
}
63+
}
64+
65+
func TestParseMysqlGTIDSet(t *testing.T) {
66+
input := "0b8beec9-911e-11e9-9f7b-8a057645f3f6:1-1175877800,246e88bd-0288-11e8-9cee-230cd2fc765b:1-592884032"
67+
expected := &MysqlGTIDSet{
68+
Sets: map[string]*UUIDSet{
69+
"0b8beec9-911e-11e9-9f7b-8a057645f3f6": {
70+
SID: uuid.Must(uuid.Parse("0b8beec9-911e-11e9-9f7b-8a057645f3f6")),
71+
Intervals: []Interval{{Start: 1, Stop: 1175877801}},
72+
},
73+
"246e88bd-0288-11e8-9cee-230cd2fc765b": {
74+
SID: uuid.Must(uuid.Parse("246e88bd-0288-11e8-9cee-230cd2fc765b")),
75+
Intervals: []Interval{{Start: 1, Stop: 592884033}},
76+
},
77+
},
78+
}
79+
80+
got, err := ParseMysqlGTIDSet(input)
81+
if err != nil {
82+
t.Fatalf("ParseMysqlGTIDSet() error = %v", err)
83+
}
84+
if !reflect.DeepEqual(got, expected) {
85+
t.Errorf("ParseMysqlGTIDSet() = %v, want %v", got, expected)
86+
}
87+
88+
if got.String() != input {
89+
t.Errorf("String() = %v, want %v", got.String(), input)
90+
}
91+
}

0 commit comments

Comments
 (0)