vitess.io/vitess@v0.16.2/go/vt/vtctl/reparentutil/durability.go (about) 1 /* 2 Copyright 2021 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package reparentutil 18 19 import ( 20 "fmt" 21 22 "vitess.io/vitess/go/vt/log" 23 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 24 "vitess.io/vitess/go/vt/topo/topoproto" 25 "vitess.io/vitess/go/vt/vtctl/reparentutil/promotionrule" 26 ) 27 28 //======================================================================= 29 30 // A NewDurabler is a function that creates a new Durabler based on the 31 // properties specified in the input map. Every Durabler must 32 // register a NewDurabler function. 33 type NewDurabler func() Durabler 34 35 var ( 36 // durabilityPolicies is a map that stores the functions needed to create a new Durabler 37 durabilityPolicies = make(map[string]NewDurabler) 38 ) 39 40 func init() { 41 // register all the durability rules with their functions to create them 42 RegisterDurability("none", func() Durabler { 43 return &durabilityNone{} 44 }) 45 RegisterDurability("semi_sync", func() Durabler { 46 return &durabilitySemiSync{} 47 }) 48 RegisterDurability("cross_cell", func() Durabler { 49 return &durabilityCrossCell{} 50 }) 51 RegisterDurability("test", func() Durabler { 52 return &durabilityTest{} 53 }) 54 } 55 56 // Durabler is the interface which is used to get the promotion rules for candidates and the semi sync setup 57 type Durabler interface { 58 // promotionRule represents the precedence in which we want to tablets to be promoted. 59 // The higher the promotion rule of a tablet, the more we want it to be promoted in case of a failover 60 promotionRule(*topodatapb.Tablet) promotionrule.CandidatePromotionRule 61 // semiSyncAckers represents the number of semi-sync ackers required for a given tablet if it were to become the PRIMARY instance 62 semiSyncAckers(*topodatapb.Tablet) int 63 // isReplicaSemiSync returns whether the "replica" should send semi-sync acks if "primary" were to become the PRIMARY instance 64 isReplicaSemiSync(primary, replica *topodatapb.Tablet) bool 65 } 66 67 func RegisterDurability(name string, newDurablerFunc NewDurabler) { 68 if durabilityPolicies[name] != nil { 69 log.Fatalf("durability policy %v already registered", name) 70 } 71 durabilityPolicies[name] = newDurablerFunc 72 } 73 74 //======================================================================= 75 76 // GetDurabilityPolicy is used to get a new durability policy from the registered policies 77 func GetDurabilityPolicy(name string) (Durabler, error) { 78 newDurabilityCreationFunc, found := durabilityPolicies[name] 79 if !found { 80 return nil, fmt.Errorf("durability policy %v not found", name) 81 } 82 return newDurabilityCreationFunc(), nil 83 } 84 85 // CheckDurabilityPolicyExists is used to check if the durability policy is part of the registered policies 86 func CheckDurabilityPolicyExists(name string) bool { 87 _, found := durabilityPolicies[name] 88 return found 89 } 90 91 // PromotionRule returns the promotion rule for the instance. 92 func PromotionRule(durability Durabler, tablet *topodatapb.Tablet) promotionrule.CandidatePromotionRule { 93 // Prevent panics. 94 if tablet == nil || tablet.Alias == nil { 95 return promotionrule.MustNot 96 } 97 return durability.promotionRule(tablet) 98 } 99 100 // SemiSyncAckers returns the primary semi-sync setting for the instance. 101 // 0 means none. Non-zero specifies the number of required ackers. 102 func SemiSyncAckers(durability Durabler, tablet *topodatapb.Tablet) int { 103 return durability.semiSyncAckers(tablet) 104 } 105 106 // IsReplicaSemiSync returns the replica semi-sync setting from the tablet record. 107 // Prefer using this function if tablet record is available. 108 func IsReplicaSemiSync(durability Durabler, primary, replica *topodatapb.Tablet) bool { 109 // Prevent panics. 110 if primary == nil || primary.Alias == nil || replica == nil || replica.Alias == nil { 111 return false 112 } 113 return durability.isReplicaSemiSync(primary, replica) 114 } 115 116 //======================================================================= 117 118 // durabilityNone has no semi-sync and returns NeutralPromoteRule for Primary and Replica tablet types, MustNotPromoteRule for everything else 119 type durabilityNone struct{} 120 121 // promotionRule implements the Durabler interface 122 func (d *durabilityNone) promotionRule(tablet *topodatapb.Tablet) promotionrule.CandidatePromotionRule { 123 switch tablet.Type { 124 case topodatapb.TabletType_PRIMARY, topodatapb.TabletType_REPLICA: 125 return promotionrule.Neutral 126 } 127 return promotionrule.MustNot 128 } 129 130 // semiSyncAckers implements the Durabler interface 131 func (d *durabilityNone) semiSyncAckers(tablet *topodatapb.Tablet) int { 132 return 0 133 } 134 135 // isReplicaSemiSync implements the Durabler interface 136 func (d *durabilityNone) isReplicaSemiSync(primary, replica *topodatapb.Tablet) bool { 137 return false 138 } 139 140 //======================================================================= 141 142 // durabilitySemiSync has 1 semi-sync setup. It only allows Primary and Replica type servers to acknowledge semi sync 143 // It returns NeutralPromoteRule for Primary and Replica tablet types, MustNotPromoteRule for everything else 144 type durabilitySemiSync struct{} 145 146 // promotionRule implements the Durabler interface 147 func (d *durabilitySemiSync) promotionRule(tablet *topodatapb.Tablet) promotionrule.CandidatePromotionRule { 148 switch tablet.Type { 149 case topodatapb.TabletType_PRIMARY, topodatapb.TabletType_REPLICA: 150 return promotionrule.Neutral 151 } 152 return promotionrule.MustNot 153 } 154 155 // semiSyncAckers implements the Durabler interface 156 func (d *durabilitySemiSync) semiSyncAckers(tablet *topodatapb.Tablet) int { 157 return 1 158 } 159 160 // isReplicaSemiSync implements the Durabler interface 161 func (d *durabilitySemiSync) isReplicaSemiSync(primary, replica *topodatapb.Tablet) bool { 162 switch replica.Type { 163 case topodatapb.TabletType_PRIMARY, topodatapb.TabletType_REPLICA: 164 return true 165 } 166 return false 167 } 168 169 //======================================================================= 170 171 // durabilityCrossCell has 1 semi-sync setup. It only allows Primary and Replica type servers from a different cell to acknowledge semi sync. 172 // This means that a transaction must be in two cells for it to be acknowledged 173 // It returns NeutralPromoteRule for Primary and Replica tablet types, MustNotPromoteRule for everything else 174 type durabilityCrossCell struct{} 175 176 // promotionRule implements the Durabler interface 177 func (d *durabilityCrossCell) promotionRule(tablet *topodatapb.Tablet) promotionrule.CandidatePromotionRule { 178 switch tablet.Type { 179 case topodatapb.TabletType_PRIMARY, topodatapb.TabletType_REPLICA: 180 return promotionrule.Neutral 181 } 182 return promotionrule.MustNot 183 } 184 185 // semiSyncAckers implements the Durabler interface 186 func (d *durabilityCrossCell) semiSyncAckers(tablet *topodatapb.Tablet) int { 187 return 1 188 } 189 190 // isReplicaSemiSync implements the Durabler interface 191 func (d *durabilityCrossCell) isReplicaSemiSync(primary, replica *topodatapb.Tablet) bool { 192 switch replica.Type { 193 case topodatapb.TabletType_PRIMARY, topodatapb.TabletType_REPLICA: 194 return primary.Alias.Cell != replica.Alias.Cell 195 } 196 return false 197 } 198 199 //======================================================================= 200 201 // durabilityTest is like durabilityNone. It overrides the type for a specific tablet to prefer. It is only meant to be used for testing purposes! 202 type durabilityTest struct{} 203 204 // promotionRule implements the Durabler interface 205 func (d *durabilityTest) promotionRule(tablet *topodatapb.Tablet) promotionrule.CandidatePromotionRule { 206 if topoproto.TabletAliasString(tablet.Alias) == "zone2-0000000200" { 207 return promotionrule.Prefer 208 } 209 210 switch tablet.Type { 211 case topodatapb.TabletType_PRIMARY, topodatapb.TabletType_REPLICA: 212 return promotionrule.Neutral 213 } 214 return promotionrule.MustNot 215 } 216 217 // semiSyncAckers implements the Durabler interface 218 func (d *durabilityTest) semiSyncAckers(tablet *topodatapb.Tablet) int { 219 return 0 220 } 221 222 // isReplicaSemiSync implements the Durabler interface 223 func (d *durabilityTest) isReplicaSemiSync(primary, replica *topodatapb.Tablet) bool { 224 return false 225 }