Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ type FakeMysqlDaemon struct {
// ReadOnly is the current value of the flag
ReadOnly bool

// SuperReadOnly is the current value of the flag
SuperReadOnly bool

// SetSlavePositionPos is matched against the input of SetSlavePosition.
// If it doesn't match, SetSlavePosition will return an error.
SetSlavePositionPos mysql.Position
Expand Down Expand Up @@ -240,6 +243,13 @@ func (fmd *FakeMysqlDaemon) SetReadOnly(on bool) error {
return nil
}

// SetSuperReadOnly is part of the MysqlDaemon interface
func (fmd *FakeMysqlDaemon) SetSuperReadOnly(on bool) error {
fmd.SuperReadOnly = on
fmd.ReadOnly = on
return nil
}

// StartSlave is part of the MysqlDaemon interface.
func (fmd *FakeMysqlDaemon) StartSlave(hookExtraEnv map[string]string) error {
return fmd.ExecuteSuperQueryList(context.Background(), []string{
Expand Down
1 change: 1 addition & 0 deletions go/vt/mysqlctl/mysql_daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type MysqlDaemon interface {
MasterPosition() (mysql.Position, error)
IsReadOnly() (bool, error)
SetReadOnly(on bool) error
SetSuperReadOnly(on bool) error
SetSlavePosition(ctx context.Context, pos mysql.Position) error
SetMaster(ctx context.Context, masterHost string, masterPort int, slaveStopBefore bool, slaveStartAfter bool) error
WaitForReparentJournal(ctx context.Context, timeCreatedNS int64) error
Expand Down
11 changes: 11 additions & 0 deletions go/vt/mysqlctl/replication.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,17 @@ var (
ErrNotMaster = errors.New("no master status")
)

// SetSuperReadOnly set/unset the super_read_only flag
func (mysqld *Mysqld) SetSuperReadOnly(on bool) error {
query := "SET GLOBAL super_read_only = "
if on {
query += "ON"
} else {
query += "OFF"
}
return mysqld.ExecuteSuperQuery(context.TODO(), query)
}

// WaitMasterPos lets slaves wait to given replication position
func (mysqld *Mysqld) WaitMasterPos(ctx context.Context, targetPos mysql.Position) error {
// Get a connection.
Expand Down
26 changes: 20 additions & 6 deletions go/vt/vttablet/tabletmanager/rpc_replication.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ import (
)

var (
enableSemiSync = flag.Bool("enable_semi_sync", false, "Enable semi-sync when configuring replication, on master and replica tablets only (rdonly tablets will not ack).")
enableSemiSync = flag.Bool("enable_semi_sync", false, "Enable semi-sync when configuring replication, on master and replica tablets only (rdonly tablets will not ack).")
setSuperReadOnly = flag.Bool("use_super_read_only", false, "Set super_read_only flag when performing planned failover.")
)

// SlaveStatus returns the replication status
Expand Down Expand Up @@ -331,17 +332,29 @@ func (agent *ActionAgent) DemoteMaster(ctx context.Context) (string, error) {

// Now, set the server read-only. Note all active connections are not
// affected.
if err := agent.MysqlDaemon.SetReadOnly(true); err != nil {
// if this failed, revert the change to serving
if _ /* state changed */, err1 := agent.QueryServiceControl.SetServingType(tablet.Type, true, nil); err1 != nil {
log.Warningf("SetServingType(serving=true) failed after failed SetReadOnly %v", err1)
if *setSuperReadOnly {
// Setting super_read_only also sets read_only
if err := agent.MysqlDaemon.SetSuperReadOnly(true); err != nil {
// if this failed, revert the change to serving
if _ /* state changed */, err1 := agent.QueryServiceControl.SetServingType(tablet.Type, true, nil); err1 != nil {
log.Warningf("SetServingType(serving=true) failed after failed SetSuperReadOnly %v", err1)
}
return "", err
}
} else {
if err := agent.MysqlDaemon.SetReadOnly(true); err != nil {
// if this failed, revert the change to serving
if _ /* state changed */, err1 := agent.QueryServiceControl.SetServingType(tablet.Type, true, nil); err1 != nil {
log.Warningf("SetServingType(serving=true) failed after failed SetReadOnly %v", err1)
}
return "", err
}
return "", err
}

// If using semi-sync, we need to disable master-side.
if err := agent.fixSemiSync(topodatapb.TabletType_REPLICA); err != nil {
// if this failed, set server read-only back to false, set tablet back to serving
// setting read_only OFF will also set super_read_only OFF if it was set
if err1 := agent.MysqlDaemon.SetReadOnly(false); err1 != nil {
log.Warningf("SetReadOnly(false) failed after failed fixSemiSync %v", err1)
}
Expand All @@ -355,6 +368,7 @@ func (agent *ActionAgent) DemoteMaster(ctx context.Context) (string, error) {
if err != nil {
// if DemoteMaster failed, undo all the steps before
// 1. set server back to read-only false
// setting read_only OFF will also set super_read_only OFF if it was set
if err1 := agent.MysqlDaemon.SetReadOnly(false); err1 != nil {
log.Warningf("SetReadOnly(false) failed after failed DemoteMaster %v", err1)
}
Expand Down