@@ -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,73 @@ 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+
125+ if b .cfg .SynchronousEventHandler == nil {
126+ return errors .New ("SynchronousEventHandler must be set in BinlogSyncerConfig to use StartSynchronousBackupWithGTID" )
127+ }
128+
129+ s , err := b .StartSyncGTID (gset )
130+ if err != nil {
131+ return errors .Trace (err )
132+ }
133+
134+ return process (b , s , timeout )
135+ }
136+
137+ func process (b * BinlogSyncer , s * BinlogStreamer , timeout time.Duration ) error {
103138 var ctx context.Context
104139 var cancel context.CancelFunc
105140
@@ -123,6 +158,35 @@ func (b *BinlogSyncer) StartSynchronousBackup(p mysql.Position, timeout time.Dur
123158 }
124159}
125160
161+ func processWithHandler (b * BinlogSyncer , s * BinlogStreamer , backupHandler * BackupEventHandler , timeout time.Duration ) (retErr error ) {
162+ defer func () {
163+ if backupHandler .w != nil {
164+ closeErr := backupHandler .w .Close ()
165+ if retErr == nil {
166+ retErr = closeErr
167+ }
168+ }
169+ }()
170+ ctx , cancel := context .WithTimeout (context .Background (), timeout )
171+ defer cancel ()
172+
173+ for {
174+ select {
175+ case <- ctx .Done ():
176+ return nil
177+ case <- b .ctx .Done ():
178+ return nil
179+ case err := <- s .ech :
180+ return errors .Trace (err )
181+ case e := <- s .ch :
182+ err := backupHandler .HandleEvent (e )
183+ if err != nil {
184+ return errors .Trace (err )
185+ }
186+ }
187+ }
188+ }
189+
126190// BackupEventHandler handles writing events for backup
127191type BackupEventHandler struct {
128192 handler func (binlogFilename string ) (io.WriteCloser , error )
0 commit comments