@@ -27,6 +27,20 @@ func (b *BinlogSyncer) StartBackup(backupDir string, p mysql.Position, timeout t
2727 }
2828}
2929
30+ func (b * BinlogSyncer ) StartBackupGTID (backupDir string , gset mysql.GTIDSet , timeout time.Duration ) error {
31+ err := os .MkdirAll (backupDir , 0o755 )
32+ if err != nil {
33+ return errors .Trace (err )
34+ }
35+ if b .cfg .SynchronousEventHandler == nil {
36+ return b .StartBackupWithHandlerAndGTID (gset , timeout , func (filename string ) (io.WriteCloser , error ) {
37+ return os .OpenFile (path .Join (backupDir , filename ), os .O_CREATE | os .O_WRONLY , 0o644 )
38+ })
39+ } else {
40+ return b .StartSynchronousBackupWithGTID (gset , timeout )
41+ }
42+ }
43+
3044// StartBackupWithHandler starts the backup process for the binary log using the specified position and handler.
3145// The process will continue until the timeout is reached or an error occurs.
3246// This method should not be used together with SynchronousEventHandler.
@@ -54,52 +68,72 @@ func (b *BinlogSyncer) StartBackupWithHandler(p mysql.Position, timeout time.Dur
5468 backupHandler := & BackupEventHandler {
5569 handler : handler ,
5670 }
57-
5871 s , err := b .StartSync (p )
5972 if err != nil {
6073 return errors .Trace (err )
6174 }
75+ return processWithHandler (b , s , backupHandler , timeout )
76+ }
6277
63- defer func () {
64- if backupHandler .w != nil {
65- closeErr := backupHandler .w .Close ()
66- if retErr == nil {
67- retErr = closeErr
68- }
69- }
70- }()
78+ // StartBackupWithHandlerAndGTID starts the backup process for the binary log using the specified GTID set and handler.
79+ // - gset: The GTID set from which to begin the backup.
80+ // - timeout: The maximum duration to wait for new binlog events before stopping the backup process.
81+ // If set to 0, a default very long timeout (30 days) is used instead.
82+ // - handler: A function that takes a binlog filename and returns an WriteCloser for writing raw events to.
83+ func (b * BinlogSyncer ) StartBackupWithHandlerAndGTID (gset mysql.GTIDSet , timeout time.Duration ,
84+ handler func (binlogFilename string ) (io.WriteCloser , error ),
85+ ) (retErr error ) {
86+ if timeout == 0 {
87+ // a very long timeout here
88+ timeout = 30 * 3600 * 24 * time .Second
89+ }
90+ if b .cfg .SynchronousEventHandler != nil {
91+ return errors .New ("StartBackupWithHandlerAndGTID cannot be used when SynchronousEventHandler is set. Use StartSynchronousBackupWithGTID instead." )
92+ }
7193
72- ctx , cancel := context . WithTimeout ( context . Background (), timeout )
73- defer cancel ( )
94+ // Force use raw mode
95+ b . parser . SetRawMode ( true )
7496
75- for {
76- select {
77- case <- ctx .Done ():
78- return nil
79- case <- b .ctx .Done ():
80- return nil
81- case err := <- s .ech :
82- return errors .Trace (err )
83- case e := <- s .ch :
84- err = backupHandler .HandleEvent (e )
85- if err != nil {
86- return errors .Trace (err )
87- }
88- }
97+ // Set up the backup event handler
98+ backupHandler := & BackupEventHandler {
99+ handler : handler ,
100+ }
101+
102+ s , err := b .StartSyncGTID (gset )
103+ if err != nil {
104+ return errors .Trace (err )
89105 }
106+ return processWithHandler (b , s , backupHandler , timeout )
90107}
91108
92109// StartSynchronousBackup starts the backup process using the SynchronousEventHandler in the BinlogSyncerConfig.
93110func (b * BinlogSyncer ) StartSynchronousBackup (p mysql.Position , timeout time.Duration ) error {
94111 if b .cfg .SynchronousEventHandler == nil {
95112 return errors .New ("SynchronousEventHandler must be set in BinlogSyncerConfig to use StartSynchronousBackup" )
96113 }
97-
98114 s , err := b .StartSync (p )
99115 if err != nil {
100116 return errors .Trace (err )
101117 }
102118
119+ return process (b , s , timeout )
120+ }
121+
122+ // StartSynchronousBackupWithGTID starts the backup process using the SynchronousEventHandler in the BinlogSyncerConfig with a specified GTID set.
123+ func (b * BinlogSyncer ) StartSynchronousBackupWithGTID (gset mysql.GTIDSet , timeout time.Duration ) error {
124+ if b .cfg .SynchronousEventHandler == nil {
125+ return errors .New ("SynchronousEventHandler must be set in BinlogSyncerConfig to use StartSynchronousBackupWithGTID" )
126+ }
127+
128+ s , err := b .StartSyncGTID (gset )
129+ if err != nil {
130+ return errors .Trace (err )
131+ }
132+
133+ return process (b , s , timeout )
134+ }
135+
136+ func process (b * BinlogSyncer , s * BinlogStreamer , timeout time.Duration ) error {
103137 var ctx context.Context
104138 var cancel context.CancelFunc
105139
@@ -123,6 +157,35 @@ func (b *BinlogSyncer) StartSynchronousBackup(p mysql.Position, timeout time.Dur
123157 }
124158}
125159
160+ func processWithHandler (b * BinlogSyncer , s * BinlogStreamer , backupHandler * BackupEventHandler , timeout time.Duration ) (retErr error ) {
161+ defer func () {
162+ if backupHandler .w != nil {
163+ closeErr := backupHandler .w .Close ()
164+ if retErr == nil {
165+ retErr = closeErr
166+ }
167+ }
168+ }()
169+ ctx , cancel := context .WithTimeout (context .Background (), timeout )
170+ defer cancel ()
171+
172+ for {
173+ select {
174+ case <- ctx .Done ():
175+ return nil
176+ case <- b .ctx .Done ():
177+ return nil
178+ case err := <- s .ech :
179+ return errors .Trace (err )
180+ case e := <- s .ch :
181+ err := backupHandler .HandleEvent (e )
182+ if err != nil {
183+ return errors .Trace (err )
184+ }
185+ }
186+ }
187+ }
188+
126189// BackupEventHandler handles writing events for backup
127190type BackupEventHandler struct {
128191 handler func (binlogFilename string ) (io.WriteCloser , error )
0 commit comments