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

vttablet/tabletmanager: add isInSRVKeyspace/isShardServing #7929

Merged
merged 2 commits into from
Apr 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions go/vt/vttablet/tabletmanager/tm_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ var (
// statsBackupIsRunning is set to 1 (true) if a backup is running.
statsBackupIsRunning *stats.GaugesWithMultiLabels

// statsIsInSrvKeyspace is set to 1 (true), 0 (false) whether the tablet is in the serving keyspace
statsIsInSrvKeyspace *stats.Gauge

statsKeyspace = stats.NewString("TabletKeyspace")
statsShard = stats.NewString("TabletShard")
statsKeyRangeStart = stats.NewString("TabletKeyRangeStart")
Expand All @@ -115,6 +118,7 @@ func init() {
statsTabletType = stats.NewString("TabletType")
statsTabletTypeCount = stats.NewCountersWithSingleLabel("TabletTypeCount", "Number of times the tablet changed to the labeled type", "type")
statsBackupIsRunning = stats.NewGaugesWithMultiLabels("BackupIsRunning", "Whether a backup is running", []string{"mode"})
statsIsInSrvKeyspace = stats.NewGauge("IsInSrvKeyspace", "Whether the vttablet is in the serving keyspace (1 = true / 0 = false)")
}

// TabletManager is the main class for the tablet manager.
Expand Down
19 changes: 19 additions & 0 deletions go/vt/vttablet/tabletmanager/tm_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ type tmState struct {
mu sync.Mutex
isOpen bool
isResharding bool
isInSrvKeyspace bool
isShardServing map[topodatapb.TabletType]bool
tabletControls map[topodatapb.TabletType]bool
blacklistedTables map[topodatapb.TabletType][]string
tablet *topodatapb.Tablet
Expand Down Expand Up @@ -139,8 +141,17 @@ func (ts *tmState) RefreshFromTopoInfo(ctx context.Context, shardInfo *topo.Shar
}

if srvKeyspace != nil {
ts.isShardServing = make(map[topodatapb.TabletType]bool)
ts.tabletControls = make(map[topodatapb.TabletType]bool)

for _, partition := range srvKeyspace.GetPartitions() {

for _, shard := range partition.GetShardReferences() {
if key.KeyRangeEqual(shard.GetKeyRange(), ts.tablet.KeyRange) {
ts.isShardServing[partition.GetServedType()] = true
}
}

for _, tabletControl := range partition.GetShardTabletControls() {
if key.KeyRangeEqual(tabletControl.GetKeyRange(), ts.KeyRange()) {
if tabletControl.QueryServiceDisabled {
Expand Down Expand Up @@ -252,6 +263,14 @@ func (ts *tmState) updateLocked(ctx context.Context) {
}
}

if ts.isShardServing[ts.tablet.Type] {
ts.isInSrvKeyspace = true
statsIsInSrvKeyspace.Set(1)
} else {
ts.isInSrvKeyspace = false
statsIsInSrvKeyspace.Set(0)
}

// Open TabletServer last so that it advertises serving after all other services are up.
if reason == "" {
if err := ts.tm.QueryServiceControl.SetServingType(ts.tablet.Type, terTime, true, ""); err != nil {
Expand Down
153 changes: 153 additions & 0 deletions go/vt/vttablet/tabletmanager/tm_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"testing"
"time"

"vitess.io/vitess/go/vt/key"
"vitess.io/vitess/go/vt/servenv"

"context"
Expand Down Expand Up @@ -154,6 +155,158 @@ func TestStateTabletControls(t *testing.T) {
assert.False(t, qsc.IsServing())
}

func TestStateIsShardServingisInSrvKeyspace(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

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

If we want to be super throughout with the testing, we should also assert that the gauge ends up with the expected values when we call func (ts *tmState) Open(). That's one more place where updateLocked will be called and we expect the gauge to be updated.

Adding this test, will make sure that we will detect a regression if the Open method is refactored and no longer calls updateLocked.

Copy link
Member Author

Choose a reason for hiding this comment

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

Make sense, let me add that. Thanks!

ctx := context.Background()
ts := memorytopo.NewServer("cell1")
tm := newTestTM(t, ts, 1, "ks", "0")
defer tm.Stop()

tm.tmState.mu.Lock()
tm.tmState.tablet.Type = topodatapb.TabletType_MASTER
tm.tmState.mu.Unlock()

leftKeyRange, err := key.ParseShardingSpec("-80")
if err != nil || len(leftKeyRange) != 1 {
t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange))
}

rightKeyRange, err := key.ParseShardingSpec("80-")
if err != nil || len(rightKeyRange) != 1 {
t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange))
}

keyRange, err := key.ParseShardingSpec("0")
if err != nil || len(keyRange) != 1 {
t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(keyRange))
}

// Shard not in the SrvKeyspace, ServedType not in SrvKeyspace
ks := &topodatapb.SrvKeyspace{
Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
{
ServedType: topodatapb.TabletType_DRAINED,
ShardReferences: []*topodatapb.ShardReference{
{
Name: "-80",
KeyRange: leftKeyRange[0],
},
{
Name: "80-",
KeyRange: rightKeyRange[0],
},
},
},
},
}
want := map[topodatapb.TabletType]bool{}
tm.tmState.RefreshFromTopoInfo(ctx, nil, ks)

tm.tmState.mu.Lock()
assert.False(t, tm.tmState.isInSrvKeyspace)
assert.Equal(t, want, tm.tmState.isShardServing)
tm.tmState.mu.Unlock()

assert.Equal(t, int64(0), statsIsInSrvKeyspace.Get())

// Shard not in the SrvKeyspace, ServedType in SrvKeyspace
ks = &topodatapb.SrvKeyspace{
Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
{
ServedType: topodatapb.TabletType_MASTER,
ShardReferences: []*topodatapb.ShardReference{
{
Name: "-80",
KeyRange: leftKeyRange[0],
},
{
Name: "80-",
KeyRange: rightKeyRange[0],
},
},
},
},
}
want = map[topodatapb.TabletType]bool{}
tm.tmState.RefreshFromTopoInfo(ctx, nil, ks)

tm.tmState.mu.Lock()
assert.False(t, tm.tmState.isInSrvKeyspace)
assert.Equal(t, want, tm.tmState.isShardServing)
tm.tmState.mu.Unlock()

assert.Equal(t, int64(0), statsIsInSrvKeyspace.Get())

// Shard in the SrvKeyspace, ServedType in the SrvKeyspace
ks = &topodatapb.SrvKeyspace{
Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
{
ServedType: topodatapb.TabletType_MASTER,
ShardReferences: []*topodatapb.ShardReference{
{
Name: "0",
KeyRange: keyRange[0],
},
},
},
},
}
want = map[topodatapb.TabletType]bool{
topodatapb.TabletType_MASTER: true,
}
tm.tmState.RefreshFromTopoInfo(ctx, nil, ks)

tm.tmState.mu.Lock()
assert.True(t, tm.tmState.isInSrvKeyspace)
assert.Equal(t, want, tm.tmState.isShardServing)
tm.tmState.mu.Unlock()

assert.Equal(t, int64(1), statsIsInSrvKeyspace.Get())

// Shard in the SrvKeyspace, ServedType not in the SrvKeyspace
ks = &topodatapb.SrvKeyspace{
Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{
{
ServedType: topodatapb.TabletType_RDONLY,
ShardReferences: []*topodatapb.ShardReference{
{
Name: "0",
KeyRange: keyRange[0],
},
},
},
},
}
want = map[topodatapb.TabletType]bool{
topodatapb.TabletType_RDONLY: true,
}
tm.tmState.RefreshFromTopoInfo(ctx, nil, ks)

tm.tmState.mu.Lock()
assert.False(t, tm.tmState.isInSrvKeyspace)
assert.Equal(t, want, tm.tmState.isShardServing)
tm.tmState.mu.Unlock()

assert.Equal(t, int64(0), statsIsInSrvKeyspace.Get())

// Test tablet type change - shard in the SrvKeyspace, ServedType in the SrvKeyspace
err = tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_RDONLY, DBActionNone)
require.NoError(t, err)
tm.tmState.mu.Lock()
assert.True(t, tm.tmState.isInSrvKeyspace)
tm.tmState.mu.Unlock()

assert.Equal(t, int64(1), statsIsInSrvKeyspace.Get())

// Test tablet type change - shard in the SrvKeyspace, ServedType in the SrvKeyspace
err = tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_DRAINED, DBActionNone)
require.NoError(t, err)
tm.tmState.mu.Lock()
assert.False(t, tm.tmState.isInSrvKeyspace)
tm.tmState.mu.Unlock()

assert.Equal(t, int64(0), statsIsInSrvKeyspace.Get())
}

func TestStateNonServing(t *testing.T) {
ctx := context.Background()
ts := memorytopo.NewServer("cell1")
Expand Down