From 32ccc1710ab74429b068627930c9bb7bd950c757 Mon Sep 17 00:00:00 2001 From: Andrew Mason Date: Sat, 10 Oct 2020 00:53:00 -0400 Subject: [PATCH 01/10] Add a flag to control how long builtinbackup waits for mysqld to shutdown before aborting Signed-off-by: Andrew Mason --- go/vt/mysqlctl/builtinbackupengine.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index cc077bb6610..6f95ac5b7c0 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -20,6 +20,7 @@ import ( "bufio" "context" "encoding/json" + "flag" "fmt" "io" "os" @@ -47,6 +48,10 @@ const ( dataDictionaryFile = "mysql.ibd" ) +var ( + builtinBackupMysqldDeadline = flag.Duration("builtinbackup_mysqld_deadline", time.Minute, "how long to wait for mysqld to shutdown at the start of the backup") +) + // BuiltinBackupEngine encapsulates the logic of the builtin engine // it implements the BackupEngine interface and contains all the logic // required to implement a backup/restore by copying files from and to @@ -182,7 +187,9 @@ func (be *BuiltinBackupEngine) ExecuteBackup(ctx context.Context, params BackupP params.Logger.Infof("using replication position: %v", replicationPosition) // shutdown mysqld - err = params.Mysqld.Shutdown(ctx, params.Cnf, true) + shutdownCtx, cancel := context.WithTimeout(ctx, *builtinBackupMysqldDeadline) + err = params.Mysqld.Shutdown(shutdownCtx, params.Cnf, true) + defer cancel() if err != nil { return false, vterrors.Wrap(err, "can't shutdown mysqld") } From 0a95160d67a00c8e455587635da3ca54de9f4de2 Mon Sep 17 00:00:00 2001 From: Andrew Mason Date: Sat, 10 Oct 2020 08:46:11 -0400 Subject: [PATCH 02/10] Refactor hooks to use `CommandContext` Signed-off-by: Andrew Mason --- go/vt/hook/hook.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/go/vt/hook/hook.go b/go/vt/hook/hook.go index 0215a143829..13d4f71797f 100644 --- a/go/vt/hook/hook.go +++ b/go/vt/hook/hook.go @@ -18,6 +18,7 @@ package hook import ( "bytes" + "context" "fmt" "io" "os" @@ -90,8 +91,8 @@ func NewHookWithEnv(name string, params []string, env map[string]string) *Hook { return &Hook{Name: name, Parameters: params, ExtraEnv: env} } -// findHook trie to locate the hook, and returns the exec.Cmd for it. -func (hook *Hook) findHook() (*exec.Cmd, int, error) { +// findHook tries to locate the hook, and returns the exec.Cmd for it. +func (hook *Hook) findHook(ctx context.Context) (*exec.Cmd, int, error) { // Check the hook path. if strings.Contains(hook.Name, "/") { return nil, HOOK_INVALID_NAME, fmt.Errorf("hook cannot contain '/'") @@ -116,7 +117,7 @@ func (hook *Hook) findHook() (*exec.Cmd, int, error) { // Configure the command. log.Infof("hook: executing hook: %v %v", vthook, strings.Join(hook.Parameters, " ")) - cmd := exec.Command(vthook, hook.Parameters...) + cmd := exec.CommandContext(ctx, vthook, hook.Parameters...) if len(hook.ExtraEnv) > 0 { cmd.Env = os.Environ() for key, value := range hook.ExtraEnv { @@ -132,7 +133,7 @@ func (hook *Hook) Execute() (result *HookResult) { result = &HookResult{} // Find the hook. - cmd, status, err := hook.findHook() + cmd, status, err := hook.findHook(context.Background()) if err != nil { result.ExitStatus = status result.Stderr = err.Error() + "\n" @@ -187,7 +188,7 @@ func (hook *Hook) ExecuteOptional() error { // - an error code and an error if anything fails. func (hook *Hook) ExecuteAsWritePipe(out io.Writer) (io.WriteCloser, WaitFunc, int, error) { // Find the hook. - cmd, status, err := hook.findHook() + cmd, status, err := hook.findHook(context.Background()) if err != nil { return nil, nil, status, err } @@ -226,7 +227,7 @@ func (hook *Hook) ExecuteAsWritePipe(out io.Writer) (io.WriteCloser, WaitFunc, i // - an error code and an error if anything fails. func (hook *Hook) ExecuteAsReadPipe(in io.Reader) (io.Reader, WaitFunc, int, error) { // Find the hook. - cmd, status, err := hook.findHook() + cmd, status, err := hook.findHook(context.Background()) if err != nil { return nil, nil, status, err } From ade85dbd5145cfe6edaa8ffd399c2c16ff97101f Mon Sep 17 00:00:00 2001 From: Andrew Mason Date: Sat, 10 Oct 2020 08:47:30 -0400 Subject: [PATCH 03/10] Create `ExecuteContext`, further refactor Signed-off-by: Andrew Mason --- go/vt/hook/hook.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/go/vt/hook/hook.go b/go/vt/hook/hook.go index 13d4f71797f..2bfad1b5795 100644 --- a/go/vt/hook/hook.go +++ b/go/vt/hook/hook.go @@ -128,12 +128,12 @@ func (hook *Hook) findHook(ctx context.Context) (*exec.Cmd, int, error) { return cmd, HOOK_SUCCESS, nil } -// Execute tries to execute the Hook and returns a HookResult. -func (hook *Hook) Execute() (result *HookResult) { +// ExecuteContext tries to execute the Hook with the given context and returns a HookResult. +func (hook *Hook) ExecuteContext(ctx context.Context) (result *HookResult) { result = &HookResult{} // Find the hook. - cmd, status, err := hook.findHook(context.Background()) + cmd, status, err := hook.findHook(ctx) if err != nil { result.ExitStatus = status result.Stderr = err.Error() + "\n" @@ -163,6 +163,11 @@ func (hook *Hook) Execute() (result *HookResult) { return result } +// Execute tries to execute the Hook and returns a HookResult. +func (hook *Hook) Execute() (result *HookResult) { + return hook.ExecuteContext(context.Background()) +} + // ExecuteOptional executes an optional hook, logs if it doesn't // exist, and returns a printable error. func (hook *Hook) ExecuteOptional() error { From 0366fe9445a2f444f7e345b72b800655522f6009 Mon Sep 17 00:00:00 2001 From: Andrew Mason Date: Sat, 10 Oct 2020 08:48:30 -0400 Subject: [PATCH 04/10] Thread the context through to the shutdown hook Signed-off-by: Andrew Mason --- go/vt/mysqlctl/mysqld.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index 7abd1da7a78..fc6fce373be 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -512,7 +512,7 @@ func (mysqld *Mysqld) Shutdown(ctx context.Context, cnf *Mycnf, waitForMysqld bo // try the mysqld shutdown hook, if any h := hook.NewSimpleHook("mysqld_shutdown") - hr := h.Execute() + hr := h.ExecuteContext(ctx) switch hr.ExitStatus { case hook.HOOK_SUCCESS: // hook exists and worked, we can keep going From c10013fa6b541a8af7a58e90dbd8e3beae7befc5 Mon Sep 17 00:00:00 2001 From: Andrew Mason Date: Sat, 10 Oct 2020 11:26:02 -0400 Subject: [PATCH 05/10] Track duration, correctly handle error cases for timeout-killed processes Signed-off-by: Andrew Mason --- go/vt/hook/hook.go | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/go/vt/hook/hook.go b/go/vt/hook/hook.go index 2bfad1b5795..6cee35e4241 100644 --- a/go/vt/hook/hook.go +++ b/go/vt/hook/hook.go @@ -19,6 +19,7 @@ package hook import ( "bytes" "context" + "errors" "fmt" "io" "os" @@ -26,6 +27,7 @@ import ( "path" "strings" "syscall" + "time" vtenv "vitess.io/vitess/go/vt/env" "vitess.io/vitess/go/vt/log" @@ -70,6 +72,10 @@ const ( // HOOK_GENERIC_ERROR is returned for unknown errors. HOOK_GENERIC_ERROR = -6 + + // HOOK_TIMEOUT_ERROR is returned when a CommandContext has its context + // become done before the command terminates. + HOOK_TIMEOUT_ERROR = -7 ) // WaitFunc is a return type for the Pipe methods. @@ -144,21 +150,45 @@ func (hook *Hook) ExecuteContext(ctx context.Context) (result *HookResult) { var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr + + start := time.Now() err = cmd.Run() + duration := time.Since(start) + result.Stdout = stdout.String() result.Stderr = stderr.String() + + defer func() { + log.Infof("hook: result is %v", result.String()) + }() + if err == nil { result.ExitStatus = HOOK_SUCCESS - } else { - if cmd.ProcessState != nil && cmd.ProcessState.Sys() != nil { - result.ExitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() - } else { - result.ExitStatus = HOOK_CANNOT_GET_EXIT_STATUS - } - result.Stderr += "ERROR: " + err.Error() + "\n" + return result } - log.Infof("hook: result is %v", result.String()) + if ctx.Err() != nil && errors.Is(ctx.Err(), context.DeadlineExceeded) { + // When (exec.Cmd).Run hits a context cancelled, the process is killed via SIGTERM. + // This means: + // 1. cmd.ProcessState.Exited() is false. + // 2. cmd.ProcessState.ExitCode() is -1. + // [ref]: https://golang.org/pkg/os/#ProcessState.ExitCode + // + // Therefore, we need to catch this error specifically, and set result.ExitStatus to + // HOOK_TIMEOUT_ERROR, because just using ExitStatus will result in HOOK_DOES_NOT_EXIST, + // which would be wrong. Since we're already doing some custom handling, we'll also include + // the amount of time the command was running in the error string, in case that is helpful. + result.ExitStatus = HOOK_TIMEOUT_ERROR + result.Stderr += fmt.Sprintf("ERROR: (after %s) %s\n", duration, err) + return result + } + + if cmd.ProcessState != nil && cmd.ProcessState.Sys() != nil { + result.ExitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() + } else { + result.ExitStatus = HOOK_CANNOT_GET_EXIT_STATUS + } + result.Stderr += "ERROR: " + err.Error() + "\n" return result } From 9c66f0c49d90febfd6436a00b092785e32c612b7 Mon Sep 17 00:00:00 2001 From: Andrew Mason Date: Sat, 10 Oct 2020 11:48:20 -0400 Subject: [PATCH 06/10] Add a test for hook timeouts Signed-off-by: Andrew Mason --- go/vt/hook/hook_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 go/vt/hook/hook_test.go diff --git a/go/vt/hook/hook_test.go b/go/vt/hook/hook_test.go new file mode 100644 index 00000000000..fd9235f14b3 --- /dev/null +++ b/go/vt/hook/hook_test.go @@ -0,0 +1,39 @@ +package hook + +import ( + "context" + "os" + "os/exec" + "path" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + vtenv "vitess.io/vitess/go/vt/env" +) + +func TestExecuteContext(t *testing.T) { + vtroot, err := vtenv.VtRoot() + require.NoError(t, err) + + sleep, err := exec.LookPath("sleep") + require.NoError(t, err) + + sleepHookPath := path.Join(vtroot, "vthook", "sleep") + require.NoError(t, os.Symlink(sleep, sleepHookPath)) + defer func() { + require.NoError(t, os.Remove(sleepHookPath)) + }() + + h := NewHook("sleep", []string{"5"}) + ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*10) + defer cancel() + + hr := h.ExecuteContext(ctx) + assert.Equal(t, HOOK_TIMEOUT_ERROR, hr.ExitStatus) + + h.Parameters = []string{"0.1"} + hr = h.Execute() + assert.Equal(t, HOOK_SUCCESS, hr.ExitStatus) +} From 99bf5de6eabc7fd9e5b2f2e23d3036cf81385108 Mon Sep 17 00:00:00 2001 From: Andrew Mason Date: Sun, 11 Oct 2020 16:00:43 -0400 Subject: [PATCH 07/10] Export for testing, document, change default value Signed-off-by: Andrew Mason --- go/vt/mysqlctl/builtinbackupengine.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index 6f95ac5b7c0..b17c53d50aa 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -49,7 +49,10 @@ const ( ) var ( - builtinBackupMysqldDeadline = flag.Duration("builtinbackup_mysqld_deadline", time.Minute, "how long to wait for mysqld to shutdown at the start of the backup") + // BuiltinBackupMysqldDeadline is how long ExecuteBackup should wait for response from mysqld.Shutdown. + // It can later be extended for other calls to mysqld during backup functions. + // Exported for testing. + BuiltinBackupMysqldDeadline = flag.Duration("builtinbackup_mysqld_deadline", 10*time.Minute, "how long to wait for mysqld to shutdown at the start of the backup") ) // BuiltinBackupEngine encapsulates the logic of the builtin engine @@ -187,7 +190,7 @@ func (be *BuiltinBackupEngine) ExecuteBackup(ctx context.Context, params BackupP params.Logger.Infof("using replication position: %v", replicationPosition) // shutdown mysqld - shutdownCtx, cancel := context.WithTimeout(ctx, *builtinBackupMysqldDeadline) + shutdownCtx, cancel := context.WithTimeout(ctx, *BuiltinBackupMysqldDeadline) err = params.Mysqld.Shutdown(shutdownCtx, params.Cnf, true) defer cancel() if err != nil { From b278ffa03e1832ee8c6a2e8308a335fac4265577 Mon Sep 17 00:00:00 2001 From: Andrew Mason Date: Sun, 11 Oct 2020 16:02:54 -0400 Subject: [PATCH 08/10] Add Startup/Shutdown durations to fakemysqldaemon Signed-off-by: Andrew Mason --- .../fakemysqldaemon/fakemysqldaemon.go | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go index f4142ffee20..84e933dfa6f 100644 --- a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go +++ b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go @@ -48,6 +48,14 @@ type FakeMysqlDaemon struct { // Running is used by Start / Shutdown Running bool + // StartupTime is used to simulate mysqlds that take some time to respond + // to a "start" command. It is used by Start. + StartupTime time.Duration + + // ShutdownTime is used to simulate mysqlds that take some time to respond + // to a "stop" request (i.e. a wedged systemd unit). It is used by Shutdown. + ShutdownTime time.Duration + // MysqlPort will be returned by GetMysqlPort(). Set to -1 to // return an error. MysqlPort sync2.AtomicInt32 @@ -181,6 +189,15 @@ func (fmd *FakeMysqlDaemon) Start(ctx context.Context, cnf *mysqlctl.Mycnf, mysq if fmd.Running { return fmt.Errorf("fake mysql daemon already running") } + + if fmd.StartupTime > 0 { + select { + case <-time.After(fmd.StartupTime): + case <-ctx.Done(): + return ctx.Err() + } + } + fmd.Running = true return nil } @@ -190,6 +207,15 @@ func (fmd *FakeMysqlDaemon) Shutdown(ctx context.Context, cnf *mysqlctl.Mycnf, w if !fmd.Running { return fmt.Errorf("fake mysql daemon not running") } + + if fmd.ShutdownTime > 0 { + select { + case <-time.After(fmd.ShutdownTime): + case <-ctx.Done(): + return ctx.Err() + } + } + fmd.Running = false return nil } From a918ff3378bc3724951db1f0a2e3fc7f10ceab94 Mon Sep 17 00:00:00 2001 From: Andrew Mason Date: Sun, 11 Oct 2020 16:06:50 -0400 Subject: [PATCH 09/10] Add blackbox tests for ExecuteBackup that exercise shutdown-deadline behavior Signed-off-by: Andrew Mason --- go/vt/mysqlctl/builtinbackupengine_test.go | 135 +++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 go/vt/mysqlctl/builtinbackupengine_test.go diff --git a/go/vt/mysqlctl/builtinbackupengine_test.go b/go/vt/mysqlctl/builtinbackupengine_test.go new file mode 100644 index 00000000000..959aa5058b1 --- /dev/null +++ b/go/vt/mysqlctl/builtinbackupengine_test.go @@ -0,0 +1,135 @@ +// Package mysqlctl_test is the blackbox tests for package mysqlctl. +// Tests that need to use fakemysqldaemon must be written as blackbox tests; +// since fakemysqldaemon imports mysqlctl, importing fakemysqldaemon in +// a `package mysqlctl` test would cause a circular import. +package mysqlctl_test + +import ( + "context" + "os" + "path" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/fakesqldb" + "vitess.io/vitess/go/vt/logutil" + "vitess.io/vitess/go/vt/mysqlctl" + "vitess.io/vitess/go/vt/mysqlctl/fakemysqldaemon" + "vitess.io/vitess/go/vt/mysqlctl/filebackupstorage" + "vitess.io/vitess/go/vt/proto/topodata" + "vitess.io/vitess/go/vt/proto/vttime" + "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/topo/memorytopo" + "vitess.io/vitess/go/vt/vttablet/faketmclient" + "vitess.io/vitess/go/vt/vttablet/tmclient" +) + +func setBuiltinBackupMysqldDeadline(t time.Duration) time.Duration { + old := *mysqlctl.BuiltinBackupMysqldDeadline + mysqlctl.BuiltinBackupMysqldDeadline = &t + + return old +} + +func createBackupDir(root string, dirs ...string) error { + for _, dir := range dirs { + if err := os.MkdirAll(path.Join(root, dir), 0755); err != nil { + return err + } + } + + return nil +} + +func TestExecuteBackup(t *testing.T) { + // Set up local backup directory + backupRoot := "testdata/builtinbackup_test" + *filebackupstorage.FileBackupStorageRoot = backupRoot + require.NoError(t, createBackupDir(backupRoot, "innodb", "log", "datadir")) + defer os.RemoveAll(backupRoot) + + ctx := context.Background() + + // Set up topo + keyspace, shard := "mykeyspace", "-80" + ts := memorytopo.NewServer("cell1") + defer ts.Close() + + require.NoError(t, ts.CreateKeyspace(ctx, keyspace, &topodata.Keyspace{})) + require.NoError(t, ts.CreateShard(ctx, keyspace, shard)) + + tablet := topo.NewTablet(100, "cell1", "mykeyspace-00-80-0100") + tablet.Keyspace = keyspace + tablet.Shard = shard + + require.NoError(t, ts.CreateTablet(ctx, tablet)) + + _, err := ts.UpdateShardFields(ctx, keyspace, shard, func(si *topo.ShardInfo) error { + si.MasterAlias = &topodata.TabletAlias{Uid: 100, Cell: "cell1"} + + now := time.Now() + si.MasterTermStartTime = &vttime.Time{Seconds: int64(now.Second()), Nanoseconds: int32(now.Nanosecond())} + + return nil + }) + require.NoError(t, err) + + // Set up tm client + // Note that using faketmclient.NewFakeTabletManagerClient will cause infinite recursion :shrug: + tmclient.RegisterTabletManagerClientFactory("grpc", + func() tmclient.TabletManagerClient { return &faketmclient.FakeTabletManagerClient{} }, + ) + + be := &mysqlctl.BuiltinBackupEngine{} + + // Configure a tight deadline to force a timeout + oldDeadline := setBuiltinBackupMysqldDeadline(time.Second) + defer setBuiltinBackupMysqldDeadline(oldDeadline) + + bh := filebackupstorage.FileBackupHandle{} + + // Spin up a fake daemon to be used in backups. It needs to be allowed to receive: + // "STOP SLAVE", "START SLAVE", in that order. + mysqld := fakemysqldaemon.NewFakeMysqlDaemon(fakesqldb.New(t)) + mysqld.ExpectedExecuteSuperQueryList = []string{"STOP SLAVE", "START SLAVE"} + // mysqld.ShutdownTime = time.Minute + + ok, err := be.ExecuteBackup(ctx, mysqlctl.BackupParams{ + Logger: logutil.NewConsoleLogger(), + Mysqld: mysqld, + Cnf: &mysqlctl.Mycnf{ + InnodbDataHomeDir: path.Join(backupRoot, "innodb"), + InnodbLogGroupHomeDir: path.Join(backupRoot, "log"), + DataDir: path.Join(backupRoot, "datadir"), + }, + HookExtraEnv: map[string]string{}, + TopoServer: ts, + Keyspace: keyspace, + Shard: shard, + }, &bh) + + require.NoError(t, err) + assert.True(t, ok) + + mysqld.ExpectedExecuteSuperQueryCurrent = 0 // resest the index of what queries we've run + mysqld.ShutdownTime = time.Minute // reminder that shutdownDeadline is 1s + + ok, err = be.ExecuteBackup(ctx, mysqlctl.BackupParams{ + Logger: logutil.NewConsoleLogger(), + Mysqld: mysqld, + Cnf: &mysqlctl.Mycnf{ + InnodbDataHomeDir: path.Join(backupRoot, "innodb"), + InnodbLogGroupHomeDir: path.Join(backupRoot, "log"), + DataDir: path.Join(backupRoot, "datadir"), + }, + HookExtraEnv: map[string]string{}, + TopoServer: ts, + Keyspace: keyspace, + Shard: shard, + }, &bh) + + assert.Error(t, err) + assert.False(t, ok) +} From 9d9166c78dd6365648d4f115f97cd08aacd3ce16 Mon Sep 17 00:00:00 2001 From: Andrew Mason Date: Mon, 19 Oct 2020 17:24:00 -0400 Subject: [PATCH 10/10] Rename from deadline to timeout Signed-off-by: Andrew Mason --- go/vt/mysqlctl/builtinbackupengine.go | 6 +++--- go/vt/mysqlctl/builtinbackupengine_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index b17c53d50aa..a1db9af5107 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -49,10 +49,10 @@ const ( ) var ( - // BuiltinBackupMysqldDeadline is how long ExecuteBackup should wait for response from mysqld.Shutdown. + // BuiltinBackupMysqldTimeout is how long ExecuteBackup should wait for response from mysqld.Shutdown. // It can later be extended for other calls to mysqld during backup functions. // Exported for testing. - BuiltinBackupMysqldDeadline = flag.Duration("builtinbackup_mysqld_deadline", 10*time.Minute, "how long to wait for mysqld to shutdown at the start of the backup") + BuiltinBackupMysqldTimeout = flag.Duration("builtinbackup_mysqld_timeout", 10*time.Minute, "how long to wait for mysqld to shutdown at the start of the backup") ) // BuiltinBackupEngine encapsulates the logic of the builtin engine @@ -190,7 +190,7 @@ func (be *BuiltinBackupEngine) ExecuteBackup(ctx context.Context, params BackupP params.Logger.Infof("using replication position: %v", replicationPosition) // shutdown mysqld - shutdownCtx, cancel := context.WithTimeout(ctx, *BuiltinBackupMysqldDeadline) + shutdownCtx, cancel := context.WithTimeout(ctx, *BuiltinBackupMysqldTimeout) err = params.Mysqld.Shutdown(shutdownCtx, params.Cnf, true) defer cancel() if err != nil { diff --git a/go/vt/mysqlctl/builtinbackupengine_test.go b/go/vt/mysqlctl/builtinbackupengine_test.go index 959aa5058b1..3e9b739839b 100644 --- a/go/vt/mysqlctl/builtinbackupengine_test.go +++ b/go/vt/mysqlctl/builtinbackupengine_test.go @@ -27,8 +27,8 @@ import ( ) func setBuiltinBackupMysqldDeadline(t time.Duration) time.Duration { - old := *mysqlctl.BuiltinBackupMysqldDeadline - mysqlctl.BuiltinBackupMysqldDeadline = &t + old := *mysqlctl.BuiltinBackupMysqldTimeout + mysqlctl.BuiltinBackupMysqldTimeout = &t return old }