func (wr *Wrangler) SourceShardAdd(keyspace, shard string, uid uint32, skeyspace, sshard string, keyRange key.KeyRange, tables []string) error { actionNode := actionnode.UpdateShard() lockPath, err := wr.lockShard(keyspace, shard, actionNode) if err != nil { return err } err = wr.sourceShardAdd(keyspace, shard, uid, skeyspace, sshard, keyRange, tables) return wr.unlockShard(keyspace, shard, actionNode, lockPath, err) }
func (wr *Wrangler) SourceShardDelete(keyspace, shard string, uid uint32) error { actionNode := actionnode.UpdateShard() lockPath, err := wr.lockShard(keyspace, shard, actionNode) if err != nil { return err } err = wr.sourceShardDelete(keyspace, shard, uid) return wr.unlockShard(keyspace, shard, actionNode, lockPath, err) }
// RemoveShardCell will remove a cell from the Cells list in a shard. // It will first check the shard has no tablets there. if 'force' is // specified, it will remove the cell even when the tablet map cannot // be retrieved. This is intended to be used when a cell is completely // down and its topology server cannot even be reached. func (wr *Wrangler) RemoveShardCell(keyspace, shard, cell string, force bool) error { actionNode := actionnode.UpdateShard() lockPath, err := wr.lockShard(keyspace, shard, actionNode) if err != nil { return err } err = wr.removeShardCell(keyspace, shard, cell, force) return wr.unlockShard(keyspace, shard, actionNode, lockPath, err) }
// updateShardCellsAndMaster will update the 'Cells' and possibly // MasterAlias records for the shard, if needed. func (wr *Wrangler) updateShardCellsAndMaster(si *topo.ShardInfo, tabletAlias topo.TabletAlias, tabletType topo.TabletType, force bool) error { // See if we need to update the Shard: // - add the tablet's cell to the shard's Cells if needed // - change the master if needed shardUpdateRequired := false if !si.HasCell(tabletAlias.Cell) { shardUpdateRequired = true } if tabletType == topo.TYPE_MASTER && si.MasterAlias != tabletAlias { shardUpdateRequired = true } if !shardUpdateRequired { return nil } actionNode := actionnode.UpdateShard() keyspace := si.Keyspace() shard := si.ShardName() lockPath, err := wr.lockShard(keyspace, shard, actionNode) if err != nil { return err } // re-read the shard with the lock si, err = wr.ts.GetShard(keyspace, shard) if err != nil { return wr.unlockShard(keyspace, shard, actionNode, lockPath, err) } // update it wasUpdated := false if !si.HasCell(tabletAlias.Cell) { si.Cells = append(si.Cells, tabletAlias.Cell) wasUpdated = true } if tabletType == topo.TYPE_MASTER && si.MasterAlias != tabletAlias { if !si.MasterAlias.IsZero() && !force { return wr.unlockShard(keyspace, shard, actionNode, lockPath, fmt.Errorf("creating this tablet would override old master %v in shard %v/%v", si.MasterAlias, keyspace, shard)) } si.MasterAlias = tabletAlias wasUpdated = true } if wasUpdated { // write it back if err := topo.UpdateShard(context.TODO(), wr.ts, si); err != nil { return wr.unlockShard(keyspace, shard, actionNode, lockPath, err) } } // and unlock return wr.unlockShard(keyspace, shard, actionNode, lockPath, err) }
// SetShardTabletControl changes the TabletControl records // for a shard. It does not rebuild any serving graph or do // cross-shard consistency check. // - if disableQueryService is set, tables has to be empty // - if disableQueryService is not set, and tables is empty, we remove // the TabletControl record for the cells func (wr *Wrangler) SetShardTabletControl(keyspace, shard string, tabletType topo.TabletType, cells []string, remove, disableQueryService bool, tables []string) error { if disableQueryService && len(tables) > 0 { return fmt.Errorf("SetShardTabletControl cannot have both DisableQueryService set and tables set") } actionNode := actionnode.UpdateShard() lockPath, err := wr.lockShard(keyspace, shard, actionNode) if err != nil { return err } err = wr.setShardTabletControl(keyspace, shard, tabletType, cells, remove, disableQueryService, tables) return wr.unlockShard(keyspace, shard, actionNode, lockPath, err) }
// Scrap a tablet. If force is used, we write to topo.Server // directly and don't remote-execute the command. // // If we scrap the master for a shard, we will clear its record // from the Shard object (only if that was the right master) func (wr *Wrangler) Scrap(tabletAlias topo.TabletAlias, force, skipRebuild bool) error { // load the tablet, see if we'll need to rebuild ti, err := wr.ts.GetTablet(tabletAlias) if err != nil { return err } rebuildRequired := ti.Tablet.IsInServingGraph() wasMaster := ti.Type == topo.TYPE_MASTER if force { err = topotools.Scrap(wr.ts, ti.Alias, force) } else { err = wr.tmc.Scrap(wr.ctx, ti) } if err != nil { return err } if !rebuildRequired { wr.Logger().Infof("Rebuild not required") return nil } if skipRebuild { wr.Logger().Warningf("Rebuild required, but skipping it") return nil } // update the Shard object if the master was scrapped if wasMaster { actionNode := actionnode.UpdateShard() lockPath, err := wr.lockShard(ti.Keyspace, ti.Shard, actionNode) if err != nil { return err } // read the shard with the lock si, err := wr.ts.GetShard(ti.Keyspace, ti.Shard) if err != nil { return wr.unlockShard(ti.Keyspace, ti.Shard, actionNode, lockPath, err) } // update it if the right alias is there if si.MasterAlias == tabletAlias { si.MasterAlias = topo.TabletAlias{} // write it back if err := topo.UpdateShard(context.TODO(), wr.ts, si); err != nil { return wr.unlockShard(ti.Keyspace, ti.Shard, actionNode, lockPath, err) } } else { wr.Logger().Warningf("Scrapping master %v from shard %v/%v but master in Shard object was %v", tabletAlias, ti.Keyspace, ti.Shard, si.MasterAlias) } // and unlock if err := wr.unlockShard(ti.Keyspace, ti.Shard, actionNode, lockPath, err); err != nil { return err } } // and rebuild the original shard / keyspace _, err = wr.RebuildShardGraph(ti.Keyspace, ti.Shard, []string{ti.Alias.Cell}) return err }