@@ -55,9 +55,10 @@ type lockProcessedStruct struct {
5555}
5656
5757type applyEventStruct struct {
58- writeFunc * tableWriteFunc
59- dmlEvent * binlog.BinlogDMLEvent
60- coords mysql.BinlogCoordinates
58+ writeFunc * tableWriteFunc
59+ dmlEvent * binlog.BinlogDMLEvent
60+ coords mysql.BinlogCoordinates
61+ eventTimestamp time.Time
6162}
6263
6364func newApplyEventStructByFunc (writeFunc * tableWriteFunc ) * applyEventStruct {
@@ -66,7 +67,7 @@ func newApplyEventStructByFunc(writeFunc *tableWriteFunc) *applyEventStruct {
6667}
6768
6869func newApplyEventStructByDML (dmlEntry * binlog.BinlogEntry ) * applyEventStruct {
69- result := & applyEventStruct {dmlEvent : dmlEntry .DmlEvent , coords : dmlEntry .Coordinates }
70+ result := & applyEventStruct {dmlEvent : dmlEntry .DmlEvent , coords : dmlEntry .Coordinates , eventTimestamp : dmlEntry . Timestamp }
7071 return result
7172}
7273
@@ -2170,14 +2171,28 @@ func (mgtr *Migrator) printStatus(rule PrintStatusRule, writers ...io.Writer) {
21702171
21712172 currentBinlogCoordinates := mgtr .eventsStreamer .GetCurrentBinlogCoordinates ()
21722173
2173- status := fmt .Sprintf ("Copy: %d/%d %.1f%%; Applied: %d; Backlog: %d/%d; Time: %+v(total), %+v(copy); streamer: %+v; Lag: %.2fs, HeartbeatLag: %.2fs, State: %s; ETA: %s" ,
2174+ // Lag reporting differs by mode. Standard mode reports the inspected replica
2175+ // "Lag" (changelog heartbeat) plus "HeartbeatLag". Move-tables mode has no
2176+ // changelog heartbeat, and the source-side replication "Lag" is meaningless
2177+ // (writes go to the target, so migration-induced replica lag appears on target
2178+ // replicas and is handled separately by throttling). The "Lag" field is
2179+ // therefore dropped and writer lag (now - last applied binlog event timestamp)
2180+ // is reported as "WriterLag" instead.
2181+ lagStatus := fmt .Sprintf ("Lag: %.2fs, HeartbeatLag: %.2fs" ,
2182+ mgtr .migrationContext .GetCurrentLagDuration ().Seconds (),
2183+ mgtr .migrationContext .TimeSinceLastHeartbeatOnChangelog ().Seconds (),
2184+ )
2185+ if mgtr .migrationContext .IsMoveTablesMode () {
2186+ lagStatus = fmt .Sprintf ("WriterLag: %.2fs" , mgtr .migrationContext .GetBinlogWriterLag ().Seconds ())
2187+ }
2188+
2189+ status := fmt .Sprintf ("Copy: %d/%d %.1f%%; Applied: %d; Backlog: %d/%d; Time: %+v(total), %+v(copy); streamer: %+v; %s, State: %s; ETA: %s" ,
21742190 totalRowsCopied , rowsEstimate , progressPct ,
21752191 atomic .LoadInt64 (& mgtr .migrationContext .TotalDMLEventsApplied ),
21762192 len (mgtr .applyEventsQueue ), cap (mgtr .applyEventsQueue ),
21772193 base .PrettifyDurationOutput (elapsedTime ), base .PrettifyDurationOutput (mgtr .migrationContext .ElapsedRowCopyTime ()),
21782194 currentBinlogCoordinates .DisplayString (),
2179- mgtr .migrationContext .GetCurrentLagDuration ().Seconds (),
2180- mgtr .migrationContext .TimeSinceLastHeartbeatOnChangelog ().Seconds (),
2195+ lagStatus ,
21812196 state ,
21822197 eta ,
21832198 )
@@ -2242,6 +2257,24 @@ func (mgtr *Migrator) initiateStreaming() error {
22422257 mgtr .migrationContext .SetRecentBinlogCoordinates (mgtr .eventsStreamer .GetCurrentBinlogCoordinates ())
22432258 }
22442259 }()
2260+
2261+ // In move-tables mode there is no changelog heartbeat. Writer lag is derived
2262+ // from binlog-header timestamps of applied events; when the streamer has been
2263+ // silent for the heartbeat interval, treat that silence as "caught up" and bump
2264+ // the last-applied timestamp to now so lag does not climb forever while idle.
2265+ if mgtr .migrationContext .IsMoveTablesMode () {
2266+ go func () {
2267+ interval := time .Duration (mgtr .migrationContext .HeartbeatIntervalMilliseconds ) * time .Millisecond
2268+ ticker := time .NewTicker (interval )
2269+ defer ticker .Stop ()
2270+ for range ticker .C {
2271+ if atomic .LoadInt64 (& mgtr .finishedMigrating ) > 0 {
2272+ return
2273+ }
2274+ mgtr .migrationContext .BumpBinlogWriterLagIfIdle (interval )
2275+ }
2276+ }()
2277+ }
22452278 return nil
22462279}
22472280
@@ -2258,6 +2291,11 @@ func (mgtr *Migrator) addDMLEventsListener() error {
22582291 mgtr .migrationContext .DatabaseName ,
22592292 originalTableName ,
22602293 func (dmlEntry * binlog.BinlogEntry ) error {
2294+ // Record that the streamer just delivered an event for the moved table,
2295+ // so the idle-bump rule can tell "falling behind" from "source is quiet".
2296+ if mgtr .migrationContext .IsMoveTablesMode () {
2297+ mgtr .migrationContext .MarkBinlogEventStreamed ()
2298+ }
22612299 // Use helper to prevent deadlock if buffer fills and executeWriteFuncs exits
22622300 // This is critical because this callback blocks the event streamer
22632301 return base .SendWithContext (mgtr .migrationContext .GetContext (), mgtr .applyEventsQueue , newApplyEventStructByDML (dmlEntry ))
@@ -2492,6 +2530,7 @@ func (mgtr *Migrator) onApplyEventStruct(eventStruct *applyEventStruct) error {
24922530 if eventStruct .dmlEvent != nil {
24932531 dmlEvents := [](* binlog.BinlogDMLEvent ){}
24942532 dmlEvents = append (dmlEvents , eventStruct .dmlEvent )
2533+ lastEventTimestamp := eventStruct .eventTimestamp
24952534 var nonDmlStructToApply * applyEventStruct
24962535
24972536 availableEvents := len (mgtr .applyEventsQueue )
@@ -2509,6 +2548,7 @@ func (mgtr *Migrator) onApplyEventStruct(eventStruct *applyEventStruct) error {
25092548 break
25102549 }
25112550 dmlEvents = append (dmlEvents , additionalStruct .dmlEvent )
2551+ lastEventTimestamp = additionalStruct .eventTimestamp
25122552 }
25132553 // Create a task to apply the DML event; this will be execute by executeWriteFuncs()
25142554 var applyEventFunc tableWriteFunc = func () error {
@@ -2522,6 +2562,12 @@ func (mgtr *Migrator) onApplyEventStruct(eventStruct *applyEventStruct) error {
25222562 mgtr .applier .CurrentCoordinates = eventStruct .coords
25232563 mgtr .applier .CurrentCoordinatesMutex .Unlock ()
25242564
2565+ // In move-tables mode there is no changelog heartbeat; writer lag is derived
2566+ // from the binlog-header timestamp of the last event we just applied.
2567+ if mgtr .migrationContext .IsMoveTablesMode () && ! lastEventTimestamp .IsZero () {
2568+ mgtr .migrationContext .UpdateLastAppliedBinlogEventTime (lastEventTimestamp )
2569+ }
2570+
25252571 if nonDmlStructToApply != nil {
25262572 // We pulled DML events from the queue, and then we hit a non-DML event. Wait!
25272573 // We need to handle it!
0 commit comments