Skip to content

Commit 17e3e47

Browse files
reuse CutOverLockTimeoutSeconds for move-tables
1 parent 287e8a9 commit 17e3e47

5 files changed

Lines changed: 44 additions & 26 deletions

File tree

go/base/context.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,12 @@ func (mctx *MigrationContext) SetCutOverLockTimeoutSeconds(timeoutSeconds int64)
508508
if timeoutSeconds < 1 {
509509
return fmt.Errorf("minimal timeout is 1sec. Timeout remains at %d", mctx.CutOverLockTimeoutSeconds)
510510
}
511-
if timeoutSeconds > 10 {
512-
return fmt.Errorf("maximal timeout is 10sec. Timeout remains at %d", mctx.CutOverLockTimeoutSeconds)
511+
maxTimeout := int64(10)
512+
if mctx.IsMoveTablesMode() {
513+
maxTimeout = 60
514+
}
515+
if timeoutSeconds > maxTimeout {
516+
return fmt.Errorf("maximal timeout is %dsec. Timeout remains at %d", maxTimeout, mctx.CutOverLockTimeoutSeconds)
513517
}
514518
mctx.CutOverLockTimeoutSeconds = timeoutSeconds
515519
return nil

go/base/context_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,3 +326,22 @@ func TestSetAbortError_ThreadSafe(t *testing.T) {
326326
t.Errorf("Stored error %v not in list of sent errors", got)
327327
}
328328
}
329+
330+
func TestSetCutOverLockTimeoutSecondsRangeByMode(t *testing.T) {
331+
{
332+
ctx := NewMigrationContext()
333+
require.NoError(t, ctx.SetCutOverLockTimeoutSeconds(10))
334+
err := ctx.SetCutOverLockTimeoutSeconds(11)
335+
require.Error(t, err)
336+
require.Contains(t, err.Error(), "maximal timeout is 10sec")
337+
}
338+
339+
{
340+
ctx := NewMigrationContext()
341+
ctx.MoveTables.TableNames = []string{"tbl"}
342+
require.NoError(t, ctx.SetCutOverLockTimeoutSeconds(60))
343+
err := ctx.SetCutOverLockTimeoutSeconds(61)
344+
require.Error(t, err)
345+
require.Contains(t, err.Error(), "maximal timeout is 60sec")
346+
}
347+
}

go/cmd/gh-ost/main.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ func main() {
198198

199199
flag.CommandLine.SetOutput(os.Stdout)
200200
flag.Parse()
201+
cutOverLockTimeoutUserSpecified := false
202+
flag.Visit(func(f *flag.Flag) {
203+
if f.Name == "cut-over-lock-timeout-seconds" {
204+
cutOverLockTimeoutUserSpecified = true
205+
}
206+
})
201207

202208
if *checkFlag {
203209
return
@@ -387,6 +393,9 @@ func main() {
387393
if migrationContext.MoveTables.TargetDatabase == "" {
388394
migrationContext.MoveTables.TargetDatabase = migrationContext.DatabaseName
389395
}
396+
if !cutOverLockTimeoutUserSpecified {
397+
*cutOverLockTimeoutSeconds = 60
398+
}
390399
migrationContext.MoveTables.ConnectionConfig = mysql.NewConnectionConfig()
391400
}
392401

go/logic/migrator.go

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,6 @@ var (
2828
RetrySleepFn = time.Sleep
2929
checkpointTimeout = 2 * time.Second
3030

31-
// moveTablesCutOverDrainTimeout caps how long T3 of the move-tables
32-
// cooperative cutover (#8209) waits for the applier to catch up to the
33-
// drain GTID captured at T2. 60s is a starting default chosen over
34-
// CutOverLockTimeoutSeconds (which is capped at 1-10s by
35-
// SetCutOverLockTimeoutSeconds and would be too short for a real drain
36-
// under load). Up for review with Daniel/Eric in the PR.
37-
moveTablesCutOverDrainTimeout = 60 * time.Second
3831
// moveTablesCutOverDrainPollInterval is the per-iteration sleep in T3's
3932
// drain poll. 100ms per move_table_mode.md §1.5.
4033
moveTablesCutOverDrainPollInterval = 100 * time.Millisecond
@@ -1038,15 +1031,10 @@ func (mgtr *Migrator) moveTablesCutOver() (err error) {
10381031
// drain target (i.e. the applier contains every GTID in drainGTID). Reads
10391032
// of CurrentCoordinates hold the mutex per applier.go:75. Per-iteration
10401033
// logging is Debug only to avoid spamming Info on a hot loop.
1041-
//
1042-
// Timeout is a named constant (moveTablesCutOverDrainTimeout = 60s). NOTE:
1043-
// the internalization doc suggested reusing CutOverLockTimeoutSeconds, but
1044-
// that's capped at 1-10s (context.go:SetCutOverLockTimeoutSeconds) — too
1045-
// short for a real drain under load. 60s default is up for review with
1046-
// Daniel/Eric; flagged in the PR description.
1034+
drainTimeout := time.Duration(mgtr.migrationContext.CutOverLockTimeoutSeconds) * time.Second
10471035
mgtr.migrationContext.Log.Infof("T3: draining applier to drain GTID (timeout %s, poll %s)",
1048-
moveTablesCutOverDrainTimeout, moveTablesCutOverDrainPollInterval)
1049-
drainCtx, cancel := context.WithTimeout(context.Background(), moveTablesCutOverDrainTimeout)
1036+
drainTimeout, moveTablesCutOverDrainPollInterval)
1037+
drainCtx, cancel := context.WithTimeout(context.Background(), drainTimeout)
10501038
defer cancel()
10511039
ticker := time.NewTicker(moveTablesCutOverDrainPollInterval)
10521040
defer ticker.Stop()
@@ -1073,7 +1061,7 @@ func (mgtr *Migrator) moveTablesCutOver() (err error) {
10731061
}
10741062
select {
10751063
case <-drainCtx.Done():
1076-
return fmt.Errorf("drain poll timed out after %s: applier did not catch up to drain GTID", moveTablesCutOverDrainTimeout)
1064+
return fmt.Errorf("drain poll timed out after %s: applier did not catch up to drain GTID", drainTimeout)
10771065
case <-ticker.C:
10781066
// next iteration
10791067
}

go/logic/migrator_move_tables_cutover_test.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -281,26 +281,25 @@ func (s *MoveTablesCutOverSuite) TestRenameFailurePropagates() {
281281
}
282282

283283
// TestDrainTimeoutPropagates maps to T3 timeout handling: applier coordinates
284-
// never reach the drain GTID -> drain poll bounded by moveTablesCutOverDrainTimeout
284+
// never reach the drain GTID -> drain poll bounded by CutOverLockTimeoutSeconds
285285
// returns a wrapped error and the flag is not set.
286286
func (s *MoveTablesCutOverSuite) TestDrainTimeoutPropagates() {
287287
ctx := context.Background()
288288
_, err := s.db.ExecContext(ctx, fmt.Sprintf("CREATE TABLE %s (id INT PRIMARY KEY)", getTestTableName()))
289289
s.Require().NoError(err)
290290

291-
// Patch the package-level timeout/poll just for this test.
292-
origTimeout, origPoll := moveTablesCutOverDrainTimeout, moveTablesCutOverDrainPollInterval
293-
moveTablesCutOverDrainTimeout = 200 * time.Millisecond
291+
// Patch poll interval and use a 1-second drain timeout for a bounded test.
292+
origPoll := moveTablesCutOverDrainPollInterval
294293
moveTablesCutOverDrainPollInterval = 50 * time.Millisecond
295294
s.T().Cleanup(func() {
296-
moveTablesCutOverDrainTimeout = origTimeout
297295
moveTablesCutOverDrainPollInterval = origPoll
298296
})
299297

300298
var calls []string
301299
fakeHooks := &recordingHooks{name: "fake", calls: &calls}
302300
// initialCoords nil - drain comparison never satisfies.
303301
m, mc := s.buildMigrator(fakeHooks, nil)
302+
mc.CutOverLockTimeoutSeconds = 1
304303

305304
s.Require().Equal(int64(0), atomic.LoadInt64(&mc.CutOverCompleteFlag), "pre-state: flag must be 0")
306305

@@ -327,17 +326,16 @@ func (s *MoveTablesCutOverSuite) TestDrainWaitsForQueuedDML() {
327326
_, err := s.db.ExecContext(ctx, fmt.Sprintf("CREATE TABLE %s (id INT PRIMARY KEY)", getTestTableName()))
328327
s.Require().NoError(err)
329328

330-
origTimeout, origPoll := moveTablesCutOverDrainTimeout, moveTablesCutOverDrainPollInterval
331-
moveTablesCutOverDrainTimeout = 200 * time.Millisecond
329+
origPoll := moveTablesCutOverDrainPollInterval
332330
moveTablesCutOverDrainPollInterval = 50 * time.Millisecond
333331
s.T().Cleanup(func() {
334-
moveTablesCutOverDrainTimeout = origTimeout
335332
moveTablesCutOverDrainPollInterval = origPoll
336333
})
337334

338335
var calls []string
339336
fakeHooks := &recordingHooks{name: "fake", calls: &calls}
340337
m, mc := s.buildMigrator(fakeHooks, s.containingDrainGTID())
338+
mc.CutOverLockTimeoutSeconds = 1
341339
m.applyEventsQueue <- newApplyEventStructByDML(&binlog.BinlogEntry{
342340
DmlEvent: &binlog.BinlogDMLEvent{
343341
DatabaseName: testMysqlDatabase,

0 commit comments

Comments
 (0)