-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Experimental: Multi-tenant import support in Vitess #15128
Changes from 20 commits
7b97add
f680c67
5a89e9c
633e817
9767c52
645a313
764d39b
82412b4
95c7742
04327be
416cb18
8c21354
092d5b0
91481b9
e81e873
d2617f6
dade06e
b753df4
f46061f
c34783f
ba8e428
55c7df6
9b6b640
eedb210
afaa323
3343c15
6ab42cc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
/* | ||
Copyright 2024 The Vitess Authors. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package command | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os" | ||
"strings" | ||
|
||
"github.com/spf13/cobra" | ||
|
||
"vitess.io/vitess/go/cmd/vtctldclient/cli" | ||
"vitess.io/vitess/go/json2" | ||
|
||
vschemapb "vitess.io/vitess/go/vt/proto/vschema" | ||
vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata" | ||
) | ||
|
||
var ( | ||
// ApplyKeyspaceRoutingRules makes an ApplyKeyspaceRoutingRules gRPC call to a vtctld. | ||
ApplyKeyspaceRoutingRules = &cobra.Command{ | ||
Use: "ApplyKeyspaceRoutingRules {--rules RULES | --rules-file RULES_FILE} [--cells=c1,c2,...] [--skip-rebuild] [--dry-run]", | ||
Short: "Applies the provided keyspace routing rules.", | ||
DisableFlagsInUseLine: true, | ||
Args: cobra.NoArgs, | ||
RunE: commandApplyKeyspaceRoutingRules, | ||
} | ||
// GetKeyspaceRoutingRules makes a GetKeyspaceRoutingRules gRPC call to a vtctld. | ||
GetKeyspaceRoutingRules = &cobra.Command{ | ||
Use: "GetKeyspaceRoutingRules", | ||
Short: "Displays the currently active keyspace routing rules as a JSON document.", | ||
Long: "Displays the currently active keyspace routing rules as a JSON document.", | ||
DisableFlagsInUseLine: true, | ||
Args: cobra.NoArgs, | ||
RunE: commandGetKeyspaceRoutingRules, | ||
} | ||
) | ||
|
||
var applyKeyspaceRoutingRulesOptions = struct { | ||
Rules string | ||
RulesFilePath string | ||
Cells []string | ||
SkipRebuild bool | ||
DryRun bool | ||
}{} | ||
|
||
func commandApplyKeyspaceRoutingRules(cmd *cobra.Command, args []string) error { | ||
if applyKeyspaceRoutingRulesOptions.Rules != "" && applyKeyspaceRoutingRulesOptions.RulesFilePath != "" { | ||
return fmt.Errorf("cannot pass both --rules (=%s) and --rules-file (=%s)", applyKeyspaceRoutingRulesOptions.Rules, applyKeyspaceRoutingRulesOptions.RulesFilePath) | ||
} | ||
|
||
if applyKeyspaceRoutingRulesOptions.Rules == "" && applyKeyspaceRoutingRulesOptions.RulesFilePath == "" { | ||
return errors.New("must pass exactly one of --rules or --rules-file") | ||
} | ||
|
||
cli.FinishedParsing(cmd) | ||
|
||
var rulesBytes []byte | ||
if applyKeyspaceRoutingRulesOptions.RulesFilePath != "" { | ||
data, err := os.ReadFile(applyKeyspaceRoutingRulesOptions.RulesFilePath) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
rulesBytes = data | ||
} else { | ||
rulesBytes = []byte(applyKeyspaceRoutingRulesOptions.Rules) | ||
} | ||
|
||
srr := &vschemapb.KeyspaceRoutingRules{} | ||
if err := json2.Unmarshal(rulesBytes, &srr); err != nil { | ||
return err | ||
} | ||
// Round-trip so when we display the result it's readable. | ||
data, err := cli.MarshalJSON(srr) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if applyKeyspaceRoutingRulesOptions.DryRun { | ||
fmt.Printf("[DRY RUN] Would have saved new KeyspaceRoutingRules object:\n%s\n", data) | ||
|
||
if applyRoutingRulesOptions.SkipRebuild { | ||
fmt.Println("[DRY RUN] Would not have rebuilt VSchema graph, would have required operator to run RebuildVSchemaGraph for changes to take effect.") | ||
} else { | ||
fmt.Print("[DRY RUN] Would have rebuilt the VSchema graph") | ||
if len(applyRoutingRulesOptions.Cells) == 0 { | ||
fmt.Print(" in all cells\n") | ||
} else { | ||
fmt.Printf(" in the following cells: %s.\n", strings.Join(applyKeyspaceRoutingRulesOptions.Cells, ", ")) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
_, err = client.ApplyKeyspaceRoutingRules(commandCtx, &vtctldatapb.ApplyKeyspaceRoutingRulesRequest{ | ||
KeyspaceRoutingRules: srr, | ||
SkipRebuild: applyKeyspaceRoutingRulesOptions.SkipRebuild, | ||
RebuildCells: applyKeyspaceRoutingRulesOptions.Cells, | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Printf("New KeyspaceRoutingRules object:\n%s\nIf this is not what you expected, check the input data (as JSON parsing will skip unexpected fields).\n", data) | ||
|
||
if applyRoutingRulesOptions.SkipRebuild { | ||
fmt.Println("Skipping rebuild of VSchema graph as requested, you will need to run RebuildVSchemaGraph for the changes to take effect.") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func commandGetKeyspaceRoutingRules(cmd *cobra.Command, args []string) error { | ||
cli.FinishedParsing(cmd) | ||
|
||
resp, err := client.GetKeyspaceRoutingRules(commandCtx, &vtctldatapb.GetKeyspaceRoutingRulesRequest{}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
data, err := cli.MarshalJSON(resp.KeyspaceRoutingRules) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Printf("%s\n", data) | ||
|
||
return nil | ||
} | ||
|
||
func init() { | ||
ApplyKeyspaceRoutingRules.Flags().StringVarP(&applyKeyspaceRoutingRulesOptions.Rules, "rules", "r", "", "Shard routing rules, specified as a string") | ||
ApplyKeyspaceRoutingRules.Flags().StringVarP(&applyKeyspaceRoutingRulesOptions.RulesFilePath, "rules-file", "f", "", "Path to a file containing shard routing rules specified as JSON") | ||
ApplyKeyspaceRoutingRules.Flags().StringSliceVarP(&applyKeyspaceRoutingRulesOptions.Cells, "cells", "c", nil, "Limit the VSchema graph rebuilding to the specified cells. Ignored if --skip-rebuild is specified.") | ||
ApplyKeyspaceRoutingRules.Flags().BoolVar(&applyKeyspaceRoutingRulesOptions.SkipRebuild, "skip-rebuild", false, "Skip rebuilding the SrvVSchema objects.") | ||
ApplyKeyspaceRoutingRules.Flags().BoolVarP(&applyKeyspaceRoutingRulesOptions.DryRun, "dry-run", "d", false, "Validate the specified shard routing rules and note actions that would be taken, but do not actually apply the rules to the topo.") | ||
Root.AddCommand(ApplyKeyspaceRoutingRules) | ||
|
||
Root.AddCommand(GetKeyspaceRoutingRules) | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -47,6 +47,10 @@ func registerCommands(root *cobra.Command) { | |||||
create.Flags().StringSliceVar(&createOptions.ExcludeTables, "exclude-tables", nil, "Source tables to exclude from copying.") | ||||||
create.Flags().BoolVar(&createOptions.NoRoutingRules, "no-routing-rules", false, "(Advanced) Do not create routing rules while creating the workflow. See the reference documentation for limitations if you use this flag.") | ||||||
create.Flags().BoolVar(&createOptions.AtomicCopy, "atomic-copy", false, "(EXPERIMENTAL) A single copy phase is run for all tables from the source. Use this, for example, if your source keyspace has tables which use foreign key constraints.") | ||||||
create.Flags().StringVar(&createOptions.VReplicationWorkflowOptions.AdditionalFilter, "additional-filter", "", "Additional filter to apply to the tables being copied in addition to the default filter.") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really need to call this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I started with But I am fine if we want to just use |
||||||
create.Flags().BoolVar(&createOptions.VReplicationWorkflowOptions.UseKeyspaceRoutingRules, "use-keyspace-routing-rules", false, "Use keyspaces routing rules to route traffic to the target keyspace. This is not compatible with the --no-routing-rules flag and will override the default table routing rules mechanism.") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
deepthi marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
create.Flags().StringVar(&createOptions.VReplicationWorkflowOptions.SourceKeyspaceAlias, "source-keyspace-alias", "", "Used in conjunction with --use-keyspace-routing-rules. This value will be used instead of the source keyspace name in the keyspace routing rules.") | ||||||
|
||||||
base.AddCommand(create) | ||||||
|
||||||
opts := &common.SubCommandsOpts{ | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -168,6 +168,7 @@ func waitForQueryResult(t *testing.T, conn *mysql.Conn, database string, query s | |
for { | ||
qr := execVtgateQuery(t, conn, database, query) | ||
require.NotNil(t, qr) | ||
log.Infof("query %q returned %v", query, qr.Rows) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you want to keep this log line for merge? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed |
||
if want == fmt.Sprintf("%v", qr.Rows) { | ||
return | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about extending
ApplyRoutingRules
andGetRoutingRules
to take optional keyspace and shard arguments? Then we won't have so many separate commands. We can then also deprecate and deleteApplyShardRoutingRules
andGetShardRoutingRules
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Keyspace, Routing and Shard rules are quite different in terms of functionality. It might be better to have them separate because of that.
We can't have a table routing rule just for a shard for example. Also each of these takes a rules file and those files cannot contain a combination of table and keyspace for example.
Maybe we can have think of a RoutingRule umbrella command:
table
,keyspace
andshard
subcommands andapply
andget
actions. But it will be a non-trivial refactor.