vitess.io/vitess@v0.16.2/go/vt/wrangler/reparent.go (about) 1 /* 2 Copyright 2019 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 wrangler 18 19 /* 20 This file handles the reparenting operations. 21 */ 22 23 import ( 24 "context" 25 "fmt" 26 "time" 27 28 "k8s.io/apimachinery/pkg/util/sets" 29 30 "vitess.io/vitess/go/event" 31 "vitess.io/vitess/go/vt/log" 32 "vitess.io/vitess/go/vt/topo/topoproto" 33 "vitess.io/vitess/go/vt/topotools/events" 34 "vitess.io/vitess/go/vt/vtctl/grpcvtctldserver" 35 "vitess.io/vitess/go/vt/vtctl/reparentutil" 36 37 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 38 vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata" 39 ) 40 41 // ReparentTablet tells a tablet to reparent this tablet to the current 42 // primary, based on the current replication position. If there is no 43 // match, it will fail. 44 func (wr *Wrangler) ReparentTablet(ctx context.Context, tabletAlias *topodatapb.TabletAlias) error { 45 _, err := wr.vtctld.ReparentTablet(ctx, &vtctldatapb.ReparentTabletRequest{ 46 Tablet: tabletAlias, 47 }) 48 return err 49 } 50 51 // InitShardPrimary will make the provided tablet the primary for the shard. 52 func (wr *Wrangler) InitShardPrimary(ctx context.Context, keyspace, shard string, primaryElectTabletAlias *topodatapb.TabletAlias, force bool, waitReplicasTimeout time.Duration) (err error) { 53 // lock the shard 54 ctx, unlock, lockErr := wr.ts.LockShard(ctx, keyspace, shard, fmt.Sprintf("InitShardPrimary(%v)", topoproto.TabletAliasString(primaryElectTabletAlias))) 55 if lockErr != nil { 56 return lockErr 57 } 58 defer unlock(&err) 59 60 // Create reusable Reparent event with available info 61 ev := &events.Reparent{} 62 63 // do the work 64 err = grpcvtctldserver.NewVtctldServer(wr.ts).InitShardPrimaryLocked(ctx, ev, &vtctldatapb.InitShardPrimaryRequest{ 65 Keyspace: keyspace, 66 Shard: shard, 67 PrimaryElectTabletAlias: primaryElectTabletAlias, 68 Force: force, 69 }, waitReplicasTimeout, wr.tmc, wr.logger) 70 if err != nil { 71 event.DispatchUpdate(ev, "failed InitShardPrimary: "+err.Error()) 72 } else { 73 event.DispatchUpdate(ev, "finished InitShardPrimary") 74 } 75 return err 76 } 77 78 // PlannedReparentShard will make the provided tablet the primary for the shard, 79 // when both the current and new primary are reachable and in good shape. 80 func (wr *Wrangler) PlannedReparentShard(ctx context.Context, keyspace, shard string, primaryElectTabletAlias, avoidTabletAlias *topodatapb.TabletAlias, waitReplicasTimeout time.Duration) (err error) { 81 _, err = reparentutil.NewPlannedReparenter(wr.ts, wr.tmc, wr.logger).ReparentShard( 82 ctx, 83 keyspace, 84 shard, 85 reparentutil.PlannedReparentOptions{ 86 AvoidPrimaryAlias: avoidTabletAlias, 87 NewPrimaryAlias: primaryElectTabletAlias, 88 WaitReplicasTimeout: waitReplicasTimeout, 89 }, 90 ) 91 92 return err 93 } 94 95 // EmergencyReparentShard will make the provided tablet the primary for 96 // the shard, when the old primary is completely unreachable. 97 func (wr *Wrangler) EmergencyReparentShard(ctx context.Context, keyspace, shard string, primaryElectTabletAlias *topodatapb.TabletAlias, waitReplicasTimeout time.Duration, ignoredTablets sets.Set[string], preventCrossCellPromotion bool) (err error) { 98 _, err = reparentutil.NewEmergencyReparenter(wr.ts, wr.tmc, wr.logger).ReparentShard( 99 ctx, 100 keyspace, 101 shard, 102 reparentutil.EmergencyReparentOptions{ 103 NewPrimaryAlias: primaryElectTabletAlias, 104 WaitReplicasTimeout: waitReplicasTimeout, 105 IgnoreReplicas: ignoredTablets, 106 PreventCrossCellPromotion: preventCrossCellPromotion, 107 }, 108 ) 109 110 return err 111 } 112 113 // TabletExternallyReparented changes the type of new primary for this shard to PRIMARY 114 // and updates it's tablet record in the topo. Updating the shard record is handled 115 // by the new primary tablet 116 func (wr *Wrangler) TabletExternallyReparented(ctx context.Context, newPrimaryAlias *topodatapb.TabletAlias) error { 117 118 tabletInfo, err := wr.ts.GetTablet(ctx, newPrimaryAlias) 119 if err != nil { 120 log.Warningf("TabletExternallyReparented: failed to read tablet record for %v: %v", newPrimaryAlias, err) 121 return err 122 } 123 124 // Check the global shard record. 125 tablet := tabletInfo.Tablet 126 si, err := wr.ts.GetShard(ctx, tablet.Keyspace, tablet.Shard) 127 if err != nil { 128 log.Warningf("TabletExternallyReparented: failed to read global shard record for %v/%v: %v", tablet.Keyspace, tablet.Shard, err) 129 return err 130 } 131 132 // We update the tablet only if it is not currently primary 133 if tablet.Type != topodatapb.TabletType_PRIMARY { 134 log.Infof("TabletExternallyReparented: executing tablet type change to PRIMARY") 135 136 durabilityName, err := wr.ts.GetKeyspaceDurability(ctx, tablet.Keyspace) 137 if err != nil { 138 return err 139 } 140 log.Infof("Getting a new durability policy for %v", durabilityName) 141 durability, err := reparentutil.GetDurabilityPolicy(durabilityName) 142 if err != nil { 143 return err 144 } 145 146 // Create a reusable Reparent event with available info. 147 ev := &events.Reparent{ 148 ShardInfo: *si, 149 NewPrimary: tablet, 150 OldPrimary: &topodatapb.Tablet{ 151 Alias: si.PrimaryAlias, 152 Type: topodatapb.TabletType_PRIMARY, 153 }, 154 } 155 defer func() { 156 if err != nil { 157 event.DispatchUpdate(ev, "failed: "+err.Error()) 158 } 159 }() 160 event.DispatchUpdate(ev, "starting external reparent") 161 162 if err := wr.tmc.ChangeType(ctx, tablet, topodatapb.TabletType_PRIMARY, reparentutil.SemiSyncAckers(durability, tablet) > 0); err != nil { 163 log.Warningf("Error calling ChangeType on new primary %v: %v", topoproto.TabletAliasString(newPrimaryAlias), err) 164 return err 165 } 166 event.DispatchUpdate(ev, "finished") 167 } 168 return nil 169 }