Skip to content

Commit 5375aa4

Browse files
author
Shlomi Noach
committed
- Removed use of master_pos_wait(). It was unneccessary in the first place and introduced new problems.
- Supporting `--allow-nullable-unique-key` - Tool will bail out if chosen key has nullable columns and the above is not provided - Fixed `OriginalBinlogRowImage` comaprison (lower/upper case issue) - Introduced reasonable streamer reconnect sleep time
1 parent 9b54d02 commit 5375aa4

File tree

6 files changed

+35
-18
lines changed

6 files changed

+35
-18
lines changed

build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/bash
22
#
33
#
4-
RELEASE_VERSION="0.7.13"
4+
RELEASE_VERSION="0.7.16"
55

66
buildpath=/tmp/gh-ost
77
target=gh-ost

go/base/context.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ type MigrationContext struct {
3939
OriginalTableName string
4040
AlterStatement string
4141

42-
CountTableRows bool
43-
AllowedRunningOnMaster bool
44-
SwitchToRowBinlogFormat bool
42+
CountTableRows bool
43+
AllowedRunningOnMaster bool
44+
SwitchToRowBinlogFormat bool
45+
NullableUniqueKeyAllowed bool
4546

4647
config ContextConfig
4748
configMutex *sync.Mutex

go/cmd/gh-ost/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func main() {
3232
flag.StringVar(&migrationContext.AlterStatement, "alter", "", "alter statement (mandatory)")
3333
flag.BoolVar(&migrationContext.CountTableRows, "exact-rowcount", false, "actually count table rows as opposed to estimate them (results in more accurate progress estimation)")
3434
flag.BoolVar(&migrationContext.AllowedRunningOnMaster, "allow-on-master", false, "allow this migration to run directly on master. Preferably it would run on a replica")
35+
flag.BoolVar(&migrationContext.NullableUniqueKeyAllowed, "allow-nullable-unique-key", false, "allow gh-ost to migrate based on a unique key with nullable columns. As long as no NULL values exist, this should be OK. If NULL values exist in chosen key, data may be corrupted. Use at your own risk!")
3536

3637
executeFlag := flag.Bool("execute", false, "actually execute the alter & migrate the table. Default is noop: do some tests and exit")
3738
flag.BoolVar(&migrationContext.TestOnReplica, "test-on-replica", false, "Have the migration run on a replica, not on the master. At the end of migration tables are not swapped; gh-ost issues `STOP SLAVE` and you can compare the two tables for building trust")

go/logic/applier.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,17 @@ func (this *Applier) StopSlaveIOThread() error {
549549
return nil
550550
}
551551

552+
// StartSlaveSQLThread is applicable with --test-on-replica
553+
func (this *Applier) StartSlaveSQLThread() error {
554+
query := `start /* gh-ost */ slave sql_thread`
555+
log.Infof("Verifying SQL thread is running")
556+
if _, err := sqlutils.ExecNoPrepare(this.db, query); err != nil {
557+
return err
558+
}
559+
log.Infof("SQL thread started")
560+
return nil
561+
}
562+
552563
// MasterPosWait is applicable with --test-on-replica
553564
func (this *Applier) MasterPosWait(binlogCoordinates *mysql.BinlogCoordinates) error {
554565
var appliedRows int64
@@ -565,22 +576,14 @@ func (this *Applier) StopSlaveNicely() error {
565576
if err := this.StopSlaveIOThread(); err != nil {
566577
return err
567578
}
579+
if err := this.StartSlaveSQLThread(); err != nil {
580+
return err
581+
}
568582
readBinlogCoordinates, executeBinlogCoordinates, err := mysql.GetReplicationBinlogCoordinates(this.db)
569583
if err != nil {
570584
return err
571585
}
572586
log.Infof("Replication IO thread at %+v. SQL thread is at %+v", *readBinlogCoordinates, *executeBinlogCoordinates)
573-
log.Infof("Will wait for SQL thread to catch up with IO thread")
574-
if err := this.MasterPosWait(readBinlogCoordinates); err != nil {
575-
log.Errorf("Error waiting for SQL thread to catch up. Replication IO thread at %+v. SQL thread is at %+v", *readBinlogCoordinates, *executeBinlogCoordinates)
576-
return err
577-
}
578-
log.Infof("Replication SQL thread applied all events up to %+v", *readBinlogCoordinates)
579-
if selfBinlogCoordinates, err := mysql.GetSelfBinlogCoordinates(this.db); err != nil {
580-
return err
581-
} else {
582-
log.Infof("Self binlog coordinates: %+v", *selfBinlogCoordinates)
583-
}
584587
return nil
585588
}
586589

go/logic/inspect.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,16 @@ func (this *Inspector) InspectOriginalAndGhostTables() (err error) {
113113
}
114114
this.migrationContext.UniqueKey = sharedUniqueKeys[0]
115115
log.Infof("Chosen shared unique key is %s", this.migrationContext.UniqueKey.Name)
116+
if this.migrationContext.UniqueKey.HasNullable {
117+
if this.migrationContext.NullableUniqueKeyAllowed {
118+
log.Warningf("Chosen key (%s) has nullable columns. You have supplied with --allow-nullable-unique-key and so this migration proceeds. As long as there aren't NULL values in this key's column, migration should be fine. NULL values will corrupt migration's data", this.migrationContext.UniqueKey)
119+
} else {
120+
return fmt.Errorf("Chosen key (%s) has nullable columns. Bailing out. To force this operation to continue, supply --allow-nullable-unique-key flag. Only do so if you are certain there are no actual NULL values in this key. As long as there aren't, migration should be fine. NULL values in columns of this key will corrupt migration's data", this.migrationContext.UniqueKey)
121+
}
122+
}
116123
if !this.migrationContext.UniqueKey.IsPrimary() {
117-
if this.migrationContext.OriginalBinlogRowImage != "full" {
118-
return fmt.Errorf("binlog_row_image is '%s' and chosen key is %s, which is not the primary key. This operation cannot proceed. You may `set global binlog_row_image='full'` and try again")
124+
if this.migrationContext.OriginalBinlogRowImage != "FULL" {
125+
return fmt.Errorf("binlog_row_image is '%s' and chosen key is %s, which is not the primary key. This operation cannot proceed. You may `set global binlog_row_image='full'` and try again", this.migrationContext.OriginalBinlogRowImage, this.migrationContext.UniqueKey)
119126
}
120127
}
121128

@@ -261,6 +268,7 @@ func (this *Inspector) validateBinlogs() error {
261268
// Only as of 5.6. We wish to support 5.5 as well
262269
this.migrationContext.OriginalBinlogRowImage = ""
263270
}
271+
this.migrationContext.OriginalBinlogRowImage = strings.ToUpper(this.migrationContext.OriginalBinlogRowImage)
264272

265273
log.Infof("binary logs validated on %s:%d", this.connectionConfig.Key.Hostname, this.connectionConfig.Key.Port)
266274
return nil

go/logic/streamer.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"fmt"
1111
"strings"
1212
"sync"
13+
"time"
1314

1415
"github.com/github/gh-ost/go/base"
1516
"github.com/github/gh-ost/go/binlog"
@@ -27,7 +28,8 @@ type BinlogEventListener struct {
2728
}
2829

2930
const (
30-
EventsChannelBufferSize = 1
31+
EventsChannelBufferSize = 1
32+
ReconnectStreamerSleepSeconds = 5
3133
)
3234

3335
// EventsStreamer reads data from binary logs and streams it on. It acts as a publisher,
@@ -177,6 +179,8 @@ func (this *EventsStreamer) StreamEvents(canStopStreaming func() bool) error {
177179
if err := this.binlogReader.StreamEvents(canStopStreaming, this.eventsChannel); err != nil {
178180
// Reposition at same coordinates. Single attempt (TODO: make multiple attempts?)
179181
log.Infof("StreamEvents encountered unexpected error: %+v", err)
182+
time.Sleep(ReconnectStreamerSleepSeconds * time.Second)
183+
log.Infof("Reconnecting...")
180184
err = this.binlogReader.Reconnect()
181185
if err != nil {
182186
return err

0 commit comments

Comments
 (0)