Skip to content

Commit a6b31c8

Browse files
committed
feat: MariaDB GTID support
gh-ost hard-coded the go-mysql binlog syncer to MySQLFlavor and parsed every GTID set as MySQL, so --gtid could not be used against MariaDB. go-mysql already speaks the MariaDB GTID dialect; this wires it up. - Detect server flavor from the version string (IsMariaDB / FlavorFor) and set it on the BinlogSyncerConfig. - Make GTIDBinlogCoordinates hold the flavor-agnostic gomysql.GTIDSet interface; parse via ParseGTIDSet(flavor, ...). - Handle MariadbGTIDEvent alongside GTIDEvent in the streamer, and read the committed GTID set from XIDEvent.GSet without a MySQL-only cast. - Read MariaDB GTID positions from @@global.gtid_binlog_pos, Gtid_IO_Pos and @@global.gtid_slave_pos (MariaDB has no Executed_Gtid_Set column nor gtid_mode / enforce_gtid_consistency). - Skip the gtid_mode / enforce_gtid_consistency validation on MariaDB, where GTIDs are always recorded when binary logging is enabled. localtests: - Detect the server version once and reuse it; run gtid_mode=ON tests on MariaDB (normalize its current_gtid_mode to ON) and trim the GTID diagnostics that don't exist on MariaDB. - Enable gtid_strict_mode on the MariaDB test servers. Because --test-on-replica makes gh-ost write locally on the replica, give the replica its own GTID domain so its writes never collide with the primary's domain-0 stream under strict mode. - Add the gtid-resume case: interrupt a --gtid migration mid-copy via the interactive 'panic' command, then --resume, exercising the GTID checkpoint round-trip (WriteCheckpoint persists the GTID set, ReadLastCheckpoint parses it back via NewGTIDBinlogCoordinates(flavor)). Passes across the MySQL, MariaDB and Percona CI matrix. Verified: full localtests suite passes on MySQL 5.7/8.0/8.4 and on the MariaDB matrix (10.5, 10.6, 10.11, 11.4, 11.8) with gtid_strict_mode on.
1 parent 64a6e3d commit a6b31c8

18 files changed

Lines changed: 368 additions & 51 deletions

doc/command-line-flags.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,9 @@ Add this flag when executing on a 1st generation Google Cloud Platform (GCP).
218218

219219
### gtid
220220

221-
Add this flag to enable support for [MySQL replication GTIDs](https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-concepts.html) for replication positioning. This requires `gtid_mode` and `enforce_gtid_consistency` to be set to `ON`.
221+
Add this flag to enable support for [MySQL replication GTIDs](https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-concepts.html) for replication positioning. On MySQL this requires `gtid_mode` and `enforce_gtid_consistency` to be set to `ON`.
222+
223+
[MariaDB GTIDs](https://mariadb.com/kb/en/gtid/) are also supported: gh-ost detects the server flavor automatically and uses the appropriate GTID dialect. MariaDB has no `gtid_mode`/`enforce_gtid_consistency` settings — GTIDs are always recorded when binary logging is enabled, so no extra configuration is required beyond `--gtid`.
222224

223225
### heartbeat-interval-millis
224226

go/binlog/gomysql_reader.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919

2020
gomysql "github.com/go-mysql-org/go-mysql/mysql"
2121
"github.com/go-mysql-org/go-mysql/replication"
22-
uuid "github.com/google/uuid"
2322
)
2423

2524
type RowsEventFilterFunc func(databaseName, tableName string) bool
@@ -60,7 +59,7 @@ func NewGoMySQLReader(migrationContext *base.MigrationContext, rowsEventFilters
6059
}
6160
config := replication.BinlogSyncerConfig{
6261
ServerID: uint32(migrationContext.ReplicaServerId),
63-
Flavor: gomysql.MySQLFlavor,
62+
Flavor: mysql.FlavorFor(migrationContext.InspectorMySQLVersion),
6463
Host: connectionConfig.Key.Hostname,
6564
Port: uint16(connectionConfig.Key.Port),
6665
User: connectionConfig.User,
@@ -177,11 +176,19 @@ func (gmr *GoMySQLReader) StreamEvents(canStopStreaming func() bool, entriesChan
177176
}
178177

179178
switch event := ev.Event.(type) {
180-
case *replication.GTIDEvent:
179+
case *replication.GTIDEvent, *replication.MariadbGTIDEvent:
180+
// MySQL emits *GTIDEvent, MariaDB emits *MariadbGTIDEvent; both
181+
// implement BinlogGTIDEvent.GTIDNext() returning the GTID about to
182+
// be applied. We advance currentCoordinates by merging it into the
183+
// running GTID set, regardless of flavor.
181184
if !gmr.migrationContext.UseGTIDs {
182185
continue
183186
}
184-
sid, err := uuid.FromBytes(event.SID)
187+
gtidEvent, ok := ev.Event.(gomysql.BinlogGTIDEvent)
188+
if !ok {
189+
return fmt.Errorf("unexpected GTID event type: %T", ev.Event)
190+
}
191+
nextGTID, err := gtidEvent.GTIDNext()
185192
if err != nil {
186193
return err
187194
}
@@ -191,10 +198,11 @@ func (gmr *GoMySQLReader) StreamEvents(canStopStreaming func() bool, entriesChan
191198
}
192199
coords := gmr.currentCoordinates.(*mysql.GTIDBinlogCoordinates)
193200
if coords.GTIDSet == nil {
194-
gtidSet := gomysql.NewMysqlGTIDSet()
195-
coords.GTIDSet = &gtidSet
201+
coords.GTIDSet = nextGTID
202+
} else if err := coords.GTIDSet.Update(nextGTID.String()); err != nil {
203+
gmr.currentCoordinatesMutex.Unlock()
204+
return err
196205
}
197-
coords.GTIDSet.AddGTID(sid, event.GNO)
198206
gmr.currentCoordinatesMutex.Unlock()
199207
case *replication.RotateEvent:
200208
if gmr.migrationContext.UseGTIDs {
@@ -207,7 +215,11 @@ func (gmr *GoMySQLReader) StreamEvents(canStopStreaming func() bool, entriesChan
207215
gmr.currentCoordinatesMutex.Unlock()
208216
case *replication.XIDEvent:
209217
if gmr.migrationContext.UseGTIDs {
210-
gmr.LastTrxCoords = &mysql.GTIDBinlogCoordinates{GTIDSet: event.GSet.(*gomysql.MysqlGTIDSet)}
218+
// event.GSet is the full executed GTID set maintained by the
219+
// syncer (MysqlGTIDSet or MariadbGTIDSet depending on flavor).
220+
if event.GSet != nil {
221+
gmr.LastTrxCoords = &mysql.GTIDBinlogCoordinates{GTIDSet: event.GSet}
222+
}
211223
} else {
212224
gmr.LastTrxCoords = gmr.currentCoordinates.Clone()
213225
}

go/logic/applier.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,7 +849,7 @@ func (apl *Applier) ReadLastCheckpoint() (*Checkpoint, error) {
849849
}
850850
chk.Timestamp = time.Unix(timestamp, 0)
851851
if apl.migrationContext.UseGTIDs {
852-
gtidCoords, err := mysql.NewGTIDBinlogCoordinates(coordStr)
852+
gtidCoords, err := mysql.NewGTIDBinlogCoordinates(mysql.FlavorFor(apl.migrationContext.ApplierMySQLVersion), coordStr)
853853
if err != nil {
854854
return nil, err
855855
}

go/logic/inspect.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,13 @@ func (isp *Inspector) validateBinlogs() error {
427427

428428
// validateGTIDConfig checks that the GTID configuration is good to go
429429
func (isp *Inspector) validateGTIDConfig() error {
430+
if mysql.IsMariaDB(isp.dbVersion) {
431+
// MariaDB has no @@gtid_mode / @@enforce_gtid_consistency: GTIDs are
432+
// always recorded in the binary log when binary logging is enabled
433+
// (which is validated separately). Nothing else to check.
434+
isp.migrationContext.Log.Infof("MariaDB GTID config validated on %s", isp.connectionConfig.Key.String())
435+
return nil
436+
}
430437
var gtidMode, enforceGtidConsistency string
431438
query := `select @@global.gtid_mode, @@global.enforce_gtid_consistency`
432439
if err := isp.db.QueryRow(query).Scan(&gtidMode, &enforceGtidConsistency); err != nil {

go/logic/migrator_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ func TestMigratorHeartbeatDoesNotAdvancePastUnappliedDML(t *testing.T) {
209209

210210
// A DML on the original table at GTID :100 is observed and enqueued, but
211211
// not yet applied.
212-
dmlCoords, err := mysql.NewGTIDBinlogCoordinates(srcUUID + ":1-100")
212+
dmlCoords, err := mysql.NewGTIDBinlogCoordinates(mysql.MySQLFlavor, srcUUID+":1-100")
213213
require.NoError(t, err)
214214
migrator.applyEventsQueue <- newApplyEventStructByDML(&binlog.BinlogEntry{
215215
DmlEvent: &binlog.BinlogDMLEvent{
@@ -224,7 +224,7 @@ func TestMigratorHeartbeatDoesNotAdvancePastUnappliedDML(t *testing.T) {
224224

225225
// A heartbeat row is then written; its GTID set includes the un-applied
226226
// DML plus a few additional transactions.
227-
heartbeatCoords, err := mysql.NewGTIDBinlogCoordinates(srcUUID + ":1-105")
227+
heartbeatCoords, err := mysql.NewGTIDBinlogCoordinates(mysql.MySQLFlavor, srcUUID+":1-105")
228228
require.NoError(t, err)
229229
heartbeatColumnValues := sql.ToColumnValues([]interface{}{
230230
123,

go/logic/streamer.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"github.com/github/gh-ost/go/binlog"
1717
"github.com/github/gh-ost/go/mysql"
1818

19-
gomysql "github.com/go-mysql-org/go-mysql/mysql"
2019
"github.com/openark/golib/sqlutils"
2120
)
2221

@@ -162,17 +161,22 @@ func (es *EventsStreamer) GetCurrentBinlogCoordinates() mysql.BinlogCoordinates
162161

163162
// readCurrentBinlogCoordinates reads master status from hooked server
164163
func (es *EventsStreamer) readCurrentBinlogCoordinates() error {
164+
// MariaDB exposes no GTID column in SHOW MASTER STATUS; its current binlog
165+
// GTID position lives in @@global.gtid_binlog_pos.
166+
if es.migrationContext.UseGTIDs && mysql.IsMariaDB(es.dbVersion) {
167+
return es.readCurrentMariaDBGTIDCoordinates()
168+
}
165169
binaryLogStatusTerm := mysql.ReplicaTermFor(es.dbVersion, "master status")
166170
query := fmt.Sprintf("show /* gh-ost readCurrentBinlogCoordinates */ %s", binaryLogStatusTerm)
167171
foundMasterStatus := false
168172
err := sqlutils.QueryRowsMap(es.db, query, func(m sqlutils.RowMap) error {
169173
if es.migrationContext.UseGTIDs {
170174
execGtidSet := m.GetString("Executed_Gtid_Set")
171-
gtidSet, err := gomysql.ParseMysqlGTIDSet(execGtidSet)
175+
coords, err := mysql.NewGTIDBinlogCoordinates(mysql.MySQLFlavor, execGtidSet)
172176
if err != nil {
173177
return err
174178
}
175-
es.initialBinlogCoordinates = &mysql.GTIDBinlogCoordinates{GTIDSet: gtidSet.(*gomysql.MysqlGTIDSet)}
179+
es.initialBinlogCoordinates = coords
176180
} else {
177181
es.initialBinlogCoordinates = &mysql.FileBinlogCoordinates{
178182
LogFile: m.GetString("File"),
@@ -192,6 +196,23 @@ func (es *EventsStreamer) readCurrentBinlogCoordinates() error {
192196
return nil
193197
}
194198

199+
// readCurrentMariaDBGTIDCoordinates reads the current binlog GTID position from
200+
// a MariaDB server, which is exposed via @@global.gtid_binlog_pos rather than a
201+
// column in SHOW MASTER STATUS.
202+
func (es *EventsStreamer) readCurrentMariaDBGTIDCoordinates() error {
203+
var gtidBinlogPos string
204+
if err := es.db.QueryRow(`select @@global.gtid_binlog_pos`).Scan(&gtidBinlogPos); err != nil {
205+
return err
206+
}
207+
coords, err := mysql.NewGTIDBinlogCoordinates(mysql.MariaDBFlavor, gtidBinlogPos)
208+
if err != nil {
209+
return err
210+
}
211+
es.initialBinlogCoordinates = coords
212+
es.migrationContext.Log.Debugf("Streamer binlog coordinates: %+v", es.initialBinlogCoordinates)
213+
return nil
214+
}
215+
195216
// StreamEvents will begin streaming events. It will be blocking, so should be
196217
// executed by a goroutine
197218
func (es *EventsStreamer) StreamEvents(canStopStreaming func() bool) error {

go/mysql/binlog_file_test.go

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ func TestBinlogCoordinates(t *testing.T) {
4848
48e2bc1d-d66d-11e8-bf56-a0369f9437b8:1,
4949
492e2980-4518-11e9-92c6-e4434b3eca94:1-4926754399`)
5050

51-
c5 := GTIDBinlogCoordinates{GTIDSet: gtidSet1.(*gomysql.MysqlGTIDSet)}
52-
c6 := GTIDBinlogCoordinates{GTIDSet: gtidSet1.(*gomysql.MysqlGTIDSet)}
53-
c7 := GTIDBinlogCoordinates{GTIDSet: gtidSet2.(*gomysql.MysqlGTIDSet)}
54-
c8 := GTIDBinlogCoordinates{GTIDSet: gtidSet3.(*gomysql.MysqlGTIDSet)}
55-
c9 := GTIDBinlogCoordinates{GTIDSet: gtidSetBig1.(*gomysql.MysqlGTIDSet)}
56-
c10 := GTIDBinlogCoordinates{GTIDSet: gtidSetBig2.(*gomysql.MysqlGTIDSet)}
51+
c5 := GTIDBinlogCoordinates{GTIDSet: gtidSet1}
52+
c6 := GTIDBinlogCoordinates{GTIDSet: gtidSet1}
53+
c7 := GTIDBinlogCoordinates{GTIDSet: gtidSet2}
54+
c8 := GTIDBinlogCoordinates{GTIDSet: gtidSet3}
55+
c9 := GTIDBinlogCoordinates{GTIDSet: gtidSetBig1}
56+
c10 := GTIDBinlogCoordinates{GTIDSet: gtidSetBig2}
5757

5858
require.True(t, c5.Equals(&c6))
5959
require.True(t, c1.Equals(&c2))
@@ -76,6 +76,32 @@ func TestBinlogCoordinates(t *testing.T) {
7676
require.True(t, c9.SmallerThanOrEquals(&c10))
7777
}
7878

79+
func TestMariaDBGTIDBinlogCoordinates(t *testing.T) {
80+
// MariaDB GTID sets use domain-server-sequence format.
81+
c1, err := NewGTIDBinlogCoordinates(MariaDBFlavor, "0-1-100")
82+
require.NoError(t, err)
83+
c2, err := NewGTIDBinlogCoordinates(MariaDBFlavor, "0-1-100")
84+
require.NoError(t, err)
85+
c3, err := NewGTIDBinlogCoordinates(MariaDBFlavor, "0-1-150")
86+
require.NoError(t, err)
87+
88+
require.True(t, c1.Equals(c2))
89+
require.False(t, c1.Equals(c3))
90+
require.True(t, c1.SmallerThan(c3))
91+
require.False(t, c3.SmallerThan(c1))
92+
require.True(t, c1.SmallerThanOrEquals(c3))
93+
94+
clone := c1.Clone()
95+
require.True(t, c1.Equals(clone))
96+
require.False(t, c1.IsEmpty())
97+
}
98+
99+
func TestFlavorFor(t *testing.T) {
100+
require.Equal(t, MariaDBFlavor, FlavorFor("10.6.18-MariaDB-log"))
101+
require.Equal(t, MySQLFlavor, FlavorFor("8.0.36"))
102+
require.Equal(t, MySQLFlavor, FlavorFor("8.4.0"))
103+
}
104+
79105
func TestBinlogCoordinatesAsKey(t *testing.T) {
80106
m := make(map[BinlogCoordinates]bool)
81107

go/mysql/binlog_gtid.go

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,39 @@ import (
99
gomysql "github.com/go-mysql-org/go-mysql/mysql"
1010
)
1111

12-
// GTIDBinlogCoordinates describe binary log coordinates in MySQL GTID format.
12+
// Re-exported go-mysql flavor identifiers so the rest of gh-ost doesn't have to
13+
// import go-mysql directly to talk about flavors.
14+
const (
15+
MySQLFlavor = gomysql.MySQLFlavor
16+
MariaDBFlavor = gomysql.MariaDBFlavor
17+
)
18+
19+
// FlavorFor returns the go-mysql flavor identifier for the given server version
20+
// string. It is used to parse GTID sets and to configure the binlog syncer in
21+
// the correct (MySQL vs MariaDB) GTID dialect.
22+
func FlavorFor(mysqlVersion string) string {
23+
if IsMariaDB(mysqlVersion) {
24+
return MariaDBFlavor
25+
}
26+
return MySQLFlavor
27+
}
28+
29+
// GTIDBinlogCoordinates describe binary log coordinates as a GTID set. The
30+
// underlying set is either a MySQL or a MariaDB GTID set depending on the
31+
// flavor it was parsed with; all operations go through the gomysql.GTIDSet
32+
// interface so the two flavors are handled uniformly.
1333
type GTIDBinlogCoordinates struct {
14-
GTIDSet *gomysql.MysqlGTIDSet
34+
GTIDSet gomysql.GTIDSet
1535
}
1636

17-
// NewGTIDBinlogCoordinates parses a MySQL GTID set into a *GTIDBinlogCoordinates struct.
18-
func NewGTIDBinlogCoordinates(gtidSet string) (*GTIDBinlogCoordinates, error) {
19-
set, err := gomysql.ParseMysqlGTIDSet(gtidSet)
20-
return &GTIDBinlogCoordinates{
21-
GTIDSet: set.(*gomysql.MysqlGTIDSet),
22-
}, err
37+
// NewGTIDBinlogCoordinates parses a GTID set string (in the given flavor's
38+
// dialect) into a *GTIDBinlogCoordinates struct.
39+
func NewGTIDBinlogCoordinates(flavor, gtidSet string) (*GTIDBinlogCoordinates, error) {
40+
set, err := gomysql.ParseGTIDSet(flavor, gtidSet)
41+
if err != nil {
42+
return nil, err
43+
}
44+
return &GTIDBinlogCoordinates{GTIDSet: set}, nil
2345
}
2446

2547
// DisplayString returns a user-friendly string representation of these current UUID set or the full GTID set.
@@ -29,6 +51,9 @@ func (coord *GTIDBinlogCoordinates) DisplayString() string {
2951

3052
// String returns a user-friendly string representation of these full GTID set.
3153
func (coord GTIDBinlogCoordinates) String() string {
54+
if coord.GTIDSet == nil {
55+
return ""
56+
}
3257
return coord.GTIDSet.String()
3358
}
3459

@@ -74,7 +99,7 @@ func (coord *GTIDBinlogCoordinates) SmallerThanOrEquals(other BinlogCoordinates)
7499
func (coord *GTIDBinlogCoordinates) Clone() BinlogCoordinates {
75100
out := &GTIDBinlogCoordinates{}
76101
if coord.GTIDSet != nil {
77-
out.GTIDSet = coord.GTIDSet.Clone().(*gomysql.MysqlGTIDSet)
102+
out.GTIDSet = coord.GTIDSet.Clone()
78103
}
79104
return out
80105
}

go/mysql/replica_terminology_map.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,18 @@ var MysqlReplicaTermMap = map[string]string{
2626
"slave": "replica",
2727
}
2828

29+
// IsMariaDB reports whether the given server version string identifies a
30+
// MariaDB server (as opposed to Oracle MySQL). MariaDB reports versions >= 10
31+
// and differs from MySQL in replica terminology and GTID handling.
32+
func IsMariaDB(mysqlVersion string) bool {
33+
return strings.Contains(strings.ToLower(mysqlVersion), "mariadb")
34+
}
35+
2936
func ReplicaTermFor(mysqlVersion string, term string) string {
3037
// MariaDB reports versions >= 10, which compare greater than the 8.4
3138
// cutoff, but it never adopted the new replica/source terminology. Keep
3239
// the legacy terms for it.
33-
if strings.Contains(strings.ToLower(mysqlVersion), "mariadb") {
40+
if IsMariaDB(mysqlVersion) {
3441
return term
3542
}
3643

go/mysql/utils.go

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,14 +217,17 @@ func GetMasterConnectionConfigSafe(dbVersion string, connectionConfig *Connectio
217217
}
218218

219219
func GetReplicationBinlogCoordinates(dbVersion string, db *gosql.DB, gtid bool) (readBinlogCoordinates, executeBinlogCoordinates BinlogCoordinates, err error) {
220+
if gtid && IsMariaDB(dbVersion) {
221+
return getMariaDBReplicationGTIDCoordinates(db)
222+
}
220223
showReplicaStatusQuery := fmt.Sprintf("show %s", ReplicaTermFor(dbVersion, `slave status`))
221224
err = sqlutils.QueryRowsMap(db, showReplicaStatusQuery, func(m sqlutils.RowMap) error {
222225
if gtid {
223-
executeBinlogCoordinates, err = NewGTIDBinlogCoordinates(m.GetString("Executed_Gtid_Set"))
226+
executeBinlogCoordinates, err = NewGTIDBinlogCoordinates(MySQLFlavor, m.GetString("Executed_Gtid_Set"))
224227
if err != nil {
225228
return err
226229
}
227-
readBinlogCoordinates, err = NewGTIDBinlogCoordinates(m.GetString("Retrieved_Gtid_Set"))
230+
readBinlogCoordinates, err = NewGTIDBinlogCoordinates(MySQLFlavor, m.GetString("Retrieved_Gtid_Set"))
228231
if err != nil {
229232
return err
230233
}
@@ -244,10 +247,20 @@ func GetReplicationBinlogCoordinates(dbVersion string, db *gosql.DB, gtid bool)
244247
}
245248

246249
func GetSelfBinlogCoordinates(dbVersion string, db *gosql.DB, gtid bool) (selfBinlogCoordinates BinlogCoordinates, err error) {
250+
if gtid && IsMariaDB(dbVersion) {
251+
// MariaDB does not expose a GTID column in SHOW MASTER STATUS; the
252+
// executed GTID position of this server's own binary log is in
253+
// @@global.gtid_binlog_pos.
254+
var gtidBinlogPos string
255+
if err = db.QueryRow(`select @@global.gtid_binlog_pos`).Scan(&gtidBinlogPos); err != nil {
256+
return nil, err
257+
}
258+
return NewGTIDBinlogCoordinates(MariaDBFlavor, gtidBinlogPos)
259+
}
247260
binaryLogStatusTerm := ReplicaTermFor(dbVersion, "master status")
248261
err = sqlutils.QueryRowsMap(db, fmt.Sprintf("show %s", binaryLogStatusTerm), func(m sqlutils.RowMap) error {
249262
if gtid {
250-
selfBinlogCoordinates, err = NewGTIDBinlogCoordinates(m.GetString("Executed_Gtid_Set"))
263+
selfBinlogCoordinates, err = NewGTIDBinlogCoordinates(MySQLFlavor, m.GetString("Executed_Gtid_Set"))
251264
} else {
252265
selfBinlogCoordinates = NewFileBinlogCoordinates(
253266
m.GetString("File"),
@@ -259,6 +272,26 @@ func GetSelfBinlogCoordinates(dbVersion string, db *gosql.DB, gtid bool) (selfBi
259272
return selfBinlogCoordinates, err
260273
}
261274

275+
// getMariaDBReplicationGTIDCoordinates reports the IO/SQL thread GTID positions
276+
// of a MariaDB replica. MariaDB has no Executed_Gtid_Set/Retrieved_Gtid_Set
277+
// columns: the IO thread position is in SHOW SLAVE STATUS's Gtid_IO_Pos, and the
278+
// applied position is in @@global.gtid_slave_pos.
279+
func getMariaDBReplicationGTIDCoordinates(db *gosql.DB) (readBinlogCoordinates, executeBinlogCoordinates BinlogCoordinates, err error) {
280+
err = sqlutils.QueryRowsMap(db, "show slave status", func(m sqlutils.RowMap) error {
281+
readBinlogCoordinates, err = NewGTIDBinlogCoordinates(MariaDBFlavor, m.GetString("Gtid_IO_Pos"))
282+
return err
283+
})
284+
if err != nil {
285+
return readBinlogCoordinates, executeBinlogCoordinates, err
286+
}
287+
var gtidSlavePos string
288+
if err = db.QueryRow(`select @@global.gtid_slave_pos`).Scan(&gtidSlavePos); err != nil {
289+
return readBinlogCoordinates, executeBinlogCoordinates, err
290+
}
291+
executeBinlogCoordinates, err = NewGTIDBinlogCoordinates(MariaDBFlavor, gtidSlavePos)
292+
return readBinlogCoordinates, executeBinlogCoordinates, err
293+
}
294+
262295
// GetInstanceKey reads hostname and port on given DB
263296
func GetInstanceKey(db *gosql.DB) (instanceKey *InstanceKey, err error) {
264297
instanceKey = &InstanceKey{}

0 commit comments

Comments
 (0)