-
Notifications
You must be signed in to change notification settings - Fork 2.4k
allow tablet picker to exclude specified tablets from its candidate list #14224
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
Changes from 10 commits
c4e4311
2ec74d2
652d8e1
ce8797a
a843d9d
a1f1af9
c052bc2
eaad958
0b4f83f
0bc2cce
ff8bfb4
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 |
|---|---|---|
|
|
@@ -386,46 +386,133 @@ func TestVStreamsCreatedAndLagMetrics(t *testing.T) { | |
| assert.Equal(t, wantVStreamsLag, vsm.vstreamsLag.Counts(), "vstreamsLag matches") | ||
| } | ||
|
|
||
| func TestVStreamRetry(t *testing.T) { | ||
| ctx, cancel := context.WithCancel(context.Background()) | ||
| defer cancel() | ||
| func TestVStreamRetriableErrors(t *testing.T) { | ||
| type testCase struct { | ||
| name string | ||
| code vtrpcpb.Code | ||
| msg string | ||
| shouldRetry bool | ||
| ignoreTablet bool | ||
| } | ||
|
|
||
| cell := "aa" | ||
| ks := "TestVStream" | ||
| _ = createSandbox(ks) | ||
| hc := discovery.NewFakeHealthCheck(nil) | ||
| tcases := []testCase{ | ||
| { | ||
| name: "failed precondition", | ||
| code: vtrpcpb.Code_FAILED_PRECONDITION, | ||
| msg: "", | ||
| shouldRetry: true, | ||
| ignoreTablet: false, | ||
| }, | ||
| { | ||
| name: "gtid mismatch", | ||
| code: vtrpcpb.Code_INVALID_ARGUMENT, | ||
| msg: "GTIDSet Mismatch aa", | ||
| shouldRetry: true, | ||
| ignoreTablet: true, | ||
| }, | ||
| { | ||
| name: "unavailable", | ||
| code: vtrpcpb.Code_UNAVAILABLE, | ||
| msg: "", | ||
| shouldRetry: true, | ||
| ignoreTablet: false, | ||
| }, | ||
| { | ||
| name: "should not retry", | ||
| code: vtrpcpb.Code_INVALID_ARGUMENT, | ||
| msg: "final error", | ||
| shouldRetry: false, | ||
| ignoreTablet: false, | ||
| }, | ||
| } | ||
|
|
||
| st := getSandboxTopo(ctx, cell, ks, []string{"-20"}) | ||
| vsm := newTestVStreamManager(ctx, hc, st, "aa") | ||
| sbc0 := hc.AddTestTablet(cell, "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_PRIMARY, true, 1, nil) | ||
| addTabletToSandboxTopo(t, ctx, st, ks, "-20", sbc0.Tablet()) | ||
| commit := []*binlogdatapb.VEvent{ | ||
| {Type: binlogdatapb.VEventType_COMMIT}, | ||
| } | ||
| sbc0.AddVStreamEvents(commit, nil) | ||
| sbc0.AddVStreamEvents(nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "aa")) | ||
| sbc0.AddVStreamEvents(commit, nil) | ||
| sbc0.AddVStreamEvents(nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "bb")) | ||
| sbc0.AddVStreamEvents(nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "cc")) | ||
| sbc0.AddVStreamEvents(nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "final error")) | ||
| var count atomic.Int32 | ||
| vgtid := &binlogdatapb.VGtid{ | ||
| ShardGtids: []*binlogdatapb.ShardGtid{{ | ||
| Keyspace: ks, | ||
| Shard: "-20", | ||
| Gtid: "pos", | ||
| }}, | ||
| } | ||
| err := vsm.VStream(ctx, topodatapb.TabletType_PRIMARY, vgtid, nil, &vtgatepb.VStreamFlags{}, func(events []*binlogdatapb.VEvent) error { | ||
| count.Add(1) | ||
| return nil | ||
| }) | ||
| wantErr := "final error" | ||
| if err == nil || !strings.Contains(err.Error(), wantErr) { | ||
| t.Errorf("vstream end: %v, must contain %v", err.Error(), wantErr) | ||
|
|
||
| want := &binlogdatapb.VStreamResponse{Events: commit} | ||
|
|
||
| for _, tcase := range tcases { | ||
| t.Run(tcase.name, func(t *testing.T) { | ||
| ctx, cancel := context.WithCancel(context.Background()) | ||
| defer cancel() | ||
|
|
||
| // aa will be the local cell for this test, but that tablet will have a vstream error. | ||
| cells := []string{"aa", "ab"} | ||
|
|
||
| ks := "TestVStream" | ||
| _ = createSandbox(ks) | ||
| hc := discovery.NewFakeHealthCheck(nil) | ||
|
|
||
| st := getSandboxTopoMultiCell(ctx, cells, ks, []string{"-20"}) | ||
|
|
||
| sbc0 := hc.AddTestTablet(cells[0], "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_REPLICA, true, 1, nil) | ||
| sbc1 := hc.AddTestTablet(cells[1], "1.1.1.1", 1002, ks, "-20", topodatapb.TabletType_REPLICA, true, 1, nil) | ||
|
|
||
| addTabletToSandboxTopo(t, ctx, st, ks, "-20", sbc0.Tablet()) | ||
| addTabletToSandboxTopo(t, ctx, st, ks, "-20", sbc1.Tablet()) | ||
|
|
||
| vsm := newTestVStreamManager(ctx, hc, st, cells[0]) | ||
|
|
||
| // Always have the local cell tablet error so it's ignored on retry and we pick the other one | ||
| // if the error requires ignoring the tablet on retry | ||
|
pbibra marked this conversation as resolved.
Outdated
|
||
| sbc0.AddVStreamEvents(nil, vterrors.Errorf(tcase.code, tcase.msg)) | ||
|
|
||
| if tcase.ignoreTablet { | ||
| sbc1.AddVStreamEvents(commit, nil) | ||
| } else { | ||
| sbc0.AddVStreamEvents(commit, nil) | ||
| } | ||
|
|
||
| vgtid := &binlogdatapb.VGtid{ | ||
| ShardGtids: []*binlogdatapb.ShardGtid{{ | ||
| Keyspace: ks, | ||
| Shard: "-20", | ||
| Gtid: "pos", | ||
| }}, | ||
| } | ||
|
|
||
| ch := make(chan *binlogdatapb.VStreamResponse) | ||
| done := make(chan struct{}) | ||
| go func() { | ||
| err := vsm.VStream(ctx, topodatapb.TabletType_REPLICA, vgtid, nil, &vtgatepb.VStreamFlags{Cells: strings.Join(cells, ",")}, func(events []*binlogdatapb.VEvent) error { | ||
| ch <- &binlogdatapb.VStreamResponse{Events: events} | ||
| return nil | ||
| }) | ||
| wantErr := "context canceled" | ||
|
|
||
| if !tcase.shouldRetry { | ||
| wantErr = tcase.msg | ||
| } | ||
|
|
||
| if err == nil || !strings.Contains(err.Error(), wantErr) { | ||
| t.Errorf("vstream end: %v, must contain %v", err.Error(), wantErr) | ||
| } | ||
| close(done) | ||
| }() | ||
|
|
||
| Loop: | ||
|
Member
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 don't think that this is needed, is it? Since there's only one for loop.
Contributor
Author
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. The break statement breaks out of the switch instead of the loop by default, so we had to label the loop |
||
| for { | ||
| if tcase.shouldRetry { | ||
| select { | ||
| case event := <-ch: | ||
| got := event.CloneVT() | ||
| if !proto.Equal(got, want) { | ||
| t.Errorf("got different vstream event than expected") | ||
| } | ||
| cancel() | ||
| case <-done: | ||
| // The goroutine has completed, so break out of the loop | ||
| break Loop | ||
| } | ||
| } else { | ||
| <-done | ||
| break Loop | ||
| } | ||
| } | ||
| }) | ||
| } | ||
| time.Sleep(100 * time.Millisecond) // wait for goroutine within VStream to finish | ||
| assert.Equal(t, int32(2), count.Load()) | ||
|
|
||
| } | ||
|
|
||
| func TestVStreamShouldNotSendSourceHeartbeats(t *testing.T) { | ||
|
|
@@ -1266,6 +1353,22 @@ func getSandboxTopo(ctx context.Context, cell string, keyspace string, shards [] | |
| return st | ||
| } | ||
|
|
||
| func getSandboxTopoMultiCell(ctx context.Context, cells []string, keyspace string, shards []string) *sandboxTopo { | ||
| st := newSandboxForCells(ctx, cells) | ||
| ts := st.topoServer | ||
|
|
||
| for _, cell := range cells { | ||
| ts.CreateCellInfo(ctx, cell, &topodatapb.CellInfo{}) | ||
| } | ||
|
|
||
| ts.CreateKeyspace(ctx, keyspace, &topodatapb.Keyspace{}) | ||
|
|
||
| for _, shard := range shards { | ||
| ts.CreateShard(ctx, keyspace, shard) | ||
| } | ||
| return st | ||
| } | ||
|
|
||
| func addTabletToSandboxTopo(t *testing.T, ctx context.Context, st *sandboxTopo, ks, shard string, tablet *topodatapb.Tablet) { | ||
| _, err := st.topoServer.UpdateShardFields(ctx, ks, shard, func(si *topo.ShardInfo) error { | ||
| si.PrimaryAlias = tablet.Alias | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.