diff --git a/go/inst/instance_topology.go b/go/inst/instance_topology.go index 26b93113b..e02e68d91 100644 --- a/go/inst/instance_topology.go +++ b/go/inst/instance_topology.go @@ -2202,6 +2202,34 @@ func getPriorityBinlogFormatForCandidate(replicas [](*Instance)) (priorityBinlog return sorted.First(), nil } +// getPriorityDataCenterForCandidate returns the replica datacenter found +// among given instances. This will be used for choosing best candidate for promotion. +func getPriorityDataCenterForCandidate(replicas [](*Instance)) (priorityDataCenter string, err error) { + if len(replicas) == 0 { + return "", log.Errorf("empty replicas list in getPriorityBinlogFormatForCandidate") + } + candidate := "" + for _, replica := range replicas { + candidate = replica.DataCenter + return candidate, nil + } + return "", nil +} + +// IsDataCenterCandiadateReplica compare master's datacenter and replica datacenter. +// if master's datacenter eq replica datacenter return true +func IsDataCenterCandiadateReplica(priorityDataCenter string, replica *Instance) bool { + masterOfDesignatedInstance, _ := GetInstanceMaster(replica) + if masterOfDesignatedInstance.DataCenter == priorityDataCenter { + log.Debugf("instance %+v is banned because of promotion rule", replica.Key) + return true + } + if matched, _ := regexp.MatchString(config.Config.DataCenterPattern, replica.Key.Hostname); matched { + return true + } + return false +} + // chooseCandidateReplica func chooseCandidateReplica(replicas [](*Instance)) (candidateReplica *Instance, aheadReplicas, equalReplicas, laterReplicas, cannotReplicateReplicas [](*Instance), err error) { if len(replicas) == 0 { @@ -2209,18 +2237,36 @@ func chooseCandidateReplica(replicas [](*Instance)) (candidateReplica *Instance, } priorityMajorVersion, _ := getPriorityMajorVersionForCandidate(replicas) priorityBinlogFormat, _ := getPriorityBinlogFormatForCandidate(replicas) - - for _, replica := range replicas { - replica := replica - if isGenerallyValidAsCandidateReplica(replica) && - !IsBannedFromBeingCandidateReplica(replica) && - !IsSmallerMajorVersion(priorityMajorVersion, replica.MajorVersionString()) && - !IsSmallerBinlogFormat(priorityBinlogFormat, replica.Binlog_format) { - // this is the one - candidateReplica = replica - break - } - } + // priorityDataCenter return boll for candidate + priorityDataCenter, _ := getPriorityDataCenterForCandidate(replicas) + + + if config.Config.PreventCrossDataCenterMasterFailover { + for _, replica := range replicas { + replica := replica + if isGenerallyValidAsCandidateReplica(replica) && + !IsBannedFromBeingCandidateReplica(replica) && + !IsSmallerMajorVersion(priorityMajorVersion, replica.MajorVersionString()) && + !IsSmallerBinlogFormat(priorityBinlogFormat, replica.Binlog_format) && + IsDataCenterCandiadateReplica(priorityDataCenter, replica) { + // this is the one + candidateReplica = replica + break + } + } + } else { + for _, replica := range replicas { + replica := replica + if isGenerallyValidAsCandidateReplica(replica) && + !IsBannedFromBeingCandidateReplica(replica) && + !IsSmallerMajorVersion(priorityMajorVersion, replica.MajorVersionString()) && + !IsSmallerBinlogFormat(priorityBinlogFormat, replica.Binlog_format) { + // this is the one + candidateReplica = replica + break + } + } + } if candidateReplica == nil { // Unable to find a candidate that will master others. // Instead, pick a (single) replica which is not banned.