vtctl: CopySchemaShard optionally allows source shard instead of source

tablet as argument.
This commit is contained in:
Michael Berlin 2015-06-12 15:55:20 -07:00
Родитель e8d8012ed2
Коммит a30503ca0b
3 изменённых файлов: 46 добавлений и 17 удалений

Просмотреть файл

@ -315,8 +315,8 @@ var commands = []commandGroup{
"[-force] {-sql=<sql> || -sql-file=<filename>} <keyspace>",
"Applies the schema change to the specified keyspace on every master, running in parallel on all shards. The changes are then propagated to slaves via replication. If the force flag is set, then numerous checks will be ignored, so that option should be used very cautiously."},
command{"CopySchemaShard", commandCopySchemaShard,
"[-tables=<table1>,<table2>,...] [-exclude_tables=<table1>,<table2>,...] [-include-views] <source tablet alias> <destination keyspace/shard>",
"Copies the schema from a source tablet to the specified shard. The schema is applied directly on the master of the destination shard, and it is propagated to the replicas through binlogs."},
"[-tables=<table1>,<table2>,...] [-exclude_tables=<table1>,<table2>,...] [-include-views] {<source keyspace/shard> || <source tablet alias>} <destination keyspace/shard>",
"Copies the schema from a source shard's master (or a specific tablet) to a destination shard. The schema is applied directly on the master of the destination shard, and it is propagated to the replicas through binlogs."},
command{"ValidateVersionShard", commandValidateVersionShard,
"<keyspace/shard>",
@ -1803,11 +1803,7 @@ func commandCopySchemaShard(ctx context.Context, wr *wrangler.Wrangler, subFlags
}
if subFlags.NArg() != 2 {
return fmt.Errorf("The <tablet alias> and <keyspace/shard> arguments are both required for the CopySchemaShard command. The <tablet alias> argument identifies a source and the <keyspace/shard> argument identifies a destination.")
}
tabletAlias, err := topo.ParseTabletAliasString(subFlags.Arg(0))
if err != nil {
return err
return fmt.Errorf("The <source keyspace/shard> and <destination keyspace/shard> arguments are both required for the CopySchemaShard command. Instead of the <source keyspace/shard> argument, you can also specify <tablet alias> which refers to a specific tablet of the shard in the source keyspace.")
}
var tableArray []string
if *tables != "" {
@ -1817,13 +1813,21 @@ func commandCopySchemaShard(ctx context.Context, wr *wrangler.Wrangler, subFlags
if *excludeTables != "" {
excludeTableArray = strings.Split(*excludeTables, ",")
}
keyspace, shard, err := topo.ParseKeyspaceShardString(subFlags.Arg(1))
destKeyspace, destShard, err := topo.ParseKeyspaceShardString(subFlags.Arg(1))
if err != nil {
return err
}
return wr.CopySchemaShard(ctx, tabletAlias, tableArray, excludeTableArray, *includeViews, keyspace, shard)
sourceKeyspace, sourceShard, err := topo.ParseKeyspaceShardString(subFlags.Arg(0))
if err == nil {
return wr.CopySchemaShardFromShard(ctx, tableArray, excludeTableArray, *includeViews, sourceKeyspace, sourceShard, destKeyspace, destShard)
} else {
sourceTabletAlias, err := topo.ParseTabletAliasString(subFlags.Arg(0))
if err == nil {
return wr.CopySchemaShard(ctx, sourceTabletAlias, tableArray, excludeTableArray, *includeViews, destKeyspace, destShard)
}
return err
}
}
func commandValidateVersionShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error {

Просмотреть файл

@ -417,27 +417,38 @@ func (wr *Wrangler) ApplySchemaKeyspace(ctx context.Context, keyspace string, ch
return nil, wr.unlockKeyspace(ctx, keyspace, actionNode, lockPath, err)
}
// CopySchemaShardFromShard copies the schema from a source shard to the specified destination shard.
// For both source and destination it picks the master tablet. See also CopySchemaShard.
func (wr *Wrangler) CopySchemaShardFromShard(ctx context.Context, tables, excludeTables []string, includeViews bool, sourceKeyspace, sourceShard, destKeyspace, destShard string) error {
sourceShardInfo, err := wr.ts.GetShard(ctx, sourceKeyspace, sourceShard)
if err != nil {
return err
}
return wr.CopySchemaShard(ctx, sourceShardInfo.MasterAlias, tables, excludeTables, includeViews, destKeyspace, destShard)
}
// CopySchemaShard copies the schema from a source tablet to the
// specified shard. The schema is applied directly on the master of
// the destination shard, and is propogated to the replicas through
// binlogs.
func (wr *Wrangler) CopySchemaShard(ctx context.Context, srcTabletAlias topo.TabletAlias, tables, excludeTables []string, includeViews bool, keyspace, shard string) error {
func (wr *Wrangler) CopySchemaShard(ctx context.Context, srcTabletAlias topo.TabletAlias, tables, excludeTables []string, includeViews bool, destKeyspace, destShard string) error {
sd, err := wr.GetSchema(ctx, srcTabletAlias, tables, excludeTables, includeViews)
if err != nil {
return err
}
shardInfo, err := wr.ts.GetShard(ctx, keyspace, shard)
destShardInfo, err := wr.ts.GetShard(ctx, destKeyspace, destShard)
if err != nil {
return err
}
tabletInfo, err := wr.ts.GetTablet(ctx, shardInfo.MasterAlias)
destTabletInfo, err := wr.ts.GetTablet(ctx, destShardInfo.MasterAlias)
if err != nil {
return err
}
createSql := sd.ToSQLStrings()
for i, sqlLine := range createSql {
err = wr.applySqlShard(ctx, tabletInfo, sqlLine, i == len(createSql)-1)
err = wr.applySqlShard(ctx, destTabletInfo, sqlLine, i == len(createSql)-1)
if err != nil {
return err
}

Просмотреть файл

@ -90,7 +90,15 @@ func (fpc *FakePoolConnection) Reconnect() error {
return nil
}
func TestCopySchemaShard(t *testing.T) {
func TestCopySchemaShard_UseTabletAsSource(t *testing.T) {
copySchema(t, false /* useShardAsSource */)
}
func TestCopySchemaShard_UseShardAsSource(t *testing.T) {
copySchema(t, true /* useShardAsSource */)
}
func copySchema(t *testing.T, useShardAsSource bool) {
db := fakesqldb.Register()
ts := zktopo.NewTestServer(t, []string{"cell1", "cell2"})
wr := wrangler.New(logutil.NewConsoleLogger(), ts, tmclient.NewTabletManagerClient(), time.Second)
@ -110,7 +118,7 @@ func TestCopySchemaShard(t *testing.T) {
defer ft.StopActionLoop(t)
}
sourceRdonly.FakeMysqlDaemon.Schema = &myproto.SchemaDefinition{
schema := &myproto.SchemaDefinition{
DatabaseSchema: "CREATE DATABASE `{{.DatabaseName}}` /*!40100 DEFAULT CHARACTER SET utf8 */",
TableDefinitions: []*myproto.TableDefinition{
&myproto.TableDefinition{
@ -125,6 +133,8 @@ func TestCopySchemaShard(t *testing.T) {
},
},
}
sourceMaster.FakeMysqlDaemon.Schema = schema
sourceRdonly.FakeMysqlDaemon.Schema = schema
createDb := "CREATE DATABASE `vt_ks` /*!40100 DEFAULT CHARACTER SET utf8 */"
createTable := "CREATE TABLE `vt_ks`.`resharding1` (\n"+
@ -146,7 +156,11 @@ func TestCopySchemaShard(t *testing.T) {
db.AddQuery(createTable, &mproto.QueryResult{})
db.AddQuery(createTableView, &mproto.QueryResult{})
if err := vp.Run([]string{"CopySchemaShard", "-include-views", sourceRdonly.Tablet.Alias.String(), "ks/-40"}); err != nil {
source := sourceRdonly.Tablet.Alias.String()
if useShardAsSource {
source = "ks/-80"
}
if err := vp.Run([]string{"CopySchemaShard", "-include-views", source, "ks/-40"}); err != nil {
t.Fatalf("CopySchemaShard failed: %v", err)
}
if count := db.GetQueryCalledNum(createDb); count != 1 {