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

VSCopy: Enable to copy from all shards in either a specified keyspace or all keyspaces #11909

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
077136b
VSCopy: Demonstrate to fail a test case on which the vstream API requ…
yoheimuta Dec 7, 2022
2f7adbc
VSCopy: Copy from all shards in all keyspaces by specifying only an e…
yoheimuta Dec 7, 2022
3afc402
tests: Make TestRowCount stable regardless of the number of keyspaces
yoheimuta Dec 7, 2022
05e5ea0
tests: Cleanup TestCreateAndDropDatabase correctly to stop TestVStrea…
yoheimuta Dec 8, 2022
013b2f0
tests: Tweak to fix a comment
yoheimuta Dec 8, 2022
fdb2b68
VSCopy: fix the unit tests when the input vgtid with an empty gtid la…
yoheimuta Dec 8, 2022
d83daaf
VSCopy: Keyspace wildcard selection lines up with the table wildcard …
yoheimuta Feb 7, 2023
71e1681
VSCopy: Tests the VCopy with multiple keyspaces and resharding
yoheimuta Feb 9, 2023
436568d
VSCopy: Make TestVStreamCopyMultiKeyspaceReshard clearer to check if …
yoheimuta Feb 9, 2023
fdc13e1
Merge remote-tracking branch 'origin/main' into vscopy-unspecified-ke…
yoheimuta Feb 9, 2023
c39af7c
VSCopy: Return an invalid argument error if shards are unspecified an…
yoheimuta Feb 10, 2023
7e67f27
VSCopy: Add a test description about its purpose and target
yoheimuta Feb 14, 2023
ca2dafd
VSCopy: Remove duplicate literals in the test
yoheimuta Feb 14, 2023
24e69b9
VSCopy: Retain defaultReplicas variable in the test
yoheimuta Feb 14, 2023
dc98a42
VSCopy: Explain why we are setting Match to 'customer.*' in the test
yoheimuta Feb 14, 2023
c2138b5
VSCopy: Remove an unused VStreamFlag for the test
yoheimuta Feb 14, 2023
6910cbc
VSCopy: Use sentence capitalization in the test
yoheimuta Feb 14, 2023
16f10b3
VSCopy: Verify that we didn't lose any events or get duplicates of th…
yoheimuta Feb 14, 2023
6a791ba
VSCopy: Return a value instead of a pointer because there is no need …
yoheimuta Feb 14, 2023
c70fa39
VSCopy: Add a comment describing what TestVStreamCopyFromAllKeyspaces…
yoheimuta Feb 14, 2023
cdc4077
VSCopy: Add a comment describing why we expect these specific numbers…
yoheimuta Feb 14, 2023
6b2d9fe
VSCopy: Tweak the test case name
yoheimuta Feb 14, 2023
a013980
VSCopy: Make a utility function to sort COPY_COMPLETED events in the …
yoheimuta Feb 14, 2023
cd119d4
VSCopy: Replace the matcher with a simpler one in the test
yoheimuta Feb 14, 2023
f7e480f
VSCopy: Move the print debug call to the FailNow section in the test
yoheimuta Feb 14, 2023
e8f0e60
VSCopy: Use require.NoError in new tests
yoheimuta Feb 14, 2023
ba8c231
VSCopy: Use require instead of t.Fatalf in the test
yoheimuta Feb 14, 2023
d730563
VSCopy: Apply the reviewer's suggestion to make the error message eas…
yoheimuta Feb 14, 2023
3b41d76
VSCopy: Add a comment noting what we're actually testing
yoheimuta Feb 14, 2023
d7169ec
VSCopy: Correct the test comment and elaborate the special-case
yoheimuta Feb 14, 2023
8970182
VSCopy: Tweak an error message and a comment
yoheimuta Feb 15, 2023
38eb575
Merge remote-tracking branch 'origin/main' into vscopy-unspecified-ke…
yoheimuta Feb 16, 2023
256400f
VSCopy: Adjust to a change in the signature of a test function that w…
yoheimuta Feb 16, 2023
94beeac
Merge remote-tracking branch 'origin/main' into vscopy-unspecified-ke…
yoheimuta Feb 24, 2023
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
68 changes: 60 additions & 8 deletions go/vt/vtgate/endtoend/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ create table t1_copy_basic(
primary key(id1)
) Engine=InnoDB;

create table t1_copy_all(
id1 bigint,
id2 bigint,
primary key(id1)
) Engine=InnoDB;

create table t1_copy_resume(
id1 bigint,
id2 bigint,
Expand Down Expand Up @@ -152,6 +158,12 @@ create table t1_sharded(
Name: "hash",
}},
},
"t1_copy_all": {
ColumnVindexes: []*vschemapb.ColumnVindex{{
Column: "id1",
Name: "hash",
}},
},
"t1_copy_resume": {
ColumnVindexes: []*vschemapb.ColumnVindex{{
Column: "id1",
Expand Down Expand Up @@ -219,6 +231,31 @@ create table t1_sharded(
},
},
}

schema2 = `
create table t1_copy_all_ks2(
id1 bigint,
id2 bigint,
primary key(id1)
) Engine=InnoDB;
`

vschema2 = &vschemapb.Keyspace{
Sharded: true,
Vindexes: map[string]*vschemapb.Vindex{
"hash": {
Type: "hash",
},
},
Tables: map[string]*vschemapb.Table{
"t1_copy_all_ks2": {
ColumnVindexes: []*vschemapb.ColumnVindex{{
Column: "id1",
Name: "hash",
}},
},
},
}
)

func TestMain(m *testing.M) {
Expand All @@ -227,21 +264,36 @@ func TestMain(m *testing.M) {
exitCode := func() int {
var cfg vttest.Config
cfg.Topology = &vttestpb.VTTestTopology{
Keyspaces: []*vttestpb.Keyspace{{
Name: "ks",
Shards: []*vttestpb.Shard{{
Name: "-80",
}, {
Name: "80-",
}},
}},
Keyspaces: []*vttestpb.Keyspace{
{
Name: "ks",
Shards: []*vttestpb.Shard{{
Name: "-80",
}, {
Name: "80-",
}},
},
{
Name: "ks2",
Shards: []*vttestpb.Shard{{
Name: "-80",
}, {
Name: "80-",
}},
},
},
}
if err := cfg.InitSchemas("ks", schema, vschema); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.RemoveAll(cfg.SchemaDir)
return 1
}
defer os.RemoveAll(cfg.SchemaDir)
if err := cfg.InitSchemas("ks2", schema2, vschema2); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.RemoveAll(cfg.SchemaDir)
return 1
}

cfg.TabletHostName = *tabletHostName

Expand Down
11 changes: 11 additions & 0 deletions go/vt/vtgate/endtoend/misc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package endtoend
import (
"context"
"fmt"
osExec "os/exec"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -55,6 +56,16 @@ func TestCreateAndDropDatabase(t *testing.T) {
require.NoError(t, err)
defer conn.Close()

// cleanup the keyspace from the topology.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

A leaked "testitest" keyspace makes TestVStreamCopyWithoutKeyspaceShard/copy_from_all_keyspaces fail.
Specifically, the VStreamer API itself fails with the below error.

E1207 19:46:02.204532   47701 tablet_picker.go:179] error getting shard testitest/0: node doesn't exist: keyspaces/testitest/shards/0/Shard

To fix it, 05e5ea0 adds a new cleanup function to delete the keyspace explicitly.

defer func() {
// the corresponding database needs to be created in advance.
// a subsequent DeleteKeyspace command returns the error of 'node doesn't exist' without it.
mattlord marked this conversation as resolved.
Show resolved Hide resolved
_ = exec(t, conn, "create database testitest")
mattlord marked this conversation as resolved.
Show resolved Hide resolved

_, err := osExec.Command("vtctldclient", "--server", grpcAddress, "DeleteKeyspace", "--recursive", "--force", "testitest").CombinedOutput()
require.NoError(t, err)
}()

// run it 3 times.
for count := 0; count < 3; count++ {
t.Run(fmt.Sprintf("exec:%d", count), func(t *testing.T) {
Expand Down
2 changes: 2 additions & 0 deletions go/vt/vtgate/endtoend/row_count_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ import (
"github.com/stretchr/testify/require"

"vitess.io/vitess/go/mysql"
"vitess.io/vitess/go/test/endtoend/utils"
)

func TestRowCount(t *testing.T) {
ctx := context.Background()
conn, err := mysql.Connect(ctx, &vtParams)
require.NoError(t, err)
defer conn.Close()
utils.Exec(t, conn, "use ks")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This use statement is now necessary because the number of keyspace is multiple. 3afc402

type tc struct {
query string
expected int
Expand Down
124 changes: 124 additions & 0 deletions go/vt/vtgate/endtoend/vstream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,130 @@ func TestVStreamCopyBasic(t *testing.T) {
}
}

func TestVStreamCopyWithoutKeyspaceShard(t *testing.T) {
mattlord marked this conversation as resolved.
Show resolved Hide resolved
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

conn, err := mysql.Connect(ctx, &vtParams)
if err != nil {
t.Fatal(err)
}
mattlord marked this conversation as resolved.
Show resolved Hide resolved
defer conn.Close()

_, err = conn.ExecuteFetch("insert into t1_copy_all(id1,id2) values(1,1), (2,2), (3,3), (4,4), (5,5), (6,6), (7,7), (8,8)", 1, false)
if err != nil {
t.Fatal(err)
}

_, err = conn.ExecuteFetch("insert into t1_copy_all_ks2(id1,id2) values(10,10), (20,20)", 1, false)
if err != nil {
t.Fatal(err)
}

filter := &binlogdatapb.Filter{
Rules: []*binlogdatapb.Rule{{
Match: "/t1_copy_all.*/",
}},
}
flags := &vtgatepb.VStreamFlags{}

expectedKs1EventNum := 2 /* num shards */ * (9 /* begin/field/vgtid:pos/4 rowevents avg/vgitd: lastpk/commit) */ + 3 /* begin/vgtid/commit for completed table */ + 1 /* copy operation completed */)
expectedKs2EventNum := 2 /* num shards */ * (6 /* begin/field/vgtid:pos/1 rowevents avg/vgitd: lastpk/commit) */ + 3 /* begin/vgtid/commit for completed table */ + 1 /* copy operation completed */)
expectedFullyCopyCompletedNum := 1
mattlord marked this conversation as resolved.
Show resolved Hide resolved

cases := []struct {
name string
shardGtid *binlogdatapb.ShardGtid
expectedEventNum int
expectedCompletedEvents []string
}{
{
name: "copy from all keyspaces",
shardGtid: &binlogdatapb.ShardGtid{
Gtid: "",
},
expectedEventNum: expectedKs1EventNum + expectedKs2EventNum + expectedFullyCopyCompletedNum,
expectedCompletedEvents: []string{
`type:COPY_COMPLETED keyspace:"ks" shard:"-80"`,
`type:COPY_COMPLETED keyspace:"ks" shard:"80-"`,
`type:COPY_COMPLETED keyspace:"ks2" shard:"-80"`,
`type:COPY_COMPLETED keyspace:"ks2" shard:"80-"`,
`type:COPY_COMPLETED`,
},
},
{
name: "copy from all shards in the keyspace",
mattlord marked this conversation as resolved.
Show resolved Hide resolved
shardGtid: &binlogdatapb.ShardGtid{
Keyspace: "ks",
Gtid: "",
},
expectedEventNum: expectedKs1EventNum + expectedFullyCopyCompletedNum,
expectedCompletedEvents: []string{
`type:COPY_COMPLETED keyspace:"ks" shard:"-80"`,
`type:COPY_COMPLETED keyspace:"ks" shard:"80-"`,
`type:COPY_COMPLETED`,
},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
gconn, conn, mconn, closeConnections := initialize(ctx, t)
defer closeConnections()

var vgtid = &binlogdatapb.VGtid{}
vgtid.ShardGtids = []*binlogdatapb.ShardGtid{c.shardGtid}
reader, err := gconn.VStream(ctx, topodatapb.TabletType_PRIMARY, vgtid, filter, flags)
_, _ = conn, mconn
if err != nil {
t.Fatal(err)
}
require.NotNil(t, reader)
var evs []*binlogdatapb.VEvent
var completedEvs []*binlogdatapb.VEvent
for {
e, err := reader.Recv()
switch err {
case nil:
evs = append(evs, e...)

for _, ev := range e {
if ev.Type == binlogdatapb.VEventType_COPY_COMPLETED {
completedEvs = append(completedEvs, ev)
}
}

printEvents(evs) // for debugging ci failures
mattlord marked this conversation as resolved.
Show resolved Hide resolved

if len(evs) == c.expectedEventNum {
// The arrival order of COPY_COMPLETED events with keyspace/shard is not constant.
// On the other hand, the last event should always be a fully COPY_COMPLETED event.
// That's why the sort.Slice doesn't have to handle the last element in completedEvs.
sort.Slice(completedEvs[:len(completedEvs)-1], func(i, j int) bool {
if completedEvs[i].GetKeyspace() != completedEvs[j].GetKeyspace() {
return completedEvs[i].GetKeyspace() < completedEvs[j].GetKeyspace()
}
return completedEvs[i].GetShard() < completedEvs[j].GetShard()
})
mattlord marked this conversation as resolved.
Show resolved Hide resolved
for i, ev := range completedEvs {
require.Regexp(t, c.expectedCompletedEvents[i], ev.String())
mattlord marked this conversation as resolved.
Show resolved Hide resolved
}
t.Logf("TestVStreamCopyWithoutKeyspaceShard was successful")
return
} else if c.expectedEventNum < len(evs) {
t.Fatalf("len(events)=%v are not expected\n", len(evs))
mattlord marked this conversation as resolved.
Show resolved Hide resolved
}
case io.EOF:
log.Infof("stream ended\n")
cancel()
Comment on lines +378 to +379
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this mean for the test? Just that we're done?

Copy link
Contributor Author

@yoheimuta yoheimuta Feb 15, 2023

Choose a reason for hiding this comment

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

I initially thought that this code was unnecessary and didn't have any meaningful purpose, but I realized that it might have been added for a specific reason based on the assumption that the existing test code was reasonable and robust. To clarify the intent behind this code, I will ask the original implementer in our chat.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi 👋 @rohit-nayak-ps
I'm wondering if I can get rid of the code that cancels the context if the stream ends unexpectedly. It looks like it's not needed, but this line doesn't run in a normal scenario, so I want to double-check it just in case.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was curious. This isn't blocking.

default:
log.Errorf("Returned err %v", err)
t.Fatalf("remote error: %v\n", err)
mattlord marked this conversation as resolved.
Show resolved Hide resolved
}
}
})
}
}

func TestVStreamCopyResume(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
Expand Down
12 changes: 2 additions & 10 deletions go/vt/vtgate/vstream_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,8 @@ func (vsm *vstreamManager) resolveParams(ctx context.Context, tabletType topodat
return nil, nil, nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "vgtid must have at least one value with a starting position")
}
// To fetch from all keyspaces, the input must contain a single ShardGtid
// that has an empty keyspace, and the Gtid must be "current". In the
// future, we'll allow the Gtid to be empty which will also support
// copying of existing data.
// that has an empty keyspace.
if len(vgtid.ShardGtids) == 1 && vgtid.ShardGtids[0].Keyspace == "" {
if vgtid.ShardGtids[0].Gtid != "current" {
return nil, nil, nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "for an empty keyspace, the Gtid value must be 'current': %v", vgtid)
}
keyspaces, err := vsm.toposerv.GetSrvKeyspaceNames(ctx, vsm.cell, false)
if err != nil {
return nil, nil, nil, err
Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer the request be more explicit as it will likely generate A LOT of load and could have a big impact on production. I think it would also be nice if the keyspace wildcard selection lined up with the table wildcard selection in binlogdata.Filter.Rule.Match, which is /.* as a valid regular expression is accepted if the string has a / prefix. So I think accepting valid regular expressions for the keyspace would be much nicer: /.*.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mattlord It makes sense in terms of the difference in impact between "streaming" and "copy."
Accepting the keyspace wildcard sounds useful. With this feature, we don't have to accept the request with an empty keyspace and empty gtid.

Do you think the following specifications are still required?

  • A special request flag, for example, "EnableEmptyKeyspace" or "EnableWildcardKeyspace" in VStreamFlags.
    • I think only the keyspace wildcard like /.* is enough.
  • The valid combination of an empty keyspace and "current" gtid.
    • While the combination of an empty keyspace and the gtid other than "current" is invalid. It complicates the code, but not so much.
    • Some may think it's better to stop accepting this input for the sake of simplicity at this moment.

As such, I plan to update accepting the keyspace wildcard and preserve the previous behavior as much as possible like the below table. What do you think?

gtid keyspace valid or invalid(=noop)
"" "" invalid because of no literal match. No change.
"current" "" valid because of the compatibility. No change.
"" "/.*" valid if found because of wildcard match. New behavior.
"current" "/.*" valid if found because of wildcard match. New behavior.
"" "/ks.*/" valid if found because of wildcard match. New behavior.
"current" "/ks.*/" valid if found because of wildcard match. New behavior.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the explicit keyspace wildcard is enough and we don't need a new flag around that.

Now that I understand the usage of current better, I think we have to keep it in place for compatibility sake. What do you think @rohit-nayak-ps ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @rohit-nayak-ps, I'd appreciate your feedback. Let me know if anything is missing.

Copy link
Contributor

Choose a reason for hiding this comment

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

@yoheimuta, sorry for the delay. I am fine with the approach outlined above.

We should add a (or modify the existing) e2e test to confirm that resharding will continue to work if multiple keyspaces are being streamed. We have code (see the logic around journaler in vstream_manager), which waits for participating shards to converge, before automatically continuing to stream from the new shards. I think it should be fine, when there are multiple keyspaces, but confirming with a test will be useful.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for your confirmation!
I'm looking into e2e test too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi 👋

@mattlord I implemented the keyspace wildcard selection by d83daaf and c39af7c.

@rohit-nayak-ps I added the e2e test by 71e1681 and 436568d

And I think the CI failure is caused by some unreliable tests because the failing test changes every time we run it and it passes when we run it locally.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks @yoheimuta, we will review it soon. Yes, that CI failure is also happening on other PRs and I have asked the related team to look at it.

Expand All @@ -194,17 +189,14 @@ func (vsm *vstreamManager) resolveParams(ctx context.Context, tabletType topodat
for _, keyspace := range keyspaces {
newvgtid.ShardGtids = append(newvgtid.ShardGtids, &binlogdatapb.ShardGtid{
Keyspace: keyspace,
Gtid: "current",
Gtid: vgtid.ShardGtids[0].Gtid,
})
}
vgtid = newvgtid
}
newvgtid := &binlogdatapb.VGtid{}
for _, sgtid := range vgtid.ShardGtids {
if sgtid.Shard == "" {
if sgtid.Gtid != "current" {
return nil, nil, nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "if shards are unspecified, the Gtid value must be 'current': %v", vgtid)
}
// TODO(sougou): this should work with the new Migrate workflow
_, _, allShards, err := vsm.resolver.GetKeyspaceShards(ctx, sgtid.Keyspace, tabletType)
if err != nil {
Expand Down
64 changes: 51 additions & 13 deletions go/vt/vtgate/vstream_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -886,16 +886,37 @@ func TestResolveVStreamParams(t *testing.T) {
err: "vgtid must have at least one value with a starting position",
}, {
input: &binlogdatapb.VGtid{
ShardGtids: []*binlogdatapb.ShardGtid{{}},
ShardGtids: []*binlogdatapb.ShardGtid{{
Keyspace: "TestVStream",
}},
Comment on lines +899 to +901
Copy link
Contributor

Choose a reason for hiding this comment

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

These test additions are unrelated to this PR, or no? I would think we would test the new behavior, which would mean NOT specifying the shards and now not getting an error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mattlord I thought they were related to this PR.
Technically, I didn't add new test cases (input & output). I changed the expected output in the following existing two cases:

  1. When the input is ShardGtids: []*binlogdatapb.ShardGtid{{}},
  2. When the input is ShardGtids: []*binlogdatapb.ShardGtid{{Keyspace: "TestVStream"}},

Copy link
Contributor

@mattlord mattlord Feb 11, 2023

Choose a reason for hiding this comment

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

Here as well I think that comments noting what we're actually testing, how, and why are helpful. The future reader won't easily see comments here on the PR. And I know that the existing code is very poorly commented, but I want to do better moving forward. 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added by 3b41d76.

},
err: "for an empty keyspace, the Gtid value must be 'current'",
}, {
input: &binlogdatapb.VGtid{
output: &binlogdatapb.VGtid{
ShardGtids: []*binlogdatapb.ShardGtid{{
Keyspace: "TestVStream",
Shard: "-20",
}, {
Keyspace: "TestVStream",
Shard: "20-40",
}, {
Keyspace: "TestVStream",
Shard: "40-60",
}, {
Keyspace: "TestVStream",
Shard: "60-80",
}, {
Keyspace: "TestVStream",
Shard: "80-a0",
}, {
Keyspace: "TestVStream",
Shard: "a0-c0",
}, {
Keyspace: "TestVStream",
Shard: "c0-e0",
}, {
Keyspace: "TestVStream",
Shard: "e0-",
}},
},
err: "if shards are unspecified, the Gtid value must be 'current'",
}, {
input: &binlogdatapb.VGtid{
ShardGtids: []*binlogdatapb.ShardGtid{{
Expand Down Expand Up @@ -987,17 +1008,34 @@ func TestResolveVStreamParams(t *testing.T) {
assert.Equal(t, wantFilter, filter, tcase.input)
require.False(t, flags.MinimizeSkew)
}

// Special-case: empty keyspace because output is too big.
input := &binlogdatapb.VGtid{
ShardGtids: []*binlogdatapb.ShardGtid{{
Gtid: "current",
}},
specialCases := []struct {
mattlord marked this conversation as resolved.
Show resolved Hide resolved
input string
output string
}{
{
input: "current",
output: "current",
},
mattlord marked this conversation as resolved.
Show resolved Hide resolved
{},
}
vgtid, _, _, err := vsm.resolveParams(context.Background(), topodatapb.TabletType_REPLICA, input, nil, nil)
require.NoError(t, err, input)
if got, want := len(vgtid.ShardGtids), 8; want >= got {
t.Errorf("len(vgtid.ShardGtids): %v, must be >%d", got, want)
for _, tcase := range specialCases {
input := &binlogdatapb.VGtid{
ShardGtids: []*binlogdatapb.ShardGtid{{
Gtid: tcase.input,
}},
}
vgtid, _, _, err := vsm.resolveParams(context.Background(), topodatapb.TabletType_REPLICA, input, nil, nil)
require.NoError(t, err, tcase.input)
if got, want := len(vgtid.ShardGtids), 8; want >= got {
t.Errorf("len(vgtid.ShardGtids): %v, must be >%d", got, want)
}
for _, s := range vgtid.ShardGtids {
require.Equal(t, tcase.output, s.Gtid)
}
}

for _, minimizeSkew := range []bool{true, false} {
t.Run(fmt.Sprintf("resolveParams MinimizeSkew %t", minimizeSkew), func(t *testing.T) {
flags := &vtgatepb.VStreamFlags{MinimizeSkew: minimizeSkew}
Expand Down
Loading