Skip to content

Commit 57347ec

Browse files
author
Shlomi Noach
authored
Merge pull request #51 from github/cut-over
cut-over flag and other stuff
2 parents 78a39d9 + bbd19ab commit 57347ec

File tree

5 files changed

+58
-18
lines changed

5 files changed

+58
-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.8.2"
4+
RELEASE_VERSION="0.8.3"
55

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

go/base/context.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ const (
2828
CountRowsEstimate = "CountRowsEstimate"
2929
)
3030

31+
type CutOver int
32+
33+
const (
34+
CutOverTwoStep CutOver = 1
35+
CutOverVoluntaryLock
36+
CutOverUdfWait
37+
)
38+
3139
const (
3240
maxRetries = 10
3341
)
@@ -63,9 +71,9 @@ type MigrationContext struct {
6371
Noop bool
6472
TestOnReplica bool
6573
OkToDropTable bool
66-
QuickAndBumpySwapTables bool
6774
InitiallyDropOldTable bool
6875
InitiallyDropGhostTable bool
76+
CutOverType CutOver
6977

7078
TableEngine string
7179
RowsEstimate int64

go/cmd/gh-ost/main.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ func main() {
5959
executeFlag := flag.Bool("execute", false, "actually execute the alter & migrate the table. Default is noop: do some tests and exit")
6060
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")
6161
flag.BoolVar(&migrationContext.OkToDropTable, "ok-to-drop-table", false, "Shall the tool drop the old table at end of operation. DROPping tables can be a long locking operation, which is why I'm not doing it by default. I'm an online tool, yes?")
62-
flag.BoolVar(&migrationContext.QuickAndBumpySwapTables, "quick-and-bumpy-swap-tables", false, "Shall the tool issue a faster swapping of tables at end of operation, at the cost of causing a brief period of time when the table does not exist? This will cause queries on table to fail with error (as opposed to being locked for a longer duration of a swap)")
6362
flag.BoolVar(&migrationContext.InitiallyDropOldTable, "initially-drop-old-table", false, "Drop a possibly existing OLD table (remains from a previous run?) before beginning operation. Default is to panic and abort if such table exists")
6463
flag.BoolVar(&migrationContext.InitiallyDropGhostTable, "initially-drop-ghost-table", false, "Drop a possibly existing Ghost table (remains from a previous run?) before beginning operation. Default is to panic and abort if such table exists")
64+
cutOver := flag.String("cut-over", "", "(mandatory) choose cut-over type (two-step, voluntary-lock)")
6565

6666
flag.BoolVar(&migrationContext.SwitchToRowBinlogFormat, "switch-to-rbr", false, "let this tool automatically switch binary log format to 'ROW' on the replica, if needed. The format will NOT be switched back. I'm too scared to do that, and wish to protect you if you happen to execute another migration while this one is running")
6767
flag.Int64Var(&migrationContext.ChunkSize, "chunk-size", 1000, "amount of rows to handle in each iteration (allowed range: 100-100,000)")
@@ -129,8 +129,15 @@ func main() {
129129
if migrationContext.AllowedRunningOnMaster && migrationContext.TestOnReplica {
130130
log.Fatalf("--allow-on-master and --test-on-replica are mutually exclusive")
131131
}
132-
if migrationContext.QuickAndBumpySwapTables && migrationContext.TestOnReplica {
133-
log.Fatalf("--quick-and-bumpy-swap-tables and --test-on-replica are mutually exclusive (the former implies migrating on master)")
132+
switch *cutOver {
133+
case "two-step":
134+
migrationContext.CutOverType = base.CutOverTwoStep
135+
case "voluntary-lock":
136+
migrationContext.CutOverType = base.CutOverVoluntaryLock
137+
case "":
138+
log.Fatalf("--cut-over must be specified")
139+
default:
140+
log.Fatalf("Unknown cut-over: %s", *cutOver)
134141
}
135142
if err := migrationContext.ReadConfigFile(); err != nil {
136143
log.Fatale(err)

go/logic/inspect.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,8 @@ func (this *Inspector) ValidateOriginalTable() (err error) {
6363
if err := this.validateTableForeignKeys(); err != nil {
6464
return err
6565
}
66-
if this.migrationContext.CountTableRows {
67-
if err := this.countTableRows(); err != nil {
68-
return err
69-
}
70-
} else {
71-
if err := this.estimateTableRowsViaExplain(); err != nil {
72-
return err
73-
}
66+
if err := this.estimateTableRowsViaExplain(); err != nil {
67+
return err
7468
}
7569
return nil
7670
}
@@ -99,6 +93,8 @@ func (this *Inspector) InspectOriginalTable() (err error) {
9993
return nil
10094
}
10195

96+
// InspectOriginalAndGhostTables compares original and ghost tables to see whether the migration
97+
// makes sense and is valid. It extracts the list of shared columns and the chosen migration unique key
10298
func (this *Inspector) InspectOriginalAndGhostTables() (err error) {
10399
this.migrationContext.GhostTableColumns, this.migrationContext.GhostTableUniqueKeys, err = this.InspectTableColumnsAndUniqueKeys(this.migrationContext.GetGhostTableName())
104100
if err != nil {
@@ -353,7 +349,7 @@ func (this *Inspector) estimateTableRowsViaExplain() error {
353349
return nil
354350
}
355351

356-
func (this *Inspector) countTableRows() error {
352+
func (this *Inspector) CountTableRows() error {
357353
log.Infof("As instructed, I'm issuing a SELECT COUNT(*) on the table. This may take a while")
358354
query := fmt.Sprintf(`select /* gh-ost */ count(*) as rows from %s.%s`, sql.EscapeName(this.migrationContext.DatabaseName), sql.EscapeName(this.migrationContext.OriginalTableName))
359355
if err := this.db.QueryRow(query).Scan(&this.migrationContext.RowsEstimate); err != nil {

go/logic/migrator.go

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type Migrator struct {
5151

5252
rowCopyCompleteFlag int64
5353
allEventsUpToLockProcessedInjectedFlag int64
54+
cleanupImminentFlag int64
5455
// copyRowsQueue should not be buffered; if buffered some non-damaging but
5556
// excessive work happens at the end of the iteration as new copy-jobs arrive befroe realizing the copy is complete
5657
copyRowsQueue chan tableWriteFunc
@@ -312,6 +313,14 @@ func (this *Migrator) Migrate() (err error) {
312313
if err := this.inspector.InspectOriginalAndGhostTables(); err != nil {
313314
return err
314315
}
316+
if this.migrationContext.CountTableRows {
317+
if this.migrationContext.Noop {
318+
log.Debugf("Noop operation; not really counting table rows")
319+
} else if err := this.inspector.CountTableRows(); err != nil {
320+
return err
321+
}
322+
}
323+
315324
if err := this.addDMLEventsListener(); err != nil {
316325
return err
317326
}
@@ -371,7 +380,7 @@ func (this *Migrator) stopWritesAndCompleteMigration() (err error) {
371380
return this.stopWritesAndCompleteMigrationOnReplica()
372381
}
373382
// Running on master
374-
if this.migrationContext.QuickAndBumpySwapTables {
383+
if this.migrationContext.CutOverType == base.CutOverTwoStep {
375384
return this.stopWritesAndCompleteMigrationOnMasterQuickAndBumpy()
376385
}
377386

@@ -555,14 +564,30 @@ func (this *Migrator) initiateStatus() error {
555564
}
556565

557566
func (this *Migrator) printMigrationStatusHint() {
558-
hint := fmt.Sprintf("# Migrating %s.%s; Ghost table is %s.%s; migration started at %+v",
567+
fmt.Println(fmt.Sprintf("# Migrating %s.%s; Ghost table is %s.%s",
559568
sql.EscapeName(this.migrationContext.DatabaseName),
560569
sql.EscapeName(this.migrationContext.OriginalTableName),
561570
sql.EscapeName(this.migrationContext.DatabaseName),
562571
sql.EscapeName(this.migrationContext.GetGhostTableName()),
572+
))
573+
fmt.Println(fmt.Sprintf("# Migration started at %+v",
563574
this.migrationContext.StartTime.Format(time.RubyDate),
564-
)
565-
fmt.Println(hint)
575+
))
576+
fmt.Println(fmt.Sprintf("# chunk-size: %+v; max lag: %+vms; max-load: %+v",
577+
atomic.LoadInt64(&this.migrationContext.ChunkSize),
578+
atomic.LoadInt64(&this.migrationContext.MaxLagMillisecondsThrottleThreshold),
579+
this.migrationContext.MaxLoad,
580+
))
581+
if this.migrationContext.ThrottleFlagFile != "" {
582+
fmt.Println(fmt.Sprintf("# Throttle flag file: %+v",
583+
this.migrationContext.ThrottleFlagFile,
584+
))
585+
}
586+
if this.migrationContext.ThrottleAdditionalFlagFile != "" {
587+
fmt.Println(fmt.Sprintf("# Throttle additional flag file: %+v",
588+
this.migrationContext.ThrottleAdditionalFlagFile,
589+
))
590+
}
566591
}
567592

568593
func (this *Migrator) printStatus() {
@@ -638,6 +663,9 @@ func (this *Migrator) initiateHeartbeatListener() {
638663
ticker := time.Tick((heartbeatIntervalMilliseconds * time.Millisecond) / 2)
639664
for range ticker {
640665
go func() error {
666+
if atomic.LoadInt64(&this.cleanupImminentFlag) > 0 {
667+
return nil
668+
}
641669
changelogState, err := this.inspector.readChangelogState()
642670
if err != nil {
643671
return log.Errore(err)
@@ -808,6 +836,7 @@ func (this *Migrator) executeWriteFuncs() error {
808836

809837
// finalCleanup takes actions at very end of migration, dropping tables etc.
810838
func (this *Migrator) finalCleanup() error {
839+
atomic.StoreInt64(&this.cleanupImminentFlag, 1)
811840
if err := this.retryOperation(this.applier.DropChangelogTable); err != nil {
812841
return err
813842
}

0 commit comments

Comments
 (0)