vitess.io/vitess@v0.16.2/go/vt/topo/helpers/copy.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 helpers contains a few utility classes to handle topo.Server 18 // objects, and transitions from one topo implementation to another. 19 package helpers 20 21 import ( 22 "context" 23 24 "google.golang.org/protobuf/proto" 25 26 "vitess.io/vitess/go/vt/log" 27 "vitess.io/vitess/go/vt/topo" 28 "vitess.io/vitess/go/vt/topo/topoproto" 29 30 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 31 ) 32 33 // CopyKeyspaces will create the keyspaces in the destination topo. 34 func CopyKeyspaces(ctx context.Context, fromTS, toTS *topo.Server) { 35 keyspaces, err := fromTS.GetKeyspaces(ctx) 36 if err != nil { 37 log.Fatalf("GetKeyspaces: %v", err) 38 } 39 40 for _, keyspace := range keyspaces { 41 42 ki, err := fromTS.GetKeyspace(ctx, keyspace) 43 if err != nil { 44 log.Fatalf("GetKeyspace(%v): %v", keyspace, err) 45 } 46 47 if err := toTS.CreateKeyspace(ctx, keyspace, ki.Keyspace); err != nil { 48 if topo.IsErrType(err, topo.NodeExists) { 49 log.Warningf("keyspace %v already exists", keyspace) 50 } else { 51 log.Errorf("CreateKeyspace(%v): %v", keyspace, err) 52 } 53 } 54 55 vs, err := fromTS.GetVSchema(ctx, keyspace) 56 switch { 57 case err == nil: 58 if err := toTS.SaveVSchema(ctx, keyspace, vs); err != nil { 59 log.Errorf("SaveVSchema(%v): %v", keyspace, err) 60 } 61 case topo.IsErrType(err, topo.NoNode): 62 // Nothing to do. 63 default: 64 log.Errorf("GetVSchema(%v): %v", keyspace, err) 65 } 66 } 67 } 68 69 // CopyShards will create the shards in the destination topo. 70 func CopyShards(ctx context.Context, fromTS, toTS *topo.Server) { 71 keyspaces, err := fromTS.GetKeyspaces(ctx) 72 if err != nil { 73 log.Fatalf("fromTS.GetKeyspaces: %v", err) 74 } 75 76 for _, keyspace := range keyspaces { 77 shards, err := fromTS.GetShardNames(ctx, keyspace) 78 if err != nil { 79 log.Fatalf("GetShardNames(%v): %v", keyspace, err) 80 return 81 } 82 83 for _, shard := range shards { 84 85 si, err := fromTS.GetShard(ctx, keyspace, shard) 86 if err != nil { 87 log.Fatalf("GetShard(%v, %v): %v", keyspace, shard, err) 88 } 89 90 if err := toTS.CreateShard(ctx, keyspace, shard); err != nil { 91 if topo.IsErrType(err, topo.NodeExists) { 92 log.Warningf("shard %v/%v already exists", keyspace, shard) 93 } else { 94 log.Fatalf("CreateShard(%v, %v): %v", keyspace, shard, err) 95 } 96 } 97 if _, err := toTS.UpdateShardFields(ctx, keyspace, shard, func(toSI *topo.ShardInfo) error { 98 toSI.Shard = proto.Clone(si.Shard).(*topodatapb.Shard) 99 return nil 100 }); err != nil { 101 log.Fatalf("UpdateShardFields(%v, %v): %v", keyspace, shard, err) 102 } 103 } 104 } 105 } 106 107 // CopyTablets will create the tablets in the destination topo. 108 func CopyTablets(ctx context.Context, fromTS, toTS *topo.Server) { 109 cells, err := fromTS.GetKnownCells(ctx) 110 if err != nil { 111 log.Fatalf("fromTS.GetKnownCells: %v", err) 112 } 113 114 for _, cell := range cells { 115 tabletAliases, err := fromTS.GetTabletAliasesByCell(ctx, cell) 116 if err != nil { 117 log.Fatalf("GetTabletsByCell(%v): %v", cell, err) 118 } else { 119 for _, tabletAlias := range tabletAliases { 120 121 // read the source tablet 122 ti, err := fromTS.GetTablet(ctx, tabletAlias) 123 if err != nil { 124 log.Fatalf("GetTablet(%v): %v", tabletAlias, err) 125 } 126 127 // try to create the destination 128 err = toTS.CreateTablet(ctx, ti.Tablet) 129 if topo.IsErrType(err, topo.NodeExists) { 130 // update the destination tablet 131 log.Warningf("tablet %v already exists, updating it", tabletAlias) 132 _, err = toTS.UpdateTabletFields(ctx, tabletAlias, func(t *topodatapb.Tablet) error { 133 proto.Merge(t, ti.Tablet) 134 return nil 135 }) 136 } 137 if err != nil { 138 log.Fatalf("CreateTablet(%v): %v", tabletAlias, err) 139 } 140 } 141 } 142 } 143 } 144 145 // CopyShardReplications will create the ShardReplication objects in 146 // the destination topo. 147 func CopyShardReplications(ctx context.Context, fromTS, toTS *topo.Server) { 148 keyspaces, err := fromTS.GetKeyspaces(ctx) 149 if err != nil { 150 log.Fatalf("fromTS.GetKeyspaces: %v", err) 151 } 152 153 cells, err := fromTS.GetCellInfoNames(ctx) 154 if err != nil { 155 log.Fatalf("GetCellInfoNames(): %v", err) 156 } 157 158 for _, keyspace := range keyspaces { 159 shards, err := fromTS.GetShardNames(ctx, keyspace) 160 if err != nil { 161 log.Fatalf("GetShardNames(%v): %v", keyspace, err) 162 } 163 164 for _, shard := range shards { 165 for _, cell := range cells { 166 sri, err := fromTS.GetShardReplication(ctx, cell, keyspace, shard) 167 if err != nil { 168 log.Fatalf("GetShardReplication(%v, %v, %v): %v", cell, keyspace, shard, err) 169 } 170 171 sriNodes := map[string]struct{}{} 172 for _, node := range sri.Nodes { 173 sriNodes[topoproto.TabletAliasString(node.TabletAlias)] = struct{}{} 174 } 175 176 if err := toTS.UpdateShardReplicationFields(ctx, cell, keyspace, shard, func(oldSR *topodatapb.ShardReplication) error { 177 var nodes []*topodatapb.ShardReplication_Node 178 for _, oldNode := range oldSR.Nodes { 179 if _, ok := sriNodes[topoproto.TabletAliasString(oldNode.TabletAlias)]; ok { 180 continue 181 } 182 183 nodes = append(nodes, oldNode) 184 } 185 186 nodes = append(nodes, sri.ShardReplication.Nodes...) 187 // Even though ShardReplication currently only has the .Nodes field, 188 // keeping the proto.Merge call here prevents this copy from 189 // unintentionally breaking if we add new fields. 190 proto.Merge(oldSR, sri.ShardReplication) 191 oldSR.Nodes = nodes 192 return nil 193 }); err != nil { 194 log.Warningf("UpdateShardReplicationFields(%v, %v, %v): %v", cell, keyspace, shard, err) 195 } 196 } 197 } 198 } 199 } 200 201 // CopyRoutingRules will create the routing rules in the destination topo. 202 func CopyRoutingRules(ctx context.Context, fromTS, toTS *topo.Server) { 203 rr, err := fromTS.GetRoutingRules(ctx) 204 if err != nil { 205 log.Fatalf("GetRoutingRules: %v", err) 206 } 207 if err := toTS.SaveRoutingRules(ctx, rr); err != nil { 208 log.Errorf("SaveRoutingRules(%v): %v", rr, err) 209 } 210 }