accepting --trust-rbr
- avoiding need to restart replication - in turn avoiding need for SUPER
This commit is contained in:
parent
98f6ddf00c
commit
1995be2b3f
@ -51,6 +51,7 @@ type MigrationContext struct {
|
|||||||
AllowedRunningOnMaster bool
|
AllowedRunningOnMaster bool
|
||||||
AllowedMasterMaster bool
|
AllowedMasterMaster bool
|
||||||
SwitchToRowBinlogFormat bool
|
SwitchToRowBinlogFormat bool
|
||||||
|
TrustRBR bool
|
||||||
NullableUniqueKeyAllowed bool
|
NullableUniqueKeyAllowed bool
|
||||||
ApproveRenamedColumns bool
|
ApproveRenamedColumns bool
|
||||||
SkipRenamedColumns bool
|
SkipRenamedColumns bool
|
||||||
@ -92,6 +93,7 @@ type MigrationContext struct {
|
|||||||
TableEngine string
|
TableEngine string
|
||||||
RowsEstimate int64
|
RowsEstimate int64
|
||||||
UsedRowsEstimateMethod RowsEstimateMethod
|
UsedRowsEstimateMethod RowsEstimateMethod
|
||||||
|
HasSuperPrivilege bool
|
||||||
OriginalBinlogFormat string
|
OriginalBinlogFormat string
|
||||||
OriginalBinlogRowImage string
|
OriginalBinlogRowImage string
|
||||||
InspectorConnectionConfig *mysql.ConnectionConfig
|
InspectorConnectionConfig *mysql.ConnectionConfig
|
||||||
|
@ -69,6 +69,7 @@ func main() {
|
|||||||
cutOver := flag.String("cut-over", "atomic", "choose cut-over type (default|atomic, two-step)")
|
cutOver := flag.String("cut-over", "atomic", "choose cut-over type (default|atomic, two-step)")
|
||||||
|
|
||||||
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")
|
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")
|
||||||
|
flag.BoolVar(&migrationContext.TrustRBR, "trust-rbr", false, "set to 'true' when you know for certain your server uses 'ROW' binlog_format. gh-ost is unable to tell, event after reading binlog_format, whether the replication process does indeed use 'ROW', and restarts replication to be certain RBR setting is applied. Such operation requires SUPER privileges which you might not have. Setting this flag avoids restarting replication and you can proceed to use gh-ost without SUPER privileges")
|
||||||
chunkSize := flag.Int64("chunk-size", 1000, "amount of rows to handle in each iteration (allowed range: 100-100,000)")
|
chunkSize := flag.Int64("chunk-size", 1000, "amount of rows to handle in each iteration (allowed range: 100-100,000)")
|
||||||
defaultRetries := flag.Int64("default-retries", 60, "Default number of retries for various operations before panicking")
|
defaultRetries := flag.Int64("default-retries", 60, "Default number of retries for various operations before panicking")
|
||||||
cutOverLockTimeoutSeconds := flag.Int64("cut-over-lock-timeout-seconds", 3, "Max number of seconds to hold locks on tables while attempting to cut-over (retry attempted when lock exceeds timeout)")
|
cutOverLockTimeoutSeconds := flag.Int64("cut-over-lock-timeout-seconds", 3, "Max number of seconds to hold locks on tables while attempting to cut-over (retry attempted when lock exceeds timeout)")
|
||||||
@ -145,7 +146,9 @@ func main() {
|
|||||||
if migrationContext.MigrateOnReplica && migrationContext.TestOnReplica {
|
if migrationContext.MigrateOnReplica && migrationContext.TestOnReplica {
|
||||||
log.Fatalf("--migrate-on-replica and --test-on-replica are mutually exclusive")
|
log.Fatalf("--migrate-on-replica and --test-on-replica are mutually exclusive")
|
||||||
}
|
}
|
||||||
|
if migrationContext.SwitchToRowBinlogFormat && migrationContext.TrustRBR {
|
||||||
|
log.Fatalf("--switch-to-rbr and --trust-rbr are mutually exclusive")
|
||||||
|
}
|
||||||
switch *cutOver {
|
switch *cutOver {
|
||||||
case "atomic", "default", "":
|
case "atomic", "default", "":
|
||||||
migrationContext.CutOverType = base.CutOverAtomic
|
migrationContext.CutOverType = base.CutOverAtomic
|
||||||
|
@ -50,9 +50,6 @@ func (this *Inspector) InitDBConnections() (err error) {
|
|||||||
if err := this.validateGrants(); err != nil {
|
if err := this.validateGrants(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// if err := this.restartReplication(); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
if err := this.validateBinlogs(); err != nil {
|
if err := this.validateBinlogs(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -157,6 +154,7 @@ func (this *Inspector) validateGrants() error {
|
|||||||
query := `show /* gh-ost */ grants for current_user()`
|
query := `show /* gh-ost */ grants for current_user()`
|
||||||
foundAll := false
|
foundAll := false
|
||||||
foundSuper := false
|
foundSuper := false
|
||||||
|
foundReplicationClient := false
|
||||||
foundReplicationSlave := false
|
foundReplicationSlave := false
|
||||||
foundDBAll := false
|
foundDBAll := false
|
||||||
|
|
||||||
@ -169,6 +167,9 @@ func (this *Inspector) validateGrants() error {
|
|||||||
if strings.Contains(grant, `SUPER`) && strings.Contains(grant, ` ON *.*`) {
|
if strings.Contains(grant, `SUPER`) && strings.Contains(grant, ` ON *.*`) {
|
||||||
foundSuper = true
|
foundSuper = true
|
||||||
}
|
}
|
||||||
|
if strings.Contains(grant, `REPLICATION CLIENT`) && strings.Contains(grant, ` ON *.*`) {
|
||||||
|
foundReplicationClient = true
|
||||||
|
}
|
||||||
if strings.Contains(grant, `REPLICATION SLAVE`) && strings.Contains(grant, ` ON *.*`) {
|
if strings.Contains(grant, `REPLICATION SLAVE`) && strings.Contains(grant, ` ON *.*`) {
|
||||||
foundReplicationSlave = true
|
foundReplicationSlave = true
|
||||||
}
|
}
|
||||||
@ -187,6 +188,7 @@ func (this *Inspector) validateGrants() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
this.migrationContext.HasSuperPrivilege = foundSuper
|
||||||
|
|
||||||
if foundAll {
|
if foundAll {
|
||||||
log.Infof("User has ALL privileges")
|
log.Infof("User has ALL privileges")
|
||||||
@ -196,7 +198,11 @@ func (this *Inspector) validateGrants() error {
|
|||||||
log.Infof("User has SUPER, REPLICATION SLAVE privileges, and has ALL privileges on %s.*", sql.EscapeName(this.migrationContext.DatabaseName))
|
log.Infof("User has SUPER, REPLICATION SLAVE privileges, and has ALL privileges on %s.*", sql.EscapeName(this.migrationContext.DatabaseName))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Debugf("Privileges: Super: %t, REPLICATION SLAVE: %t, ALL on *.*: %t, ALL on %s.*: %t", foundSuper, foundReplicationSlave, foundAll, sql.EscapeName(this.migrationContext.DatabaseName), foundDBAll)
|
if foundReplicationClient && foundReplicationSlave && foundDBAll {
|
||||||
|
log.Infof("User has REPLICATION CLIENT, REPLICATION SLAVE privileges, and has ALL privileges on %s.*", sql.EscapeName(this.migrationContext.DatabaseName))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
log.Debugf("Privileges: Super: %t, REPLICATION CLIENT: %t, REPLICATION SLAVE: %t, ALL on *.*: %t, ALL on %s.*: %t", foundSuper, foundReplicationClient, foundReplicationSlave, foundAll, sql.EscapeName(this.migrationContext.DatabaseName), foundDBAll)
|
||||||
return log.Errorf("User has insufficient privileges for migration. Needed: SUPER, REPLICATION SLAVE and ALL on %s.*", sql.EscapeName(this.migrationContext.DatabaseName))
|
return log.Errorf("User has insufficient privileges for migration. Needed: SUPER, REPLICATION SLAVE and ALL on %s.*", sql.EscapeName(this.migrationContext.DatabaseName))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,16 +236,26 @@ func (this *Inspector) restartReplication() error {
|
|||||||
// the replication thread apply it.
|
// the replication thread apply it.
|
||||||
func (this *Inspector) applyBinlogFormat() error {
|
func (this *Inspector) applyBinlogFormat() error {
|
||||||
if this.migrationContext.RequiresBinlogFormatChange() {
|
if this.migrationContext.RequiresBinlogFormatChange() {
|
||||||
|
if !this.migrationContext.SwitchToRowBinlogFormat {
|
||||||
|
return fmt.Errorf("Existing binlog_format is %s. Am not switching it to ROW unless you specify --switch-to-rbr", this.migrationContext.OriginalBinlogFormat)
|
||||||
|
}
|
||||||
if _, err := sqlutils.ExecNoPrepare(this.db, `set global binlog_format='ROW'`); err != nil {
|
if _, err := sqlutils.ExecNoPrepare(this.db, `set global binlog_format='ROW'`); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := sqlutils.ExecNoPrepare(this.db, `set session binlog_format='ROW'`); err != nil {
|
if _, err := sqlutils.ExecNoPrepare(this.db, `set session binlog_format='ROW'`); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := this.restartReplication(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
log.Debugf("'ROW' binlog format applied")
|
log.Debugf("'ROW' binlog format applied")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if err := this.restartReplication(); err != nil {
|
// We already have RBR, no explicit switch
|
||||||
return err
|
if !this.migrationContext.TrustRBR {
|
||||||
|
if err := this.restartReplication(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user