From 5389714d530fc63a6e008383511067f90c92817c Mon Sep 17 00:00:00 2001 From: deepthi Date: Thu, 30 Apr 2020 13:29:07 -0700 Subject: [PATCH] Print MasterTermStartTime in ListAllTablets, ListTablets, ListShardTablets. In case of an old master, we replace the timestamp displayed with "defunct". Also show MasterTermStartTime in output of "show vitess_tablets" from vtgate. Signed-off-by: deepthi --- go.mod | 1 + go.sum | 1 + go/vt/discovery/fake_healthcheck.go | 5 +++ go/vt/vtctl/vtctl.go | 55 +++++++++++++++++++++++++-- go/vt/vtctl/vtctlclienttest/client.go | 10 ++--- go/vt/vtgate/executor.go | 10 ++++- go/vt/vtgate/executor_test.go | 6 +-- 7 files changed, 76 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 7b25d972eb..0fbd71309d 100644 --- a/go.mod +++ b/go.mod @@ -86,6 +86,7 @@ require ( gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect gopkg.in/ini.v1 v1.51.0 // indirect gopkg.in/ldap.v2 v2.5.0 + gotest.tools v2.2.0+incompatible honnef.co/go/tools v0.0.1-2019.2.3 k8s.io/apiextensions-apiserver v0.17.3 k8s.io/apimachinery v0.17.3 diff --git a/go.sum b/go.sum index d58ca54346..b367981a54 100644 --- a/go.sum +++ b/go.sum @@ -754,6 +754,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/go/vt/discovery/fake_healthcheck.go b/go/vt/discovery/fake_healthcheck.go index 4e9f0369c2..ed3fe2a599 100644 --- a/go/vt/discovery/fake_healthcheck.go +++ b/go/vt/discovery/fake_healthcheck.go @@ -19,6 +19,9 @@ package discovery import ( "sort" "sync" + "time" + + "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" @@ -179,6 +182,8 @@ func (fhc *FakeHealthCheck) AddFakeTablet(cell, host string, port int32, keyspac t.Shard = shard t.Type = tabletType t.PortMap["vt"] = port + // reparentTS only has precision to seconds + t.MasterTermStartTime = logutil.TimeToProto(time.Unix(reparentTS, 0)) key := TabletToMapKey(t) fhc.mu.Lock() diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index 3949e22843..e2f599afa6 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -514,15 +514,41 @@ func fmtTabletAwkable(ti *topo.TabletInfo) string { if shard == "" { shard = "" } - return fmt.Sprintf("%v %v %v %v %v %v %v", topoproto.TabletAliasString(ti.Alias), keyspace, shard, topoproto.TabletTypeLString(ti.Type), ti.Addr(), ti.MysqlAddr(), fmtMapAwkable(ti.Tags)) + mtst := "" + // special case for old master that hasn't updated topo yet + if ti.MasterTermStartTime != nil { + if ti.MasterTermStartTime.Seconds == -1 { + mtst = "defunct" + } + if ti.MasterTermStartTime.Seconds > 0 { + mtst = logutil.ProtoToTime(ti.MasterTermStartTime).Format(time.RFC3339) + } + } + return fmt.Sprintf("%v %v %v %v %v %v %v %v", topoproto.TabletAliasString(ti.Alias), keyspace, shard, topoproto.TabletTypeLString(ti.Type), ti.Addr(), ti.MysqlAddr(), fmtMapAwkable(ti.Tags), mtst) } func listTabletsByShard(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string) error { - tabletAliases, err := wr.TopoServer().FindAllTabletAliasesInShard(ctx, keyspace, shard) + tabletMap, err := wr.TopoServer().GetTabletMapForShard(ctx, keyspace, shard) if err != nil { return err } - return dumpTablets(ctx, wr, tabletAliases) + var trueMasterTimestamp time.Time + for _, ti := range tabletMap { + if ti.Type == topodatapb.TabletType_MASTER { + masterTimestamp := logutil.ProtoToTime(ti.MasterTermStartTime) + if masterTimestamp.After(trueMasterTimestamp) { + trueMasterTimestamp = masterTimestamp + } + } + } + for _, ti := range tabletMap { + masterTimestamp := logutil.ProtoToTime(ti.MasterTermStartTime) + if ti.Type == topodatapb.TabletType_MASTER && masterTimestamp.Before(trueMasterTimestamp) { + ti.MasterTermStartTime.Seconds = -1 + } + wr.Logger().Printf("%v\n", fmtTabletAwkable(ti)) + } + return nil } func dumpAllTablets(ctx context.Context, wr *wrangler.Wrangler, cell string) error { @@ -530,12 +556,35 @@ func dumpAllTablets(ctx context.Context, wr *wrangler.Wrangler, cell string) err if err != nil { return err } + // It is possible that an old master has not yet updated it's type in the topo + // In that case, replace timestamp with `defunct` + trueMasterTimestamps := findTrueMasterTimestamps(tablets) for _, ti := range tablets { + key := ti.Keyspace + "." + ti.Shard + masterTimestamp := logutil.ProtoToTime(ti.MasterTermStartTime) + if ti.Type == topodatapb.TabletType_MASTER && masterTimestamp.Before(trueMasterTimestamps[key]) { + ti.MasterTermStartTime.Seconds = -1 + } wr.Logger().Printf("%v\n", fmtTabletAwkable(ti)) } return nil } +func findTrueMasterTimestamps(tablets []*topo.TabletInfo) map[string]time.Time { + result := make(map[string]time.Time) + for _, ti := range tablets { + key := ti.Keyspace + "." + ti.Shard + if v, ok := result[key]; !ok { + result[key] = logutil.ProtoToTime(ti.MasterTermStartTime) + } else { + if logutil.ProtoToTime(ti.MasterTermStartTime).After(v) { + result[key] = logutil.ProtoToTime(ti.MasterTermStartTime) + } + } + } + return result +} + func dumpTablets(ctx context.Context, wr *wrangler.Wrangler, tabletAliases []*topodatapb.TabletAlias) error { tabletMap, err := wr.TopoServer().GetTabletMap(ctx, tabletAliases) if err != nil { diff --git a/go/vt/vtctl/vtctlclienttest/client.go b/go/vt/vtctl/vtctlclienttest/client.go index 9ec2684dba..ba5d085f2c 100644 --- a/go/vt/vtctl/vtctlclienttest/client.go +++ b/go/vt/vtctl/vtctlclienttest/client.go @@ -68,10 +68,10 @@ func TestSuite(t *testing.T, ts *topo.Server, client vtctlclient.VtctlClient) { PortMap: map[string]int32{ "vt": 3333, }, - - Tags: map[string]string{"tag": "value"}, - Keyspace: "test_keyspace", - Type: topodatapb.TabletType_MASTER, + MasterTermStartTime: logutil.TimeToProto(time.Date(1970, 1, 1, 1, 1, 1, 1, time.UTC)), + Tags: map[string]string{"tag": "value"}, + Keyspace: "test_keyspace", + Type: topodatapb.TabletType_MASTER, } topoproto.SetMysqlPort(tablet, 3334) if err := ts.CreateTablet(ctx, tablet); err != nil { @@ -88,7 +88,7 @@ func TestSuite(t *testing.T, ts *topo.Server, client vtctlclient.VtctlClient) { if err != nil { t.Fatalf("failed to get first line: %v", err) } - expected := "cell1-0000000001 test_keyspace master localhost:3333 localhost:3334 [tag: \"value\"]\n" + expected := "cell1-0000000001 test_keyspace master localhost:3333 localhost:3334 [tag: \"value\"] 1970-01-01T01:01:01Z\n" if logutil.EventString(got) != expected { t.Errorf("Got unexpected log line '%v' expected '%v'", got.String(), expected) } diff --git a/go/vt/vtgate/executor.go b/go/vt/vtgate/executor.go index ee725faaf9..9a3810684d 100644 --- a/go/vt/vtgate/executor.go +++ b/go/vt/vtgate/executor.go @@ -29,6 +29,8 @@ import ( "sync" "time" + "vitess.io/vitess/go/vt/logutil" + "vitess.io/vitess/go/vt/log" vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" @@ -828,6 +830,11 @@ func (e *Executor) handleShow(ctx context.Context, safeSession *SafeSession, sql if !ts.Serving { state = "NOT_SERVING" } + mtst := ts.Tablet.MasterTermStartTime + mtstStr := "" + if mtst != nil && mtst.Seconds > 0 { + mtstStr = logutil.ProtoToTime(ts.Tablet.MasterTermStartTime).Format(time.RFC3339) + } rows = append(rows, buildVarCharRow( s.Cell, s.Target.Keyspace, @@ -836,11 +843,12 @@ func (e *Executor) handleShow(ctx context.Context, safeSession *SafeSession, sql state, topoproto.TabletAliasString(ts.Tablet.Alias), ts.Tablet.Hostname, + mtstStr, )) } } return &sqltypes.Result{ - Fields: buildVarCharFields("Cell", "Keyspace", "Shard", "TabletType", "State", "Alias", "Hostname"), + Fields: buildVarCharFields("Cell", "Keyspace", "Shard", "TabletType", "State", "Alias", "Hostname", "MasterTermStartTime"), Rows: rows, RowsAffected: uint64(len(rows)), }, nil diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go index e2b8c7345c..f35a9cd62c 100644 --- a/go/vt/vtgate/executor_test.go +++ b/go/vt/vtgate/executor_test.go @@ -797,10 +797,10 @@ func TestExecutorShow(t *testing.T) { // Just test for first & last. qr.Rows = [][]sqltypes.Value{qr.Rows[0], qr.Rows[len(qr.Rows)-1]} wantqr = &sqltypes.Result{ - Fields: buildVarCharFields("Cell", "Keyspace", "Shard", "TabletType", "State", "Alias", "Hostname"), + Fields: buildVarCharFields("Cell", "Keyspace", "Shard", "TabletType", "State", "Alias", "Hostname", "MasterTermStartTime"), Rows: [][]sqltypes.Value{ - buildVarCharRow("FakeCell", "TestExecutor", "-20", "MASTER", "SERVING", "aa-0000000000", "-20"), - buildVarCharRow("FakeCell", "TestUnsharded", "0", "MASTER", "SERVING", "aa-0000000000", "0"), + buildVarCharRow("FakeCell", "TestExecutor", "-20", "MASTER", "SERVING", "aa-0000000000", "-20", "1970-01-01T00:00:01Z"), + buildVarCharRow("FakeCell", "TestUnsharded", "0", "MASTER", "SERVING", "aa-0000000000", "0", "1970-01-01T00:00:01Z"), }, RowsAffected: 9, }