diff --git a/go/vt/discovery/tablet_picker.go b/go/vt/discovery/tablet_picker.go index e26861e0955..74010998523 100644 --- a/go/vt/discovery/tablet_picker.go +++ b/go/vt/discovery/tablet_picker.go @@ -74,12 +74,7 @@ type TabletPicker struct { // NewTabletPicker returns a TabletPicker. func NewTabletPicker(ts *topo.Server, cells []string, keyspace, shard, tabletTypesStr string) (*TabletPicker, error) { - inOrder := false - if strings.HasPrefix(tabletTypesStr, inOrderHint) { - inOrder = true - tabletTypesStr = tabletTypesStr[len(inOrderHint):] - } - tabletTypes, err := topoproto.ParseTabletTypes(tabletTypesStr) + tabletTypes, inOrder, err := ParseTabletTypesAndOrder(tabletTypesStr) if err != nil { return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "failed to parse list of tablet types: %v", tabletTypesStr) } diff --git a/go/vt/discovery/utils.go b/go/vt/discovery/utils.go index 7a9e94f019b..e7793731463 100644 --- a/go/vt/discovery/utils.go +++ b/go/vt/discovery/utils.go @@ -16,6 +16,13 @@ limitations under the License. package discovery +import ( + "strings" + + topodatapb "vitess.io/vitess/go/vt/proto/topodata" + "vitess.io/vitess/go/vt/topo/topoproto" +) + // This file contains helper filter methods to process the unfiltered list of // tablets returned by LegacyHealthCheck.GetTabletStatsFrom*. // See also legacy_replicationlag.go for a more sophisicated filter used by vtgate. @@ -37,3 +44,14 @@ func RemoveUnhealthyTablets(tabletStatsList []LegacyTabletStats) []LegacyTabletS } return result } + +func ParseTabletTypesAndOrder(tabletTypesStr string) ([]topodatapb.TabletType, bool, error) { + inOrder := false + if strings.HasPrefix(tabletTypesStr, inOrderHint) { + inOrder = true + tabletTypesStr = tabletTypesStr[len(inOrderHint):] + } + tabletTypes, err := topoproto.ParseTabletTypes(tabletTypesStr) + + return tabletTypes, inOrder, err +} diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index fc5e954624f..d20607f1c99 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -275,87 +275,167 @@ var commands = []commandGroup{ }, { "Keyspaces", []command{ - {"CreateKeyspace", commandCreateKeyspace, - "[-sharding_column_name=name] [-sharding_column_type=type] [-served_from=tablettype1:ks1,tablettype2:ks2,...] [-force] [-keyspace_type=type] [-base_keyspace=base_keyspace] [-snapshot_time=time] ", - "Creates the specified keyspace. keyspace_type can be NORMAL or SNAPSHOT. For a SNAPSHOT keyspace you must specify the name of a base_keyspace, and a snapshot_time in UTC, in RFC3339 time format, e.g. 2006-01-02T15:04:05+00:00"}, - {"DeleteKeyspace", commandDeleteKeyspace, - "[-recursive] ", - "Deletes the specified keyspace. In recursive mode, it also recursively deletes all shards in the keyspace. Otherwise, there must be no shards left in the keyspace."}, - {"RemoveKeyspaceCell", commandRemoveKeyspaceCell, - "[-force] [-recursive] ", - "Removes the cell from the Cells list for all shards in the keyspace, and the SrvKeyspace for that keyspace in that cell."}, - {"GetKeyspace", commandGetKeyspace, - "", - "Outputs a JSON structure that contains information about the Keyspace."}, - {"GetKeyspaces", commandGetKeyspaces, - "", - "Outputs a sorted list of all keyspaces."}, - {"SetKeyspaceShardingInfo", commandSetKeyspaceShardingInfo, - "[-force] [] []", - "Updates the sharding information for a keyspace."}, - {"SetKeyspaceServedFrom", commandSetKeyspaceServedFrom, - "[-source=] [-remove] [-cells=c1,c2,...] ", - "Changes the ServedFromMap manually. This command is intended for emergency fixes. This field is automatically set when you call the *MigrateServedFrom* command. This command does not rebuild the serving graph."}, - {"RebuildKeyspaceGraph", commandRebuildKeyspaceGraph, - "[-cells=c1,c2,...] [-allow_partial] ...", - "Rebuilds the serving data for the keyspace. This command may trigger an update to all connected clients."}, - {"ValidateKeyspace", commandValidateKeyspace, - "[-ping-tablets] ", - "Validates that all nodes reachable from the specified keyspace are consistent."}, - {"Reshard", commandReshard, - "[-cells=] [-tablet_types=] [-skip_schema_copy] ", - "Start a Resharding process. Example: Reshard -cells='zone1,alias1' -tablet_types='master,replica,rdonly' ks.workflow001 '0' '-80,80-'"}, - {"MoveTables", commandMoveTables, - "[-cells=] [-tablet_types=] -workflow= ", - `Move table(s) to another keyspace, table_specs is a list of tables or the tables section of the vschema for the target keyspace. Example: '{"t1":{"column_vindexes": [{"column": "id1", "name": "hash"}]}, "t2":{"column_vindexes": [{"column": "id2", "name": "hash"}]}}'. In the case of an unsharded target keyspace the vschema for each table may be empty. Example: '{"t1":{}, "t2":{}}'.`}, - {"Migrate", commandMigrate, - "[-cells=] [-tablet_types=] -workflow= ", - `Move table(s) to another keyspace, table_specs is a list of tables or the tables section of the vschema for the target keyspace. Example: '{"t1":{"column_vindexes": [{"column": "id1", "name": "hash"}]}, "t2":{"column_vindexes": [{"column": "id2", "name": "hash"}]}}'. In the case of an unsharded target keyspace the vschema for each table may be empty. Example: '{"t1":{}, "t2":{}}'.`}, - {"DropSources", commandDropSources, - "[-dry_run] [-rename_tables] ", - "After a MoveTables or Resharding workflow cleanup unused artifacts like source tables, source shards and blacklists"}, - {"CreateLookupVindex", commandCreateLookupVindex, - "[-cell= DEPRECATED] [-cells=] [-tablet_types=] ", - `Create and backfill a lookup vindex. the json_spec must contain the vindex and colvindex specs for the new lookup.`}, - {"ExternalizeVindex", commandExternalizeVindex, - ".", - `Externalize a backfilled vindex.`}, - {"Materialize", commandMaterialize, - `[-cells=] [-tablet_types=] , example : '{"workflow": "aaa", "source_keyspace": "source", "target_keyspace": "target", "table_settings": [{"target_table": "customer", "source_expression": "select * from customer", "create_ddl": "copy"}]}'`, - "Performs materialization based on the json spec. Is used directly to form VReplication rules, with an optional step to copy table structure/DDL."}, - {"SplitClone", commandSplitClone, - " ", - "Start the SplitClone process to perform horizontal resharding. Example: SplitClone ks '0' '-80,80-'"}, - {"VerticalSplitClone", commandVerticalSplitClone, - " ", - "Start the VerticalSplitClone process to perform vertical resharding. Example: SplitClone from_ks to_ks 'a,/b.*/'"}, - {"VDiff", commandVDiff, - "[-source_cell=] [-target_cell=] [-tablet_types=replica] [-filtered_replication_wait_time=30s] ", - "Perform a diff of all tables in the workflow"}, - {"MigrateServedTypes", commandMigrateServedTypes, - "[-cells=c1,c2,...] [-reverse] [-skip-refresh-state] [-filtered_replication_wait_time=30s] [-reverse_replication=false] ", - "Migrates a serving type from the source shard to the shards that it replicates to. This command also rebuilds the serving graph. The argument can specify any of the shards involved in the migration."}, - {"MigrateServedFrom", commandMigrateServedFrom, - "[-cells=c1,c2,...] [-reverse] [-filtered_replication_wait_time=30s] ", - "Makes the serve the given type. This command also rebuilds the serving graph."}, - {"SwitchReads", commandSwitchReads, - "[-cells=c1,c2,...] [-reverse] -tablet_type={replica|rdonly} [-dry-run] ", - "Switch read traffic for the specified workflow."}, - {"SwitchWrites", commandSwitchWrites, - "[-timeout=30s] [-reverse] [-reverse_replication=true] [-dry-run] ", - "Switch write traffic for the specified workflow."}, - {"CancelResharding", commandCancelResharding, - "", - "Permanently cancels a resharding in progress. All resharding related metadata will be deleted."}, - {"ShowResharding", commandShowResharding, - "", - "Displays all metadata about a resharding in progress."}, - {"FindAllShardsInKeyspace", commandFindAllShardsInKeyspace, - "", - "Displays all of the shards in the specified keyspace."}, - {"WaitForDrain", commandWaitForDrain, - "[-timeout ] [-retry_delay ] [-initial_wait ] ", - "Blocks until no new queries were observed on all tablets with the given tablet type in the specified keyspace. " + + { + name: "CreateKeyspace", + method: commandCreateKeyspace, + params: "[-sharding_column_name=name] [-sharding_column_type=type] [-served_from=tablettype1:ks1,tablettype2:ks2,...] [-force] [-keyspace_type=type] [-base_keyspace=base_keyspace] [-snapshot_time=time] ", + help: "Creates the specified keyspace. keyspace_type can be NORMAL or SNAPSHOT. For a SNAPSHOT keyspace you must specify the name of a base_keyspace, and a snapshot_time in UTC, in RFC3339 time format, e.g. 2006-01-02T15:04:05+00:00", + }, + { + name: "DeleteKeyspace", + method: commandDeleteKeyspace, + params: "[-recursive] ", + help: "Deletes the specified keyspace. In recursive mode, it also recursively deletes all shards in the keyspace. Otherwise, there must be no shards left in the keyspace.", + }, + { + name: "RemoveKeyspaceCell", + method: commandRemoveKeyspaceCell, + params: "[-force] [-recursive] ", + help: "Removes the cell from the Cells list for all shards in the keyspace, and the SrvKeyspace for that keyspace in that cell.", + }, + { + name: "GetKeyspace", + method: commandGetKeyspace, + params: "", + help: "Outputs a JSON structure that contains information about the Keyspace.", + }, + { + name: "GetKeyspaces", + method: commandGetKeyspaces, + params: "", + help: "Outputs a sorted list of all keyspaces.", + }, + { + name: "SetKeyspaceShardingInfo", + method: commandSetKeyspaceShardingInfo, + params: "[-force] [] []", + help: "Updates the sharding information for a keyspace.", + }, + { + name: "SetKeyspaceServedFrom", + method: commandSetKeyspaceServedFrom, + params: "[-source=] [-remove] [-cells=c1,c2,...] ", + help: "Changes the ServedFromMap manually. This command is intended for emergency fixes. This field is automatically set when you call the *MigrateServedFrom* command. This command does not rebuild the serving graph.", + }, + { + name: "RebuildKeyspaceGraph", + method: commandRebuildKeyspaceGraph, + params: "[-cells=c1,c2,...] [-allow_partial] ...", + help: "Rebuilds the serving data for the keyspace. This command may trigger an update to all connected clients.", + }, + { + name: "ValidateKeyspace", + method: commandValidateKeyspace, + params: "[-ping-tablets] ", + help: "Validates that all nodes reachable from the specified keyspace are consistent.", + }, + { + name: "Reshard", + method: commandReshard, + params: "[-source_shards=] [-target_shards=] [-cells=] [-tablet_types=] [-skip_schema_copy] 'action must be one of the following: Create, Complete, Cancel, SwitchTraffic, ReverseTrafffic, Show, or Progress' ", + help: "Start a Resharding process. Example: Reshard -cells='zone1,alias1' -tablet_types='MASTER,REPLICA,RDONLY' ks.workflow001 '0' '-80,80-'", + }, + { + name: "MoveTables", + method: commandMoveTables, + params: "[-source=] [-tables=] [-cells=] [-tablet_types=] [-all] [-exclude=] [-auto_start] [-stop_after_copy] 'action must be one of the following: Create, Complete, Cancel, SwitchTraffic, ReverseTrafffic, Show, or Progress' ", + help: `Move table(s) to another keyspace, table_specs is a list of tables or the tables section of the vschema for the target keyspace. Example: '{"t1":{"column_vindexes": [{"column": "id1", "name": "hash"}]}, "t2":{"column_vindexes": [{"column": "id2", "name": "hash"}]}}'. In the case of an unsharded target keyspace the vschema for each table may be empty. Example: '{"t1":{}, "t2":{}}'.`, + }, + { + name: "Migrate", + method: commandMigrate, + params: "[-cells=] [-tablet_types=] -workflow= ", + help: `Move table(s) to another keyspace, table_specs is a list of tables or the tables section of the vschema for the target keyspace. Example: '{"t1":{"column_vindexes": [{"column": "id1", "name": "hash"}]}, "t2":{"column_vindexes": [{"column": "id2", "name": "hash"}]}}'. In the case of an unsharded target keyspace the vschema for each table may be empty. Example: '{"t1":{}, "t2":{}}'.`, + }, + { + name: "DropSources", + method: commandDropSources, + params: "[-dry_run] [-rename_tables] ", + help: "After a MoveTables or Resharding workflow cleanup unused artifacts like source tables, source shards and blacklists", + }, + { + name: "CreateLookupVindex", + method: commandCreateLookupVindex, + params: "[-cell= DEPRECATED] [-cells=] [-tablet_types=] ", + help: `Create and backfill a lookup vindex. the json_spec must contain the vindex and colvindex specs for the new lookup.`, + }, + { + name: "ExternalizeVindex", + method: commandExternalizeVindex, + params: ".", + help: `Externalize a backfilled vindex.`, + }, + { + name: "Materialize", + method: commandMaterialize, + params: `[-cells=] [-tablet_types=] , example : '{"workflow": "aaa", "source_keyspace": "source", "target_keyspace": "target", "table_settings": [{"target_table": "customer", "source_expression": "select * from customer", "create_ddl": "copy"}]}'`, + help: "Performs materialization based on the json spec. Is used directly to form VReplication rules, with an optional step to copy table structure/DDL.", + }, + { + name: "SplitClone", + method: commandSplitClone, + params: " ", + help: "Start the SplitClone process to perform horizontal resharding. Example: SplitClone ks '0' '-80,80-'", + }, + { + name: "VerticalSplitClone", + method: commandVerticalSplitClone, + params: " ", + help: "Start the VerticalSplitClone process to perform vertical resharding. Example: SplitClone from_ks to_ks 'a,/b.*/'", + }, + { + name: "VDiff", + method: commandVDiff, + params: "[-source_cell=] [-target_cell=] [-tablet_types=MASTER,REPLICA,RDONLY] [-filtered_replication_wait_time=30s] ", + help: "Perform a diff of all tables in the workflow", + }, + { + name: "MigrateServedTypes", + method: commandMigrateServedTypes, + params: "[-cells=c1,c2,...] [-reverse] [-skip-refresh-state] [-filtered_replication_wait_time=30s] [-reverse_replication=false] ", + help: "Migrates a serving type from the source shard to the shards that it replicates to. This command also rebuilds the serving graph. The argument can specify any of the shards involved in the migration.", + }, + { + name: "MigrateServedFrom", + method: commandMigrateServedFrom, + params: "[-cells=c1,c2,...] [-reverse] [-filtered_replication_wait_time=30s] ", + help: "Makes the serve the given type. This command also rebuilds the serving graph.", + }, + { + name: "SwitchReads", + method: commandSwitchReads, + params: "[-cells=c1,c2,...] [-reverse] -tablet_type={replica|rdonly} [-dry-run] ", + help: "Switch read traffic for the specified workflow.", + }, + { + name: "SwitchWrites", + method: commandSwitchWrites, + params: "[-timeout=30s] [-reverse] [-reverse_replication=true] [-dry-run] ", + help: "Switch write traffic for the specified workflow.", + }, + { + name: "CancelResharding", + method: commandCancelResharding, + params: "", + help: "Permanently cancels a resharding in progress. All resharding related metadata will be deleted.", + }, + { + name: "ShowResharding", + method: commandShowResharding, + params: "", + help: "Displays all metadata about a resharding in progress.", + }, + { + name: "FindAllShardsInKeyspace", + method: commandFindAllShardsInKeyspace, + params: "", + help: "Displays all of the shards in the specified keyspace.", + }, + { + name: "WaitForDrain", + method: commandWaitForDrain, + params: "[-timeout ] [-retry_delay ] [-initial_wait ] ", + help: "Blocks until no new queries were observed on all tablets with the given tablet type in the specified keyspace. " + " This can be used as sanity check to ensure that the tablets were drained after running vtctl MigrateServedTypes " + " and vtgate is no longer using them. If -timeout is set, it fails when the timeout is reached."}, {"Mount", commandMount, @@ -1880,7 +1960,7 @@ func commandMoveTables(ctx context.Context, wr *wrangler.Wrangler, subFlags *fla workflow := subFlags.String("workflow", "", "Workflow name. Can be any descriptive string. Will be used to later migrate traffic via SwitchReads/SwitchWrites.") cells := subFlags.String("cells", "", "Cell(s) or CellAlias(es) (comma-separated) to replicate from.") - tabletTypes := subFlags.String("tablet_types", "", "Source tablet types to replicate from (e.g. master, replica, rdonly). Defaults to -vreplication_tablet_type parameter value for the tablet, which has the default value of replica.") + tabletTypes := subFlags.String("tablet_types", "", "Source tablet types to replicate from (e.g. MASTER, REPLICA, RDONLY). Defaults to --vreplication_tablet_type parameter value for the tablet, which has the default value of in_order:REPLICA,MASTER.") allTables := subFlags.Bool("all", false, "Move all tables from the source keyspace") excludes := subFlags.String("exclude", "", "Tables to exclude (comma-separated) if -all is specified") @@ -1947,7 +2027,7 @@ func commandVRWorkflow(ctx context.Context, wr *wrangler.Wrangler, subFlags *fla workflowType wrangler.VReplicationWorkflowType) error { cells := subFlags.String("cells", "", "Cell(s) or CellAlias(es) (comma-separated) to replicate from.") - tabletTypes := subFlags.String("tablet_types", "master,replica,rdonly", "Source tablet types to replicate from (e.g. master, replica, rdonly). Defaults to -vreplication_tablet_type parameter value for the tablet, which has the default value of replica.") + tabletTypes := subFlags.String("tablet_types", "in_order:REPLICA,MASTER", "Source tablet types to replicate from (e.g. MASTER, REPLICA, RDONLY). Defaults to --vreplication_tablet_type parameter value for the tablet, which has the default value of in_order:REPLICA,MASTER.") dryRun := subFlags.Bool("dry_run", false, "Does a dry run of SwitchReads and only reports the actions to be taken. -dry_run is only supported for SwitchTraffic, ReverseTraffic and Complete.") timeout := subFlags.Duration("timeout", 30*time.Second, "Specifies the maximum time to wait, in seconds, for vreplication to catch up on master migrations. The migration will be cancelled on a timeout.") reverseReplication := subFlags.Bool("reverse_replication", true, "Also reverse the replication") @@ -2101,7 +2181,7 @@ func commandVRWorkflow(ctx context.Context, wr *wrangler.Wrangler, subFlags *fla vrwp.Cells = *cells vrwp.TabletTypes = *tabletTypes if vrwp.TabletTypes == "" { - vrwp.TabletTypes = "master,replica,rdonly" + vrwp.TabletTypes = "in_order:REPLICA,MASTER" } vrwp.Timeout = *timeout vrwp.EnableReverseReplication = *reverseReplication @@ -2353,9 +2433,9 @@ func commandVerticalSplitClone(ctx context.Context, wr *wrangler.Wrangler, subFl } func commandVDiff(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { - sourceCell := subFlags.String("source_cell", "", "The source cell to compare from") - targetCell := subFlags.String("target_cell", "", "The target cell to compare with") - tabletTypes := subFlags.String("tablet_types", "master,replica,rdonly", "Tablet types for source and target") + sourceCell := subFlags.String("source_cell", "", "The source cell to compare from; default is any available cell") + targetCell := subFlags.String("target_cell", "", "The target cell to compare with; default is any available cell") + tabletTypes := subFlags.String("tablet_types", "in_order:RDONLY,REPLICA,MASTER", "Tablet types for source and target") filteredReplicationWaitTime := subFlags.Duration("filtered_replication_wait_time", 30*time.Second, "Specifies the maximum time to wait, in seconds, for filtered replication to catch up on master migrations. The migration will be cancelled on a timeout.") maxRows := subFlags.Int64("limit", math.MaxInt64, "Max rows to stop comparing after") debugQuery := subFlags.Bool("debug_query", false, "Adds a mysql query to the report that can be used for further debugging") @@ -2398,7 +2478,7 @@ func splitKeyspaceWorkflow(in string) (keyspace, workflow string, err error) { func commandMigrateServedTypes(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { cellsStr := subFlags.String("cells", "", "Specifies a comma-separated list of cells to update") reverse := subFlags.Bool("reverse", false, "Moves the served tablet type backward instead of forward.") - skipReFreshState := subFlags.Bool("skip-refresh-state", false, "Skips refreshing the state of the source tablets after the migration, meaning that the refresh will need to be done manually, replica and rdonly only)") + skipReFreshState := subFlags.Bool("skip-refresh-state", false, "Skips refreshing the state of the source tablets after the migration, meaning that the refresh will need to be done manually, REPLICA and RDONLY only)") filteredReplicationWaitTime := subFlags.Duration("filtered_replication_wait_time", 30*time.Second, "Specifies the maximum time to wait, in seconds, for filtered replication to catch up on master migrations. The migration will be cancelled on a timeout.") reverseReplication := subFlags.Bool("reverse_replication", false, "For master migration, enabling this flag reverses replication which allows you to rollback") if err := subFlags.Parse(args); err != nil { @@ -3644,7 +3724,8 @@ func printJSON(logger logutil.Logger, val interface{}) error { // mixed protobuf and non-protobuf). // // TODO(mberlin): Switch "EnumAsInts" to "false" once the frontend is -// updated and mixed types will use jsonpb as well. +// +// updated and mixed types will use jsonpb as well. func MarshalJSON(obj interface{}) (data []byte, err error) { switch obj := obj.(type) { case proto.Message: diff --git a/go/vt/vttablet/tabletmanager/vreplication/engine.go b/go/vt/vttablet/tabletmanager/vreplication/engine.go index 20528a5b98d..e21c019a6b8 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/engine.go +++ b/go/vt/vttablet/tabletmanager/vreplication/engine.go @@ -82,7 +82,7 @@ func init() { // this are the default tablet_types that will be used by the tablet picker to find sources for a vreplication stream // it can be overridden by passing a different list to the MoveTables or Reshard commands -var tabletTypesStr = flag.String("vreplication_tablet_type", "MASTER,REPLICA", "comma separated list of tablet types used as a source") +var tabletTypesStr = flag.String("vreplication_tablet_type", "in_order:REPLICA,MASTER", "comma separated list of tablet types used as a source") // waitRetryTime can be changed to a smaller value for tests. // A VReplication stream can be created by sending an insert statement @@ -328,8 +328,10 @@ func (vre *Engine) Exec(query string) (*sqltypes.Result, error) { // Exec executes the query and the related actions. // Example insert statement: // insert into _vt.vreplication +// // (workflow, source, pos, max_tps, max_replication_lag, time_updated, transaction_timestamp, state) // values ('Resharding', 'keyspace:"ks" shard:"0" tables:"a" tables:"b" ', 'MariaDB/0-1-1083', 9223372036854775807, 9223372036854775807, 481823, 0, 'Running')` +// // Example update statement: // update _vt.vreplication set state='Stopped', message='testing stop' where id=1 // Example delete: delete from _vt.vreplication where id=1 diff --git a/go/vt/wrangler/workflow.go b/go/vt/wrangler/workflow.go index 27d1f0731fe..8ee4398697f 100644 --- a/go/vt/wrangler/workflow.go +++ b/go/vt/wrangler/workflow.go @@ -8,8 +8,8 @@ import ( "time" "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/log" - "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/vtctl/workflow" "vitess.io/vitess/go/vt/vtgate/evalengine" @@ -360,25 +360,18 @@ func (vrw *VReplicationWorkflow) getCellsAsArray() []string { return nil } -func (vrw *VReplicationWorkflow) getTabletTypes() []topodatapb.TabletType { - tabletTypesArr := strings.Split(vrw.params.TabletTypes, ",") - var tabletTypes []topodatapb.TabletType - for _, tabletType := range tabletTypesArr { - servedType, _ := topoproto.ParseTabletType(tabletType) - tabletTypes = append(tabletTypes, servedType) - } - return tabletTypes -} - func (vrw *VReplicationWorkflow) parseTabletTypes() (hasReplica, hasRdonly, hasMaster bool, err error) { - tabletTypesArr := strings.Split(vrw.params.TabletTypes, ",") - for _, tabletType := range tabletTypesArr { + tabletTypes, _, err := discovery.ParseTabletTypesAndOrder(vrw.params.TabletTypes) + if err != nil { + return false, false, false, err + } + for _, tabletType := range tabletTypes { switch tabletType { - case "replica": + case topodatapb.TabletType_REPLICA: hasReplica = true - case "rdonly": + case topodatapb.TabletType_RDONLY: hasRdonly = true - case "master": + case topodatapb.TabletType_MASTER: hasMaster = true default: return false, false, false, fmt.Errorf("invalid tablet type passed %s", tabletType) @@ -406,15 +399,18 @@ func (vrw *VReplicationWorkflow) initReshard() error { func (vrw *VReplicationWorkflow) switchReads() (*[]string, error) { log.Infof("In VReplicationWorkflow.switchReads() for %+v", vrw) - var tabletTypes []topodatapb.TabletType - for _, tt := range vrw.getTabletTypes() { + fullTabletTypes, _, err := discovery.ParseTabletTypesAndOrder(vrw.params.TabletTypes) + if err != nil { + return nil, err + } + var nonPrimaryTabletTypes []topodatapb.TabletType + for _, tt := range fullTabletTypes { if tt != topodatapb.TabletType_MASTER { - tabletTypes = append(tabletTypes, tt) + nonPrimaryTabletTypes = append(nonPrimaryTabletTypes, tt) } } var dryRunResults *[]string - var err error - dryRunResults, err = vrw.wr.SwitchReads(vrw.ctx, vrw.params.TargetKeyspace, vrw.params.Workflow, tabletTypes, + dryRunResults, err = vrw.wr.SwitchReads(vrw.ctx, vrw.params.TargetKeyspace, vrw.params.Workflow, nonPrimaryTabletTypes, vrw.getCellsAsArray(), vrw.params.Direction, vrw.params.DryRun) if err != nil { return nil, err diff --git a/go/vt/wrangler/workflow_test.go b/go/vt/wrangler/workflow_test.go index 4b97d62b908..8157feab4b6 100644 --- a/go/vt/wrangler/workflow_test.go +++ b/go/vt/wrangler/workflow_test.go @@ -24,6 +24,7 @@ import ( "github.com/stretchr/testify/require" "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/proto/topodata" "vitess.io/vitess/go/vt/topo" @@ -65,8 +66,11 @@ func TestReshardingWorkflowErrorsAndMisc(t *testing.T) { mtwf.ws.WritesSwitched = true require.Errorf(t, mtwf.Cancel(), ErrWorkflowPartiallySwitched) + tabletTypes, _, err := discovery.ParseTabletTypesAndOrder(mtwf.params.TabletTypes) + require.NoError(t, err) + require.ElementsMatch(t, mtwf.getCellsAsArray(), []string{"cell1", "cell2"}) - require.ElementsMatch(t, mtwf.getTabletTypes(), []topodata.TabletType{topodata.TabletType_REPLICA, topodata.TabletType_RDONLY}) + require.ElementsMatch(t, tabletTypes, []topodata.TabletType{topodata.TabletType_REPLICA, topodata.TabletType_RDONLY}) hasReplica, hasRdonly, hasMaster, err := mtwf.parseTabletTypes() require.NoError(t, err) require.True(t, hasReplica) @@ -74,7 +78,9 @@ func TestReshardingWorkflowErrorsAndMisc(t *testing.T) { require.False(t, hasMaster) mtwf.params.TabletTypes = "replica,rdonly,master" - require.ElementsMatch(t, mtwf.getTabletTypes(), + tabletTypes, _, err = discovery.ParseTabletTypesAndOrder(mtwf.params.TabletTypes) + require.NoError(t, err) + require.ElementsMatch(t, tabletTypes, []topodata.TabletType{topodata.TabletType_REPLICA, topodata.TabletType_RDONLY, topodata.TabletType_MASTER}) hasReplica, hasRdonly, hasMaster, err = mtwf.parseTabletTypes()