-
Notifications
You must be signed in to change notification settings - Fork 288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
relay, syncer(dm): stricter GTID check when retry replication #3496
Changes from 14 commits
cdfbdeb
9a4d2f0
d510385
b473cfe
fef1bae
d808fd2
a6c0802
81b5fb2
43a4074
36bcc52
1318423
baea5ad
68a9429
6cee315
78f01e9
1787ffd
7644130
66fc82f
7e5b2c6
c4f0023
67f0c1a
b7b4120
09d0f67
9f40587
7b8588d
3eb60fe
d981941
c2c8acf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -28,6 +28,7 @@ import ( | |||||||
|
||||||||
gmysql "github.com/go-mysql-org/go-mysql/mysql" | ||||||||
"github.com/go-mysql-org/go-mysql/replication" | ||||||||
"github.com/google/uuid" | ||||||||
"github.com/pingcap/tidb/parser" | ||||||||
"github.com/pingcap/tidb/parser/mysql" | ||||||||
|
||||||||
|
@@ -476,3 +477,19 @@ func statusVarsToKV(statusVars []byte) (map[byte][]byte, error) { | |||||||
|
||||||||
return vars, nil | ||||||||
} | ||||||||
|
||||||||
// GetGTIDStr gets GTID string representation from a GTID event ot MariaDB GTID evnets. | ||||||||
// learn from: https://github.com/go-mysql-org/go-mysql/blob/c6ab05a85eb86dc51a27ceed6d2f366a32874a24/replication/binlogsyncer.go#L736 | ||||||||
// learn from: https://github.com/go-mysql-org/go-mysql/blob/c6ab05a85eb86dc51a27ceed6d2f366a32874a24/replication/binlogsyncer.go#L745 | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
func GetGTIDStr(e *replication.BinlogEvent) (string, error) { | ||||||||
switch ev := e.Event.(type) { | ||||||||
case *replication.GTIDEvent: | ||||||||
u, _ := uuid.FromBytes(ev.SID) | ||||||||
return fmt.Sprintf("%s:%d", u.String(), ev.GNO), nil | ||||||||
case *replication.MariadbGTIDEvent: | ||||||||
GTID := ev.GTID | ||||||||
return fmt.Sprintf("%d-%d-%d", GTID.DomainID, GTID.ServerID, GTID.SequenceNumber), nil | ||||||||
default: | ||||||||
return "", fmt.Errorf("unsupported event type %d", e.Header.EventType) | ||||||||
} | ||||||||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -15,7 +15,6 @@ package relay | |||||
|
||||||
import ( | ||||||
"context" | ||||||
"fmt" | ||||||
"io" | ||||||
"os" | ||||||
"path" | ||||||
|
@@ -27,7 +26,6 @@ import ( | |||||
"github.com/BurntSushi/toml" | ||||||
"github.com/go-mysql-org/go-mysql/mysql" | ||||||
"github.com/go-mysql-org/go-mysql/replication" | ||||||
"github.com/google/uuid" | ||||||
"github.com/pingcap/errors" | ||||||
"go.uber.org/zap" | ||||||
|
||||||
|
@@ -75,6 +73,8 @@ type BinlogReader struct { | |||||
relay Process | ||||||
|
||||||
currentUUID string // current UUID(with suffix) | ||||||
|
||||||
lastFileGracefulEnd bool | ||||||
} | ||||||
|
||||||
// newBinlogReader creates a new BinlogReader. | ||||||
|
@@ -91,13 +91,14 @@ func newBinlogReader(logger log.Logger, cfg *BinlogReaderConfig, relay Process) | |||||
newtctx := tcontext.NewContext(ctx, logger.WithFields(zap.String("component", "binlog reader"))) | ||||||
|
||||||
binlogReader := &BinlogReader{ | ||||||
cfg: cfg, | ||||||
parser: parser, | ||||||
indexPath: path.Join(cfg.RelayDir, utils.UUIDIndexFilename), | ||||||
cancel: cancel, | ||||||
tctx: newtctx, | ||||||
notifyCh: make(chan interface{}, 1), | ||||||
relay: relay, | ||||||
cfg: cfg, | ||||||
parser: parser, | ||||||
indexPath: path.Join(cfg.RelayDir, utils.UUIDIndexFilename), | ||||||
cancel: cancel, | ||||||
tctx: newtctx, | ||||||
notifyCh: make(chan interface{}, 1), | ||||||
relay: relay, | ||||||
lastFileGracefulEnd: true, | ||||||
} | ||||||
binlogReader.relay.RegisterListener(binlogReader) | ||||||
return binlogReader | ||||||
|
@@ -300,7 +301,7 @@ type SwitchPath struct { | |||||
nextBinlogName string | ||||||
} | ||||||
|
||||||
// parseRelay parses relay root directory, it support master-slave switch (switching to next sub directory). | ||||||
// parseRelay parses relay root directory, it supports master-slave switch (switching to next sub directory). | ||||||
func (r *BinlogReader) parseRelay(ctx context.Context, s *LocalStreamer, pos mysql.Position) error { | ||||||
currentUUID, _, realPos, err := binlog.ExtractPos(pos, r.uuids) | ||||||
if err != nil { | ||||||
|
@@ -338,6 +339,16 @@ func (r *BinlogReader) parseRelay(ctx context.Context, s *LocalStreamer, pos mys | |||||
realPos.Name = switchPath.nextBinlogName | ||||||
realPos.Pos = binlog.FileHeaderLen // start from pos 4 for next sub directory / file | ||||||
r.tctx.L().Info("switching to next ready sub directory", zap.String("next uuid", r.currentUUID), zap.Stringer("position", pos)) | ||||||
|
||||||
// when switching sub directory, last binlog file may contain unfinished transaction, so we send a notification. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
if !r.lastFileGracefulEnd { | ||||||
s.ch <- &replication.BinlogEvent{ | ||||||
RawData: []byte(ErrorMaybeDuplicateEvent.Error()), | ||||||
Header: &replication.EventHeader{ | ||||||
EventType: replication.IGNORABLE_EVENT, | ||||||
}, | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
|
@@ -485,8 +496,7 @@ func (r *BinlogReader) parseFileAsPossible(ctx context.Context, s *LocalStreamer | |||||
} | ||||||
} | ||||||
|
||||||
// parseFile parses single relay log file from specified offset | ||||||
// TODO: move all stateful variables into a class, such as r.fileParser. | ||||||
// parseFile parses single relay log file from specified offset. | ||||||
func (r *BinlogReader) parseFile( | ||||||
ctx context.Context, | ||||||
s *LocalStreamer, | ||||||
|
@@ -499,6 +509,7 @@ func (r *BinlogReader) parseFile( | |||||
} | ||||||
|
||||||
offset := state.latestPos | ||||||
r.lastFileGracefulEnd = false | ||||||
|
||||||
onEventFunc := func(e *replication.BinlogEvent) error { | ||||||
if ce := r.tctx.L().Check(zap.DebugLevel, ""); ce != nil { | ||||||
|
@@ -520,6 +531,7 @@ func (r *BinlogReader) parseFile( | |||||
if e.Header.Timestamp != 0 && e.Header.LogPos != 0 { | ||||||
// not fake rotate event, update file pos | ||||||
state.latestPos = int64(e.Header.LogPos) | ||||||
r.lastFileGracefulEnd = true | ||||||
} else { | ||||||
r.tctx.L().Debug("skip fake rotate event", zap.Reflect("header", e.Header)) | ||||||
} | ||||||
|
@@ -538,8 +550,11 @@ func (r *BinlogReader) parseFile( | |||||
state.latestPos = int64(e.Header.LogPos) | ||||||
break | ||||||
} | ||||||
u, _ := uuid.FromBytes(ev.SID) | ||||||
state.replaceWithHeartbeat, err = r.advanceCurrentGtidSet(fmt.Sprintf("%s:%d", u.String(), ev.GNO)) | ||||||
gtidStr, err2 := event.GetGTIDStr(e) | ||||||
if err2 != nil { | ||||||
return errors.Trace(err2) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems we have abandoned trace There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I remember I have seen some zap logger printing error stack 🤔 |
||||||
} | ||||||
state.replaceWithHeartbeat, err = r.advanceCurrentGtidSet(gtidStr) | ||||||
if err != nil { | ||||||
return errors.Trace(err) | ||||||
} | ||||||
|
@@ -549,8 +564,11 @@ func (r *BinlogReader) parseFile( | |||||
state.latestPos = int64(e.Header.LogPos) | ||||||
break | ||||||
} | ||||||
GTID := ev.GTID | ||||||
state.replaceWithHeartbeat, err = r.advanceCurrentGtidSet(fmt.Sprintf("%d-%d-%d", GTID.DomainID, GTID.ServerID, GTID.SequenceNumber)) | ||||||
gtidStr, err2 := event.GetGTIDStr(e) | ||||||
if err2 != nil { | ||||||
return errors.Trace(err2) | ||||||
} | ||||||
state.replaceWithHeartbeat, err = r.advanceCurrentGtidSet(gtidStr) | ||||||
if err != nil { | ||||||
return errors.Trace(err) | ||||||
} | ||||||
|
@@ -627,15 +645,6 @@ func (r *BinlogReader) parseFile( | |||||
if err != nil { | ||||||
if state.possibleLast && isIgnorableParseError(err) { | ||||||
r.tctx.L().Warn("fail to parse relay log file, meet some ignorable error", zap.String("file", state.fullPath), zap.Int64("offset", offset), zap.Error(err)) | ||||||
Ehco1996 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
// the file is truncated, we send a mock event with `IGNORABLE_EVENT` to notify the the consumer | ||||||
// TODO: should add a integration test for this | ||||||
e := &replication.BinlogEvent{ | ||||||
RawData: []byte(ErrorMaybeDuplicateEvent.Error()), | ||||||
Header: &replication.EventHeader{ | ||||||
EventType: replication.IGNORABLE_EVENT, | ||||||
}, | ||||||
} | ||||||
s.ch <- e | ||||||
} else { | ||||||
r.tctx.L().Error("parse relay log file", zap.String("file", state.fullPath), zap.Int64("offset", offset), zap.Error(err)) | ||||||
return false, false, terror.ErrParserParseRelayLog.Delegate(err, state.fullPath) | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.