Skip to content

Commit 1445bb4

Browse files
authored
Merge branch 'master' into ob-compatibility
2 parents 13889d3 + 48cb9ab commit 1445bb4

File tree

7 files changed

+46
-23
lines changed

7 files changed

+46
-23
lines changed

doc/command-line-flags.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,6 @@ List of metrics and threshold values; topping the threshold of any will cause th
202202

203203
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 otherwise will make no changes on the master. Migration will be fully executed on the replica, while making sure to maintain a small replication lag.
204204

205-
### mysql-wait-timeout
206-
207-
If set to a value greater than zero, causes `gh-ost` to set a provided [MySQL `wait_timeout`](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_wait_timeout) for MySQL sessions opened by `gh-ost`, specified in seconds.
208-
209205
### postpone-cut-over-flag-file
210206

211207
Indicate a file name, such that the final [cut-over](cut-over.md) step does not take place as long as the file exists.

go/base/context.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ type MigrationContext struct {
165165
Hostname string
166166
AssumeMasterHostname string
167167
ApplierTimeZone string
168+
ApplierWaitTimeout int64
168169
TableEngine string
169170
RowsEstimate int64
170171
RowsDeltaEstimate int64

go/cmd/gh-ost/main.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ func main() {
5151
flag.StringVar(&migrationContext.AssumeMasterHostname, "assume-master-host", "", "(optional) explicitly tell gh-ost the identity of the master. Format: some.host.com[:port] This is useful in master-master setups where you wish to pick an explicit master, or in a tungsten-replicator where gh-ost is unable to determine the master")
5252
flag.IntVar(&migrationContext.InspectorConnectionConfig.Key.Port, "port", 3306, "MySQL port (preferably a replica, not the master)")
5353
flag.Float64Var(&migrationContext.InspectorConnectionConfig.Timeout, "mysql-timeout", 0.0, "Connect, read and write timeout for MySQL")
54-
flag.Float64Var(&migrationContext.InspectorConnectionConfig.WaitTimeout, "mysql-wait-timeout", 0.0, "wait_timeout for MySQL sessions")
5554
flag.StringVar(&migrationContext.CliUser, "user", "", "MySQL user")
5655
flag.StringVar(&migrationContext.CliPassword, "password", "", "MySQL password")
5756
flag.StringVar(&migrationContext.CliMasterUser, "master-user", "", "MySQL user on master, if different from that on replica. Requires --assume-master-host")

go/logic/applier.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func (this *Applier) InitDBConnections() (err error) {
8989
return err
9090
}
9191
this.migrationContext.ApplierMySQLVersion = version
92-
if err := this.validateAndReadTimeZone(); err != nil {
92+
if err := this.validateAndReadGlobalVariables(); err != nil {
9393
return err
9494
}
9595
if !this.migrationContext.AliyunRDS && !this.migrationContext.GoogleCloudPlatform && !this.migrationContext.AzureMySQL && !this.migrationContext.OceanBaseBinlogService {
@@ -106,10 +106,13 @@ func (this *Applier) InitDBConnections() (err error) {
106106
return nil
107107
}
108108

109-
// validateAndReadTimeZone potentially reads server time-zone
110-
func (this *Applier) validateAndReadTimeZone() error {
111-
query := `select /* gh-ost */ @@global.time_zone`
112-
if err := this.db.QueryRow(query).Scan(&this.migrationContext.ApplierTimeZone); err != nil {
109+
// validateAndReadGlobalVariables potentially reads server global variables, such as the time_zone and wait_timeout.
110+
func (this *Applier) validateAndReadGlobalVariables() error {
111+
query := `select /* gh-ost */ @@global.time_zone, @@global.wait_timeout`
112+
if err := this.db.QueryRow(query).Scan(
113+
&this.migrationContext.ApplierTimeZone,
114+
&this.migrationContext.ApplierWaitTimeout,
115+
); err != nil {
113116
return err
114117
}
115118

@@ -938,6 +941,27 @@ func (this *Applier) CreateAtomicCutOverSentryTable() error {
938941
return nil
939942
}
940943

944+
// InitAtomicCutOverWaitTimeout sets the cut-over session wait_timeout in order to reduce the
945+
// time an unresponsive (but still connected) gh-ost process can hold the cut-over lock.
946+
func (this *Applier) InitAtomicCutOverWaitTimeout(tx *gosql.Tx) error {
947+
cutOverWaitTimeoutSeconds := this.migrationContext.CutOverLockTimeoutSeconds * 3
948+
this.migrationContext.Log.Infof("Setting cut-over idle timeout as %d seconds", cutOverWaitTimeoutSeconds)
949+
query := fmt.Sprintf(`set /* gh-ost */ session wait_timeout:=%d`, cutOverWaitTimeoutSeconds)
950+
_, err := tx.Exec(query)
951+
return err
952+
}
953+
954+
// RevertAtomicCutOverWaitTimeout restores the original wait_timeout for the applier session post-cut-over.
955+
func (this *Applier) RevertAtomicCutOverWaitTimeout() {
956+
this.migrationContext.Log.Infof("Reverting cut-over idle timeout to %d seconds", this.migrationContext.ApplierWaitTimeout)
957+
query := fmt.Sprintf(`set /* gh-ost */ session wait_timeout:=%d`, this.migrationContext.ApplierWaitTimeout)
958+
if _, err := sqlutils.ExecNoPrepare(this.db, query); err != nil {
959+
this.migrationContext.Log.Errorf("Failed to restore applier wait_timeout to %d seconds: %v",
960+
this.migrationContext.ApplierWaitTimeout, err,
961+
)
962+
}
963+
}
964+
941965
// AtomicCutOverMagicLock
942966
func (this *Applier) AtomicCutOverMagicLock(sessionIdChan chan int64, tableLocked chan<- error, okToUnlockTable <-chan bool, tableUnlocked chan<- error) error {
943967
tx, err := this.db.Begin()
@@ -983,6 +1007,12 @@ func (this *Applier) AtomicCutOverMagicLock(sessionIdChan chan int64, tableLocke
9831007
return err
9841008
}
9851009

1010+
if err := this.InitAtomicCutOverWaitTimeout(tx); err != nil {
1011+
tableLocked <- err
1012+
return err
1013+
}
1014+
defer this.RevertAtomicCutOverWaitTimeout()
1015+
9861016
query = fmt.Sprintf(`lock /* gh-ost */ tables %s.%s write, %s.%s write`,
9871017
sql.EscapeName(this.migrationContext.DatabaseName),
9881018
sql.EscapeName(this.migrationContext.OriginalTableName),

go/logic/migrator.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -367,12 +367,16 @@ func (this *Migrator) Migrate() (err error) {
367367
// In MySQL 8.0 (and possibly earlier) some DDL statements can be applied instantly.
368368
// Attempt to do this if AttemptInstantDDL is set.
369369
if this.migrationContext.AttemptInstantDDL {
370-
this.migrationContext.Log.Infof("Attempting to execute alter with ALGORITHM=INSTANT")
371-
if err := this.applier.AttemptInstantDDL(); err == nil {
372-
this.migrationContext.Log.Infof("Success! table %s.%s migrated instantly", sql.EscapeName(this.migrationContext.DatabaseName), sql.EscapeName(this.migrationContext.OriginalTableName))
373-
return nil
370+
if this.migrationContext.Noop {
371+
this.migrationContext.Log.Debugf("Noop operation; not really attempting instant DDL")
374372
} else {
375-
this.migrationContext.Log.Infof("ALGORITHM=INSTANT not supported for this operation, proceeding with original algorithm: %s", err)
373+
this.migrationContext.Log.Infof("Attempting to execute alter with ALGORITHM=INSTANT")
374+
if err := this.applier.AttemptInstantDDL(); err == nil {
375+
this.migrationContext.Log.Infof("Success! table %s.%s migrated instantly", sql.EscapeName(this.migrationContext.DatabaseName), sql.EscapeName(this.migrationContext.OriginalTableName))
376+
return nil
377+
} else {
378+
this.migrationContext.Log.Infof("ALGORITHM=INSTANT not supported for this operation, proceeding with original algorithm: %s", err)
379+
}
376380
}
377381
}
378382

go/mysql/connection.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ type ConnectionConfig struct {
3131
Timeout float64
3232
TransactionIsolation string
3333
Charset string
34-
WaitTimeout float64
3534
}
3635

3736
func NewConnectionConfig() *ConnectionConfig {
@@ -52,7 +51,6 @@ func (this *ConnectionConfig) DuplicateCredentials(key InstanceKey) *ConnectionC
5251
Timeout: this.Timeout,
5352
TransactionIsolation: this.TransactionIsolation,
5453
Charset: this.Charset,
55-
WaitTimeout: this.WaitTimeout,
5654
}
5755
config.ImpliedKey = &config.Key
5856
return config
@@ -141,9 +139,6 @@ func (this *ConnectionConfig) GetDBUri(databaseName string) string {
141139
fmt.Sprintf("readTimeout=%fs", this.Timeout),
142140
fmt.Sprintf("writeTimeout=%fs", this.Timeout),
143141
}
144-
if this.WaitTimeout > 0 {
145-
connectionParams = append(connectionParams, fmt.Sprintf("wait_timeout=%fs", this.WaitTimeout))
146-
}
147142

148143
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?%s", this.User, this.Password, hostname, this.Key.Port, databaseName, strings.Join(connectionParams, "&"))
149144
}

go/mysql/connection_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ func TestGetDBUri(t *testing.T) {
8282
c.User = "gromit"
8383
c.Password = "penguin"
8484
c.Timeout = 1.2345
85-
c.WaitTimeout = 0 // should be ignored
8685
c.TransactionIsolation = transactionIsolation
8786
c.Charset = "utf8mb4,utf8,latin1"
8887

@@ -96,11 +95,10 @@ func TestGetDBUriWithTLSSetup(t *testing.T) {
9695
c.User = "gromit"
9796
c.Password = "penguin"
9897
c.Timeout = 1.2345
99-
c.WaitTimeout = 60
10098
c.tlsConfig = &tls.Config{}
10199
c.TransactionIsolation = transactionIsolation
102100
c.Charset = "utf8mb4_general_ci,utf8_general_ci,latin1"
103101

104102
uri := c.GetDBUri("test")
105-
test.S(t).ExpectEquals(uri, `gromit:penguin@tcp(myhost:3306)/test?autocommit=true&interpolateParams=true&charset=utf8mb4_general_ci,utf8_general_ci,latin1&tls=ghost&transaction_isolation="REPEATABLE-READ"&timeout=1.234500s&readTimeout=1.234500s&writeTimeout=1.234500s&wait_timeout=60.000000s`)
103+
test.S(t).ExpectEquals(uri, `gromit:penguin@tcp(myhost:3306)/test?autocommit=true&interpolateParams=true&charset=utf8mb4_general_ci,utf8_general_ci,latin1&tls=ghost&transaction_isolation="REPEATABLE-READ"&timeout=1.234500s&readTimeout=1.234500s&writeTimeout=1.234500s`)
106104
}

0 commit comments

Comments
 (0)