Skip to content

Commit 61bfe4e

Browse files
author
Guillaume Lefranc
committed
Initial support for multimaster
1 parent b17f8a0 commit 61bfe4e

File tree

4 files changed

+68
-24
lines changed

4 files changed

+68
-24
lines changed

failover.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ func masterFailover(fail bool) {
4141
}
4242
master = servers[skey]
4343
master.State = stateMaster
44-
slaves[key].delete(&slaves)
44+
if multiMaster == false {
45+
slaves[key].delete(&slaves)
46+
}
4547
// Call pre-failover script
4648
if preScript != "" {
4749
logprintf("INFO : Calling pre-failover script")
@@ -75,10 +77,12 @@ func masterFailover(fail bool) {
7577
}
7678
}
7779
// Phase 3: Prepare new master
78-
logprint("INFO : Stopping slave thread on new master")
79-
err = dbhelper.StopSlave(master.Conn)
80-
if err != nil {
81-
logprint("WARN : Stopping slave failed on new master")
80+
if multiMaster == false {
81+
logprint("INFO : Stopping slave thread on new master")
82+
err = dbhelper.StopSlave(master.Conn)
83+
if err != nil {
84+
logprint("WARN : Stopping slave failed on new master")
85+
}
8286
}
8387
// Call post-failover script before unlocking the old master.
8488
if postScript != "" {
@@ -89,10 +93,12 @@ func masterFailover(fail bool) {
8993
}
9094
logprint("INFO : Post-failover script complete", string(out))
9195
}
92-
logprint("INFO : Resetting slave on new master and set read/write mode on")
93-
err = dbhelper.ResetSlave(master.Conn, true)
94-
if err != nil {
95-
logprint("WARN : Reset slave failed on new master")
96+
if multiMaster == false {
97+
logprint("INFO : Resetting slave on new master and set read/write mode on")
98+
err = dbhelper.ResetSlave(master.Conn, true)
99+
if err != nil {
100+
logprint("WARN : Reset slave failed on new master")
101+
}
96102
}
97103
err = dbhelper.SetReadOnly(master.Conn, false)
98104
if err != nil {
@@ -134,11 +140,17 @@ func masterFailover(fail bool) {
134140
}
135141
// Add the old master to the slaves list
136142
oldMaster.State = stateSlave
137-
slaves = append(slaves, oldMaster)
143+
if multiMaster == false {
144+
slaves = append(slaves, oldMaster)
145+
}
138146
}
139147
// Phase 5: Switch slaves to new master
140148
logprint("INFO : Switching other slaves to the new master")
141149
for _, sl := range slaves {
150+
// Don't switch if slave was the old master or is in a multiple master setup.
151+
if sl.URL == oldMaster.URL || sl.State == stateMaster {
152+
continue
153+
}
142154
if fail == false {
143155
logprintf("INFO : Waiting for slave %s to sync", sl.URL)
144156
dbhelper.MasterPosWait(sl.Conn, oldMaster.BinlogPos)

monitor.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,16 @@ func (server *ServerMonitor) electCandidate(l []*ServerMonitor) int {
215215
logprintf("DEBUG: Processing %d candidates", ll)
216216
}
217217
seqList := make([]uint64, ll)
218-
i := 0
219218
hiseq := 0
220-
for _, sl := range l {
219+
var max uint64
220+
for i, sl := range l {
221221
if server.State != stateFailed {
222222
if verbose {
223-
logprintf("DEBUG: Checking eligibility of slave server %s", sl.URL)
223+
logprintf("DEBUG: Checking eligibility of slave server %s [%d]", sl.URL, i)
224+
}
225+
if multiMaster == true && sl.State == stateMaster {
226+
logprintf("WARN : Slave %s has state Master. Skipping", sl.URL)
227+
continue
224228
}
225229
if dbhelper.CheckSlavePrerequisites(sl.Conn, sl.Host) == false {
226230
continue
@@ -262,16 +266,15 @@ func (server *ServerMonitor) electCandidate(l []*ServerMonitor) int {
262266
return i
263267
}
264268
seqList[i] = getSeqFromGtid(dbhelper.GetVariableByName(sl.Conn, "GTID_CURRENT_POS"))
265-
var max uint64
266-
if i == 0 {
267-
max = seqList[0]
268-
} else if seqList[i] > max {
269+
if verbose {
270+
logprintf("DEBUG: Got sequence number %d for server [%d]", seqList[i], i)
271+
}
272+
if seqList[i] > max {
269273
max = seqList[i]
270274
hiseq = i
271275
}
272-
i++
273276
}
274-
if i > 0 {
277+
if max > 0 {
275278
/* Return key of slave with the highest seqno. */
276279
return hiseq
277280
}

repmgr.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ var (
7474
failtime int64
7575
checktype string
7676
masterConn string
77+
multiMaster bool
7778
)
7879

7980
func init() {
@@ -110,6 +111,7 @@ func initRepmgrFlags(cmd *cobra.Command) {
110111
cmd.Flags().StringVar(&logfile, "logfile", "", "Write MRM messages to a log file")
111112
cmd.Flags().IntVar(&timeout, "connect-timeout", 5, "Database connection timeout in seconds")
112113
cmd.Flags().StringVar(&masterConn, "master-connection", "", "Connection name to use for multisource replication")
114+
cmd.Flags().BoolVar(&multiMaster, "multimaster", false, "Turn on multi-master detection")
113115
viper.BindPFlags(cmd.Flags())
114116
preScript = viper.GetString("pre-failover-script")
115117
postScript = viper.GetString("post-failover-script")
@@ -122,6 +124,7 @@ func initRepmgrFlags(cmd *cobra.Command) {
122124
logfile = viper.GetString("logfile")
123125
timeout = viper.GetInt("connect-timeout")
124126
masterConn = viper.GetString("master-connection")
127+
multiMaster = viper.GetBool("multimaster")
125128
}
126129

127130
var failoverCmd = &cobra.Command{

topology.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type topologyError struct {
1717

1818
func init() {
1919
rootCmd.AddCommand(topologyCmd)
20+
topologyCmd.Flags().BoolVar(&multiMaster, "multimaster", false, "Turn on multi-master detection")
2021
}
2122

2223
func (e topologyError) Error() string {
@@ -77,11 +78,26 @@ func topologyInit() error {
7778
}
7879

7980
// Check that all slave servers have the same master.
80-
for _, sl := range slaves {
81-
if sl.hasSiblings(slaves) == false {
81+
if multiMaster == false {
82+
for _, sl := range slaves {
83+
if sl.hasSiblings(slaves) == false {
84+
return topologyError{
85+
33,
86+
fmt.Sprintf("ERROR: Multiple masters were detected"),
87+
}
88+
}
89+
}
90+
} else {
91+
srw := 0
92+
for _, s := range servers {
93+
if s.ReadOnly == "OFF" {
94+
srw++
95+
}
96+
}
97+
if srw != 1 {
8298
return topologyError{
83-
33,
84-
fmt.Sprintf("ERROR: Multiple masters were detected"),
99+
11,
100+
fmt.Sprintf("ERROR: RW server count > 1 in multi-master mode. Please set slaves to RO"),
85101
}
86102
}
87103
}
@@ -91,7 +107,7 @@ func topologyInit() error {
91107
// First of all, get a server id from the slaves slice, they should be all the same
92108
sid := slaves[0].MasterServerID
93109
for k, s := range servers {
94-
if s.State == stateUnconn {
110+
if multiMaster == false && s.State == stateUnconn {
95111
if s.ServerID == sid {
96112
master = servers[k]
97113
master.State = stateMaster
@@ -101,6 +117,16 @@ func topologyInit() error {
101117
break
102118
}
103119
}
120+
if multiMaster == true {
121+
if s.ReadOnly == "OFF" {
122+
master = servers[k]
123+
master.State = stateMaster
124+
if verbose {
125+
log.Printf("DEBUG: Server %s was autodetected as a master", s.URL)
126+
}
127+
break
128+
}
129+
}
104130
}
105131
// If master is not initialized, find it in the failed hosts list
106132
if master == nil {

0 commit comments

Comments
 (0)