@@ -12,20 +12,24 @@ import (
12
12
"github.com/pingcap/errors"
13
13
)
14
14
15
- // StartBackup: Like mysqlbinlog remote raw backup
16
- // Backup remote binlog from position (filename, offset) and write in backupDir
15
+ // StartBackup starts the backup process for the binary log and writes to the backup directory.
17
16
func (b * BinlogSyncer ) StartBackup (backupDir string , p Position , timeout time.Duration ) error {
18
17
err := os .MkdirAll (backupDir , 0755 )
19
18
if err != nil {
20
19
return errors .Trace (err )
21
20
}
22
- return b .StartBackupWithHandler (p , timeout , func (filename string ) (io.WriteCloser , error ) {
23
- return os .OpenFile (path .Join (backupDir , filename ), os .O_CREATE | os .O_WRONLY , 0644 )
24
- })
21
+ if b .cfg .SynchronousEventHandler == nil {
22
+ return b .StartBackupWithHandler (p , timeout , func (filename string ) (io.WriteCloser , error ) {
23
+ return os .OpenFile (path .Join (backupDir , filename ), os .O_CREATE | os .O_WRONLY , 0644 )
24
+ })
25
+ } else {
26
+ return b .StartSynchronousBackup (p , timeout )
27
+ }
25
28
}
26
29
27
30
// StartBackupWithHandler starts the backup process for the binary log using the specified position and handler.
28
31
// The process will continue until the timeout is reached or an error occurs.
32
+ // This method should not be used together with SynchronousEventHandler.
29
33
//
30
34
// Parameters:
31
35
// - p: The starting position in the binlog from which to begin the backup.
@@ -38,6 +42,9 @@ func (b *BinlogSyncer) StartBackupWithHandler(p Position, timeout time.Duration,
38
42
// a very long timeout here
39
43
timeout = 30 * 3600 * 24 * time .Second
40
44
}
45
+ if b .cfg .SynchronousEventHandler != nil {
46
+ return errors .New ("StartBackupWithHandler cannot be used when SynchronousEventHandler is set. Use StartSynchronousBackup instead." )
47
+ }
41
48
42
49
// Force use raw mode
43
50
b .parser .SetRawMode (true )
@@ -47,18 +54,12 @@ func (b *BinlogSyncer) StartBackupWithHandler(p Position, timeout time.Duration,
47
54
handler : handler ,
48
55
}
49
56
50
- if b .cfg .SyncMode == SyncModeSync {
51
- // Set the event handler in BinlogSyncer for synchronous mode
52
- b .SetEventHandler (backupHandler )
53
- }
54
-
55
57
s , err := b .StartSync (p )
56
58
if err != nil {
57
59
return errors .Trace (err )
58
60
}
59
61
60
62
defer func () {
61
- b .SetEventHandler (nil ) // Reset the event handler
62
63
if backupHandler .w != nil {
63
64
closeErr := backupHandler .w .Close ()
64
65
if retErr == nil {
@@ -70,66 +71,76 @@ func (b *BinlogSyncer) StartBackupWithHandler(p Position, timeout time.Duration,
70
71
ctx , cancel := context .WithTimeout (context .Background (), timeout )
71
72
defer cancel ()
72
73
73
- if b .cfg .SyncMode == SyncModeSync {
74
- // Synchronous mode: wait for completion or error
74
+ for {
75
75
select {
76
76
case <- ctx .Done ():
77
77
return nil
78
78
case <- b .ctx .Done ():
79
79
return nil
80
80
case err := <- s .ech :
81
81
return errors .Trace (err )
82
- }
83
- } else {
84
- // Asynchronous mode: consume events from the streamer
85
- for {
86
- select {
87
- case <- ctx .Done ():
88
- return nil
89
- case <- b .ctx .Done ():
90
- return nil
91
- case err := <- s .ech :
82
+ case e := <- s .ch :
83
+ err = backupHandler .HandleEvent (e )
84
+ if err != nil {
92
85
return errors .Trace (err )
93
- case e := <- s .ch :
94
- err = backupHandler .HandleEvent (e )
95
- if err != nil {
96
- return errors .Trace (err )
97
- }
98
86
}
99
87
}
100
88
}
101
89
}
102
90
91
+ // StartSynchronousBackup starts the backup process using the SynchronousEventHandler in the BinlogSyncerConfig.
92
+ func (b * BinlogSyncer ) StartSynchronousBackup (p Position , timeout time.Duration ) error {
93
+ if b .cfg .SynchronousEventHandler == nil {
94
+ return errors .New ("SynchronousEventHandler must be set in BinlogSyncerConfig to use StartSynchronousBackup" )
95
+ }
96
+
97
+ if timeout == 0 {
98
+ timeout = 30 * 3600 * 24 * time .Second // Long timeout by default
99
+ }
100
+
101
+ ctx , cancel := context .WithTimeout (context .Background (), timeout )
102
+ defer cancel ()
103
+
104
+ s , err := b .StartSync (p )
105
+ if err != nil {
106
+ return errors .Trace (err )
107
+ }
108
+
109
+ // Wait for the binlog syncer to finish or encounter an error
110
+ select {
111
+ case <- ctx .Done ():
112
+ return nil
113
+ case <- b .ctx .Done ():
114
+ return nil
115
+ case err := <- s .ech :
116
+ return errors .Trace (err )
117
+ }
118
+ }
119
+
103
120
// BackupEventHandler handles writing events for backup
104
121
type BackupEventHandler struct {
105
- handler func (binlogFilename string ) (io.WriteCloser , error )
106
- w io.WriteCloser
107
- mutex sync.Mutex
108
- fsyncedChan chan struct {}
109
- eventCount int // eventCount used for testing
122
+ handler func (binlogFilename string ) (io.WriteCloser , error )
123
+ w io.WriteCloser
124
+ mutex sync.Mutex
110
125
111
126
filename string
112
127
}
113
128
129
+ // HandleEvent processes a single event for the backup.
114
130
func (h * BackupEventHandler ) HandleEvent (e * BinlogEvent ) error {
115
131
h .mutex .Lock ()
116
132
defer h .mutex .Unlock ()
117
133
118
134
var err error
119
-
120
- // Update the offset
121
135
offset := e .Header .LogPos
122
136
123
137
if e .Header .EventType == ROTATE_EVENT {
124
138
rotateEvent := e .Event .(* RotateEvent )
125
139
h .filename = string (rotateEvent .NextLogName )
126
-
127
140
if e .Header .Timestamp == 0 || offset == 0 {
128
- // Fake rotate event, skip processing
129
141
return nil
130
142
}
131
143
} else if e .Header .EventType == FORMAT_DESCRIPTION_EVENT {
132
- // Close the current writer and open a new one
133
144
if h .w != nil {
134
145
if err = h .w .Close (); err != nil {
135
146
h .w = nil
@@ -146,14 +157,12 @@ func (h *BackupEventHandler) HandleEvent(e *BinlogEvent) error {
146
157
return errors .Trace (err )
147
158
}
148
159
149
- // Write binlog header fe'bin'
150
160
_ , err = h .w .Write (BinLogFileHeader )
151
161
if err != nil {
152
162
return errors .Trace (err )
153
163
}
154
164
}
155
165
156
- // Write raw event data to the current writer
157
166
if h .w != nil {
158
167
n , err := h .w .Write (e .RawData )
159
168
if err != nil {
@@ -162,23 +171,9 @@ func (h *BackupEventHandler) HandleEvent(e *BinlogEvent) error {
162
171
if n != len (e .RawData ) {
163
172
return errors .Trace (io .ErrShortWrite )
164
173
}
165
-
166
- // Perform Sync if the writer supports it
167
- if f , ok := h .w .(* os.File ); ok {
168
- if err := f .Sync (); err != nil {
169
- return errors .Trace (err )
170
- }
171
- // Signal that fsync has completed
172
- if h .fsyncedChan != nil {
173
- h .fsyncedChan <- struct {}{}
174
- }
175
- }
176
174
} else {
177
- // If writer is nil and event is not FORMAT_DESCRIPTION_EVENT, we can't write
178
- // This should not happen if events are in expected order
179
175
return errors .New ("writer is not initialized" )
180
176
}
181
177
182
- h .eventCount ++
183
178
return nil
184
179
}
0 commit comments