Skip to content
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

Closed
Closed
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7b97add
Initial commit for adding filter clause to MoveTables. Working e2e test.
rohit-nayak-ps Feb 4, 2024
f680c67
Fix failing unit tests
rohit-nayak-ps Feb 5, 2024
5a89e9c
Fix failing unit and e2e tests
rohit-nayak-ps Feb 5, 2024
633e817
fix failing unit tests
rohit-nayak-ps Feb 5, 2024
9767c52
Fix incorrect logic for getting reverse replication filter
rohit-nayak-ps Feb 5, 2024
645a313
Fix vreplication unit tests
rohit-nayak-ps Feb 6, 2024
764d39b
Fix logic for adding additional filter in reverse workflows
rohit-nayak-ps Feb 6, 2024
82412b4
Fix a bunch of failing unit tests
rohit-nayak-ps Feb 6, 2024
95c7742
Add Keyspace Routing Rules to proto and functions to get/put the rules
rohit-nayak-ps Feb 6, 2024
04327be
Use keyspace routing rules in vtgate
rohit-nayak-ps Feb 6, 2024
416cb18
Remove compressed rules for now, until we come up with a better abstr…
rohit-nayak-ps Feb 7, 2024
8c21354
Add flags for keyspace routing rules in MoveTables. Add rules when cr…
rohit-nayak-ps Feb 7, 2024
092d5b0
Working e2e test for single tenant migration with keyspace routing ru…
rohit-nayak-ps Feb 9, 2024
91481b9
Protect map access with mutexes in e2e test. Make function scope priv…
rohit-nayak-ps Feb 9, 2024
e81e873
Make proto
rohit-nayak-ps Feb 9, 2024
d2617f6
Fix failing unit tests
rohit-nayak-ps Feb 9, 2024
dade06e
Generate flags help text
rohit-nayak-ps Feb 9, 2024
b753df4
Fix failing unit tests
rohit-nayak-ps Feb 10, 2024
f46061f
Improve e2e test by creating more tenants and randomize the workflow …
rohit-nayak-ps Feb 12, 2024
c34783f
Compression tests
rohit-nayak-ps Mar 4, 2024
ba8e428
Revert compression test. For now we are going to assume keyspace rout…
rohit-nayak-ps Mar 5, 2024
55c7df6
Address a couple of review comments
rohit-nayak-ps Mar 5, 2024
9b6b640
Address more review comments. Refactor the e2e test.The refactor of F…
rohit-nayak-ps Mar 5, 2024
eedb210
Allow creating new MoveTables workflows when there are previous Froze…
rohit-nayak-ps Mar 5, 2024
afaa323
Fix unit tests for removal of the frozen check
rohit-nayak-ps Mar 5, 2024
3343c15
Reduce number of tenants in e2e test to make it run in a reasonable t…
rohit-nayak-ps Mar 5, 2024
6ab42cc
Fix check in reverse traffic to account for keyspace routing rules. A…
rohit-nayak-ps Mar 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ require (
require (
github.com/DataDog/datadog-go/v5 v5.5.0
github.com/Shopify/toxiproxy/v2 v2.7.0
github.com/andybalholm/brotli v1.0.6
github.com/bndr/gotabulate v1.1.2
github.com/gammazero/deque v0.2.1
github.com/google/safehtml v0.1.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/aquarapid/vaultlib v0.5.1 h1:vuLWR6bZzLHybjJBSUYPgZlIp6KZ+SXeHLRRYTuk6d4=
github.com/aquarapid/vaultlib v0.5.1/go.mod h1:yT7AlEXtuabkxylOc/+Ulyp18tff1+QjgNLTnFWTlOs=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
Expand Down
157 changes: 157 additions & 0 deletions go/cmd/vtctldclient/command/keyspace_routing_rules.go
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{
Copy link
Member

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 and GetRoutingRules to take optional keyspace and shard arguments? Then we won't have so many separate commands. We can then also deprecate and delete ApplyShardRoutingRules and GetShardRoutingRules.

Copy link
Contributor Author

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 and shardsubcommands and apply andget actions. But it will be a non-trivial refactor.

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)
}
54 changes: 28 additions & 26 deletions go/cmd/vtctldclient/command/vreplication/movetables/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,16 @@ import (

var (
createOptions = struct {
SourceKeyspace string
SourceShards []string
ExternalClusterName string
AllTables bool
IncludeTables []string
ExcludeTables []string
SourceTimeZone string
NoRoutingRules bool
AtomicCopy bool
SourceKeyspace string
SourceShards []string
ExternalClusterName string
AllTables bool
IncludeTables []string
ExcludeTables []string
SourceTimeZone string
NoRoutingRules bool
AtomicCopy bool
VReplicationWorkflowOptions vtctldatapb.VReplicationWorkflowOptions
}{}

// create makes a MoveTablesCreate gRPC call to a vtctld.
Expand Down Expand Up @@ -92,23 +93,24 @@ func commandCreate(cmd *cobra.Command, args []string) error {
cli.FinishedParsing(cmd)

req := &vtctldatapb.MoveTablesCreateRequest{
Workflow: common.BaseOptions.Workflow,
TargetKeyspace: common.BaseOptions.TargetKeyspace,
SourceKeyspace: createOptions.SourceKeyspace,
SourceShards: createOptions.SourceShards,
SourceTimeZone: createOptions.SourceTimeZone,
Cells: common.CreateOptions.Cells,
TabletTypes: common.CreateOptions.TabletTypes,
TabletSelectionPreference: tsp,
AllTables: createOptions.AllTables,
IncludeTables: createOptions.IncludeTables,
ExcludeTables: createOptions.ExcludeTables,
OnDdl: common.CreateOptions.OnDDL,
DeferSecondaryKeys: common.CreateOptions.DeferSecondaryKeys,
AutoStart: common.CreateOptions.AutoStart,
StopAfterCopy: common.CreateOptions.StopAfterCopy,
NoRoutingRules: createOptions.NoRoutingRules,
AtomicCopy: createOptions.AtomicCopy,
Workflow: common.BaseOptions.Workflow,
TargetKeyspace: common.BaseOptions.TargetKeyspace,
SourceKeyspace: createOptions.SourceKeyspace,
SourceShards: createOptions.SourceShards,
SourceTimeZone: createOptions.SourceTimeZone,
Cells: common.CreateOptions.Cells,
TabletTypes: common.CreateOptions.TabletTypes,
TabletSelectionPreference: tsp,
AllTables: createOptions.AllTables,
IncludeTables: createOptions.IncludeTables,
ExcludeTables: createOptions.ExcludeTables,
OnDdl: common.CreateOptions.OnDDL,
DeferSecondaryKeys: common.CreateOptions.DeferSecondaryKeys,
AutoStart: common.CreateOptions.AutoStart,
StopAfterCopy: common.CreateOptions.StopAfterCopy,
NoRoutingRules: createOptions.NoRoutingRules,
AtomicCopy: createOptions.AtomicCopy,
VReplicationWorkflowOptions: &createOptions.VReplicationWorkflowOptions,
}

resp, err := common.GetClient().MoveTablesCreate(common.GetCommandCtx(), req)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to call this additional-filter? Why can't it just be filter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started with -filter and then realized that we also use filter in the _vt.vreplication row and we will not be using the value provided for this option as the filter but as an additional clause.

But I am fine if we want to just use -filter.

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.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.")
create.Flags().BoolVar(&createOptions.VReplicationWorkflowOptions.UseKeyspaceRoutingRules, "use-keyspace-routing-rules", false, "Use keyspace 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.")

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{
Expand Down
2 changes: 2 additions & 0 deletions go/flags/endtoend/vtctldclient.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Usage:
Available Commands:
AddCellInfo Registers a local topology service in a new cell by creating the CellInfo.
AddCellsAlias Defines a group of cells that can be referenced by a single name (the alias).
ApplyKeyspaceRoutingRules Applies the provided keyspace routing rules.
ApplyRoutingRules Applies the VSchema routing rules.
ApplySchema Applies the schema change to the specified keyspace on every primary, running in parallel on all shards. The changes are then propagated to replicas via replication.
ApplyShardRoutingRules Applies the provided shard routing rules.
Expand Down Expand Up @@ -38,6 +39,7 @@ Available Commands:
GetCellsAliases Gets all CellsAlias objects in the cluster.
GetFullStatus Outputs a JSON structure that contains full status of MySQL including the replication information, semi-sync information, GTID information among others.
GetKeyspace Returns information about the given keyspace from the topology.
GetKeyspaceRoutingRules Displays the currently active keyspace routing rules as a JSON document.
GetKeyspaces Returns information about every keyspace in the topology.
GetPermissions Displays the permissions for a tablet.
GetRoutingRules Displays the VSchema routing rules.
Expand Down
1 change: 1 addition & 0 deletions go/test/endtoend/vreplication/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to keep this log line for merge?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

if want == fmt.Sprintf("%v", qr.Rows) {
return
}
Expand Down
Loading
Loading