diff --git a/doc/command-line-flags.md b/doc/command-line-flags.md index 5f92cc0..0a13ae5 100644 --- a/doc/command-line-flags.md +++ b/doc/command-line-flags.md @@ -119,6 +119,12 @@ See also: [Sub-second replication lag throttling](subsecond-lag.md) Typically `gh-ost` is used to migrate tables on a master. If you wish to only perform the migration in full on a replica, connect `gh-ost` to said replica and pass `--migrate-on-replica`. `gh-ost` will briefly connect to the master but other issue no changes on the master. Migration will be fully executed on the replica, while making sure to maintain a small replication lag. +### postpone-cut-over-flag-file + +Indicate a file name, such that the final [cut-over](cut-over.md) step does not take place as long as the file exists. +When this flag is set, `gh-ost` expects the file to exist on startup, or else tries to create it. `gh-ost` exits with error if the file does not exist and `gh-ost` is unable to create it. +With this flag set, the migration will cut-over upon deletion of the file or upon `cut-over` [interactive command](interactive-commands.md). + ### skip-foreign-key-checks By default `gh-ost` verifies no foreign keys exist on the migrated table. On servers with large number of tables this check can take a long time. If you're absolutely certain no foreign keys exist (table does not referenece other table nor is referenced by other tables) and wish to save the check time, provide with `--skip-foreign-key-checks`. diff --git a/go/base/utils.go b/go/base/utils.go index 890ade5..727bc57 100644 --- a/go/base/utils.go +++ b/go/base/utils.go @@ -37,6 +37,15 @@ func FileExists(fileName string) bool { return false } +func TouchFile(fileName string) error { + f, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE, 0755) + if err != nil { + return (err) + } + defer f.Close() + return nil +} + // StringContainsAll returns true if `s` contains all non empty given `substrings` // The function returns `false` if no non-empty arguments are given. func StringContainsAll(s string, substrings ...string) bool { diff --git a/go/logic/migrator.go b/go/logic/migrator.go index 9bc3a40..b320161 100644 --- a/go/logic/migrator.go +++ b/go/logic/migrator.go @@ -265,6 +265,18 @@ func (this *Migrator) countTableRows() (err error) { return countRowsFunc() } +func (this *Migrator) createFlagFiles() (err error) { + if this.migrationContext.PostponeCutOverFlagFile != "" { + if !base.FileExists(this.migrationContext.PostponeCutOverFlagFile) { + if err := base.TouchFile(this.migrationContext.PostponeCutOverFlagFile); err != nil { + return log.Errorf("--postpone-cut-over-flag-file indicated by gh-ost is unable to create said file: %s", err.Error()) + } + log.Infof("Created postpone-cut-over-flag-file: %s", this.migrationContext.PostponeCutOverFlagFile) + } + } + return nil +} + // Migrate executes the complete migration logic. This is *the* major gh-ost function. func (this *Migrator) Migrate() (err error) { log.Infof("Migrating %s.%s", sql.EscapeName(this.migrationContext.DatabaseName), sql.EscapeName(this.migrationContext.OriginalTableName)) @@ -296,6 +308,9 @@ func (this *Migrator) Migrate() (err error) { if err := this.initiateApplier(); err != nil { return err } + if err := this.createFlagFiles(); err != nil { + return err + } initialLag, _ := this.inspector.getReplicationLag() log.Infof("Waiting for ghost table to be migrated. Current lag is %+v", initialLag) diff --git a/localtests/test.sh b/localtests/test.sh index f0ec9d9..45464b6 100755 --- a/localtests/test.sh +++ b/localtests/test.sh @@ -107,7 +107,6 @@ test_single() { --throttle-query='select timestampdiff(second, min(last_update), now()) < 5 from _gh_ost_test_ghc' \ --serve-socket-file=/tmp/gh-ost.test.sock \ --initially-drop-socket-file \ - --postpone-cut-over-flag-file=/tmp/gh-ost.test.postpone.flag \ --test-on-replica \ --default-retries=1 \ --chunk-size=10 \