// Change the type of tablet and recompute all necessary derived paths in the // serving graph. // force: Bypass the vtaction system and make the data change directly, and // do not run the remote hooks. // // Note we don't update the master record in the Shard here, as we can't // ChangeType from and out of master anyway. func (wr *Wrangler) ChangeType(tabletAlias topo.TabletAlias, dbType topo.TabletType, force bool) error { // Load tablet to find keyspace and shard assignment. // Don't load after the ChangeType which might have unassigned // the tablet. ti, err := wr.ts.GetTablet(tabletAlias) if err != nil { return err } rebuildRequired := ti.Tablet.IsServingType() if force { // with --force, we do not run any hook err = tm.ChangeType(wr.ts, tabletAlias, dbType, false) } else { // the remote action will run the hooks var actionPath string actionPath, err = wr.ai.ChangeType(tabletAlias, dbType) // You don't have a choice - you must wait for // completion before rebuilding. if err == nil { err = wr.ai.WaitForCompletion(actionPath, wr.actionTimeout()) } } if err != nil { return err } // we rebuild if the tablet was serving, or if it is now var keyspaceToRebuild string var shardToRebuild string var cellToRebuild string if rebuildRequired { keyspaceToRebuild = ti.Keyspace shardToRebuild = ti.Shard cellToRebuild = ti.Cell } else { // re-read the tablet, see if we become serving ti, err := wr.ts.GetTablet(tabletAlias) if err != nil { return err } if ti.Tablet.IsServingType() { rebuildRequired = true keyspaceToRebuild = ti.Keyspace shardToRebuild = ti.Shard cellToRebuild = ti.Cell } } if rebuildRequired { if err := wr.RebuildShardGraph(keyspaceToRebuild, shardToRebuild, []string{cellToRebuild}); err != nil { return err } } return nil }
// ChangeTypeNoRebuild changes a tablet's type, and returns whether // there's a shard that should be rebuilt, along with its cell, // keyspace, and shard. If force is true, it will bypass the vtaction // system and make the data change directly, and not run the remote // hooks. // // Note we don't update the master record in the Shard here, as we // can't ChangeType from and out of master anyway. func (wr *Wrangler) ChangeTypeNoRebuild(tabletAlias topo.TabletAlias, tabletType topo.TabletType, force bool) (rebuildRequired bool, cell, keyspace, shard string, err error) { // Load tablet to find keyspace and shard assignment. // Don't load after the ChangeType which might have unassigned // the tablet. ti, err := wr.ts.GetTablet(tabletAlias) if err != nil { return false, "", "", "", err } if force { if err := tabletmanager.ChangeType(wr.ts, tabletAlias, tabletType, nil, false); err != nil { return false, "", "", "", err } } else { if wr.UseRPCs { if err := wr.ai.RpcChangeType(ti, tabletType, wr.actionTimeout()); err != nil { return false, "", "", "", err } } else { // the remote action will run the hooks actionPath, err := wr.ai.ChangeType(tabletAlias, tabletType) if err != nil { return false, "", "", "", err } // You don't have a choice - you must wait for // completion before rebuilding. if err := wr.ai.WaitForCompletion(actionPath, wr.actionTimeout()); err != nil { return false, "", "", "", err } } } if !ti.Tablet.IsInServingGraph() { // re-read the tablet, see if we become serving ti, err = wr.ts.GetTablet(tabletAlias) if err != nil { return false, "", "", "", err } if !ti.Tablet.IsInServingGraph() { return false, "", "", "", nil } } return true, ti.Alias.Cell, ti.Keyspace, ti.Shard, nil }
func (tm *TabletManager) ChangeType(context *rpcproto.Context, args *topo.TabletType, reply *rpc.UnusedResponse) error { return tm.agent.RpcWrapLockAction(context.RemoteAddr, actionnode.TABLET_ACTION_CHANGE_TYPE, args, reply, func() error { return tabletmanager.ChangeType(tm.agent.TopoServer, tm.agent.TabletAlias, *args, true /*runHooks*/) }) }