Skip to content

Commit 30e7c9e

Browse files
[release-20.0] Tablet picker: Handle the case where a primary tablet is not setup for a shard (#17573) (#17575)
Signed-off-by: Rohit Nayak <rohit@planetscale.com> Co-authored-by: vitess-bot[bot] <108069721+vitess-bot[bot]@users.noreply.github.com> Co-authored-by: Rohit Nayak <rohit@planetscale.com>
1 parent be08a65 commit 30e7c9e

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

go/vt/discovery/tablet_picker.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,13 @@ func (tp *TabletPicker) GetMatchingTablets(ctx context.Context) []*topo.TabletIn
388388
log.Errorf("Error getting shard %s/%s: %v", tp.keyspace, tp.shard, err)
389389
return nil
390390
}
391-
if _, ignore := tp.ignoreTablets[si.PrimaryAlias.String()]; !ignore {
392-
aliases = append(aliases, si.PrimaryAlias)
391+
392+
// It is possible that there is a cluster event (ERS/PRS, for example) due to which
393+
// there is no primary elected for the shard at the moment.
394+
if si.PrimaryAlias != nil {
395+
if _, ignore := tp.ignoreTablets[si.PrimaryAlias.String()]; !ignore {
396+
aliases = append(aliases, si.PrimaryAlias)
397+
}
393398
}
394399
} else {
395400
actualCells := make([]string, 0)
@@ -426,6 +431,9 @@ func (tp *TabletPicker) GetMatchingTablets(ctx context.Context) []*topo.TabletIn
426431
continue
427432
}
428433
for _, node := range sri.Nodes {
434+
if node.TabletAlias == nil {
435+
continue
436+
}
429437
if _, ignore := tp.ignoreTablets[node.TabletAlias.String()]; !ignore {
430438
aliases = append(aliases, node.TabletAlias)
431439
}

go/vt/discovery/tablet_picker_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,29 @@ func TestPickPrimary(t *testing.T) {
6262
assert.True(t, proto.Equal(want, tablet), "Pick: %v, want %v", tablet, want)
6363
}
6464

65+
// TestPickNoPrimary confirms that if the picker was setup only for primary tablets but
66+
// there is no primary setup for the shard we correctly return an error.
67+
func TestPickNoPrimary(t *testing.T) {
68+
defer utils.EnsureNoLeaks(t)
69+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
70+
defer cancel()
71+
72+
te := newPickerTestEnv(t, ctx, []string{"cell", "otherCell"})
73+
want := addTablet(ctx, te, 100, topodatapb.TabletType_PRIMARY, "cell", true, true)
74+
defer deleteTablet(t, te, want)
75+
_, err := te.topoServ.UpdateShardFields(ctx, te.keyspace, te.shard, func(si *topo.ShardInfo) error {
76+
si.PrimaryAlias = nil // force a missing primary
77+
return nil
78+
})
79+
require.NoError(t, err)
80+
81+
tp, err := NewTabletPicker(ctx, te.topoServ, []string{"otherCell"}, "cell", te.keyspace, te.shard, "primary", TabletPickerOptions{})
82+
require.NoError(t, err)
83+
84+
_, err = tp.PickForStreaming(ctx)
85+
require.Errorf(t, err, "No healthy serving tablet")
86+
}
87+
6588
func TestPickLocalPreferences(t *testing.T) {
6689
defer utils.EnsureNoLeaks(t)
6790
type tablet struct {

go/vt/topo/tablet.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,9 @@ func (ts *Server) GetTabletMap(ctx context.Context, tabletAliases []*topodatapb.
489489
var sem = semaphore.NewWeighted(int64(concurrency))
490490

491491
for _, tabletAlias := range tabletAliases {
492+
if tabletAlias == nil {
493+
return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "nil tablet alias in list")
494+
}
492495
wg.Add(1)
493496
go func(tabletAlias *topodatapb.TabletAlias) {
494497
defer wg.Done()

0 commit comments

Comments
 (0)