gh-ost/vendor/github.com/siddontang/go-mysql/failover/failover.go
2017-02-12 13:13:54 +02:00

69 lines
1.8 KiB
Go

package failover
import (
"github.com/juju/errors"
"github.com/siddontang/go-mysql/mysql"
)
// Failover will do below things after the master down
// 1. Elect a slave which has the most up-to-date data with old master
// 2. Promote the slave to new master
// 3. Change other slaves to the new master
//
// Limitation:
// 1, All slaves must have the same master before, Failover will check using master server id or uuid
// 2, If the failover error, the whole topology may be wrong, we must handle this error manually
// 3, Slaves must have same replication mode, all use GTID or not
//
func Failover(flavor string, slaves []*Server) ([]*Server, error) {
var h Handler
var err error
switch flavor {
case mysql.MySQLFlavor:
h = new(MysqlGTIDHandler)
case mysql.MariaDBFlavor:
return nil, errors.Errorf("MariaDB failover is not supported now")
default:
return nil, errors.Errorf("invalid flavor %s", flavor)
}
// First check slaves use gtid or not
if err := h.CheckGTIDMode(slaves); err != nil {
return nil, errors.Trace(err)
}
// Stop all slave IO_THREAD and wait the relay log done
for _, slave := range slaves {
if err = h.WaitRelayLogDone(slave); err != nil {
return nil, errors.Trace(err)
}
}
var bestSlave *Server
// Find best slave which has the most up-to-data data
if bestSlaves, err := h.FindBestSlaves(slaves); err != nil {
return nil, errors.Trace(err)
} else {
bestSlave = bestSlaves[0]
}
// Promote the best slave to master
if err = h.Promote(bestSlave); err != nil {
return nil, errors.Trace(err)
}
// Change master
for i := 0; i < len(slaves); i++ {
if bestSlave == slaves[i] {
continue
}
if err = h.ChangeMasterTo(slaves[i], bestSlave); err != nil {
return nil, errors.Trace(err)
}
}
return slaves, nil
}