Merge pull request #7751 from tinyspeck/am_vtadmin_aggregate_schema_sizes

[vtadmin] Aggregate schema sizes
This commit is contained in:
Rafael Chacon 2021-03-31 08:57:21 -07:00 коммит произвёл GitHub
Родитель 4f416772d4 db26e63f32
Коммит b6a8acbad8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
14 изменённых файлов: 4216 добавлений и 249 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -19,6 +19,7 @@ package vtadmin
import (
"context"
"encoding/json"
stderrors "errors"
"fmt"
"net/http"
"strings"
@ -40,6 +41,7 @@ import (
vtadminhttp "vitess.io/vitess/go/vt/vtadmin/http"
vthandlers "vitess.io/vitess/go/vt/vtadmin/http/handlers"
"vitess.io/vitess/go/vt/vtadmin/sort"
"vitess.io/vitess/go/vt/vtadmin/vtadminproto"
"vitess.io/vitess/go/vt/vterrors"
"vitess.io/vitess/go/vt/vtexplain"
@ -180,7 +182,10 @@ func (api *API) FindSchema(ctx context.Context, req *vtadminpb.FindSchemaRequest
return
}
schemas, err := api.getSchemas(ctx, c, tablets)
schemas, err := api.getSchemas(ctx, c, cluster.GetSchemaOptions{
Tablets: tablets,
TableSizeOptions: req.TableSizeOptions,
})
if err != nil {
err := fmt.Errorf("%w: while collecting schemas for cluster %s", err, c.ID)
rec.RecordError(err)
@ -346,18 +351,12 @@ func (api *API) GetKeyspaces(ctx context.Context, req *vtadminpb.GetKeyspacesReq
go func(c *cluster.Cluster, ks *vtctldatapb.Keyspace) {
defer kwg.Done()
span, ctx := trace.NewSpan(ctx, "Cluster.FindAllShardsInKeyspace")
defer span.Finish()
cluster.AnnotateSpan(c, span)
span.Annotate("keyspace", ks.Name)
sr, err := c.Vtctld.FindAllShardsInKeyspace(ctx, &vtctldatapb.FindAllShardsInKeyspaceRequest{
Keyspace: ks.Name,
shards, err := c.FindAllShardsInKeyspace(ctx, ks.Name, cluster.FindAllShardsInKeyspaceOptions{
SkipDial: true,
})
if err != nil {
er.RecordError(fmt.Errorf("FindAllShardsInKeyspace(%s): %w", ks.Name, err))
er.RecordError(err)
return
}
@ -365,7 +364,7 @@ func (api *API) GetKeyspaces(ctx context.Context, req *vtadminpb.GetKeyspacesReq
kss = append(kss, &vtadminpb.Keyspace{
Cluster: c.ToProto(),
Keyspace: ks,
Shards: sr.Shards,
Shards: shards,
})
km.Unlock()
}(c, ks)
@ -398,30 +397,19 @@ func (api *API) GetSchema(ctx context.Context, req *vtadminpb.GetSchemaRequest)
span.Annotate("cluster_id", req.ClusterId)
span.Annotate("keyspace", req.Keyspace)
span.Annotate("table", req.Table)
vtadminproto.AnnotateSpanWithGetSchemaTableSizeOptions(req.TableSizeOptions, span)
clusters, _ := api.getClustersForRequest([]string{req.ClusterId})
if len(clusters) == 0 {
c, ok := api.clusterMap[req.ClusterId]
if !ok {
return nil, fmt.Errorf("%w: no cluster with id %s", errors.ErrUnsupportedCluster, req.ClusterId)
}
cluster := clusters[0]
tablet, err := cluster.FindTablet(ctx, func(t *vtadminpb.Tablet) bool {
return t.Tablet.Keyspace == req.Keyspace && t.State == vtadminpb.Tablet_SERVING
return c.GetSchema(ctx, req.Keyspace, cluster.GetSchemaOptions{
BaseRequest: &vtctldatapb.GetSchemaRequest{
Tables: []string{req.Table},
},
TableSizeOptions: req.TableSizeOptions,
})
if err != nil {
return nil, fmt.Errorf("%w: no serving tablet found for keyspace %s", err, req.Keyspace)
}
span.Annotate("tablet_alias", topoproto.TabletAliasString(tablet.Tablet.Alias))
if err := cluster.Vtctld.Dial(ctx); err != nil {
return nil, err
}
return cluster.GetSchema(ctx, &vtctldatapb.GetSchemaRequest{
Tables: []string{req.Table},
}, tablet)
}
// GetSchemas is part of the vtadminpb.VTAdminServer interface.
@ -453,7 +441,10 @@ func (api *API) GetSchemas(ctx context.Context, req *vtadminpb.GetSchemasRequest
return
}
ss, err := api.getSchemas(ctx, c, tablets)
ss, err := api.getSchemas(ctx, c, cluster.GetSchemaOptions{
Tablets: tablets,
TableSizeOptions: req.TableSizeOptions,
})
if err != nil {
er.RecordError(err)
return
@ -477,7 +468,7 @@ func (api *API) GetSchemas(ctx context.Context, req *vtadminpb.GetSchemasRequest
}
// getSchemas returns all of the schemas across all keyspaces in the given cluster.
func (api *API) getSchemas(ctx context.Context, c *cluster.Cluster, tablets []*vtadminpb.Tablet) ([]*vtadminpb.Schema, error) {
func (api *API) getSchemas(ctx context.Context, c *cluster.Cluster, opts cluster.GetSchemaOptions) ([]*vtadminpb.Schema, error) {
if err := c.Vtctld.Dial(ctx); err != nil {
return nil, err
}
@ -507,14 +498,26 @@ func (api *API) getSchemas(ctx context.Context, c *cluster.Cluster, tablets []*v
go func(c *cluster.Cluster, ks *vtctldatapb.Keyspace) {
defer wg.Done()
ss, err := api.getSchemasForKeyspace(ctx, c, ks, tablets)
ss, err := c.GetSchema(ctx, ks.Name, opts)
if err != nil {
// Ignore keyspaces without any serving tablets.
if stderrors.Is(err, errors.ErrNoServingTablet) {
log.Infof(err.Error())
return
}
er.RecordError(err)
return
}
// Ignore keyspaces without schemas
if ss == nil {
log.Infof("No schemas for %s", ks.Name)
return
}
if len(ss.TableDefinitions) == 0 {
log.Infof("No tables in schema for %s", ks.Name)
return
}
@ -533,41 +536,6 @@ func (api *API) getSchemas(ctx context.Context, c *cluster.Cluster, tablets []*v
return schemas, nil
}
func (api *API) getSchemasForKeyspace(ctx context.Context, c *cluster.Cluster, ks *vtctldatapb.Keyspace, tablets []*vtadminpb.Tablet) (*vtadminpb.Schema, error) {
// Choose the first serving tablet.
var kt *vtadminpb.Tablet
for _, t := range tablets {
if t.Tablet.Keyspace != ks.Name || t.State != vtadminpb.Tablet_SERVING {
continue
}
kt = t
}
// Skip schema lookup on this keyspace if there are no serving tablets.
if kt == nil {
return nil, nil
}
if err := c.Vtctld.Dial(ctx); err != nil {
return nil, err
}
s, err := c.GetSchema(ctx, &vtctldatapb.GetSchemaRequest{}, kt)
if err != nil {
return nil, err
}
// Ignore any schemas without table definitions; otherwise we return
// a vtadminpb.Schema object with only Cluster and Keyspace defined,
// which is not particularly useful.
if s == nil || len(s.TableDefinitions) == 0 {
return nil, nil
}
return s, nil
}
// GetTablet is part of the vtadminpb.VTAdminServer interface.
func (api *API) GetTablet(ctx context.Context, req *vtadminpb.GetTabletRequest) (*vtadminpb.Tablet, error) {
span, ctx := trace.NewSpan(ctx, "API.GetTablet")
@ -911,7 +879,9 @@ func (api *API) VTExplain(ctx context.Context, req *vtadminpb.VTExplainRequest)
go func(c *cluster.Cluster) {
defer wg.Done()
res, err := c.GetSchema(ctx, &vtctldatapb.GetSchemaRequest{}, tablet)
res, err := c.GetSchema(ctx, req.Keyspace, cluster.GetSchemaOptions{
Tablets: []*vtadminpb.Tablet{tablet},
})
if err != nil {
er.RecordError(fmt.Errorf("GetSchema(%s): %w", topoproto.TabletAliasString(tablet.Tablet.Alias), err))
return
@ -963,23 +933,16 @@ func (api *API) VTExplain(ctx context.Context, req *vtadminpb.VTExplainRequest)
go func(c *cluster.Cluster) {
defer wg.Done()
span, ctx := trace.NewSpan(ctx, "Cluster.FindAllShardsInKeyspace")
defer span.Finish()
span.Annotate("keyspace", req.Keyspace)
cluster.AnnotateSpan(c, span)
ksm, err := c.Vtctld.FindAllShardsInKeyspace(ctx, &vtctldatapb.FindAllShardsInKeyspaceRequest{
Keyspace: req.Keyspace,
shards, err := c.FindAllShardsInKeyspace(ctx, req.Keyspace, cluster.FindAllShardsInKeyspaceOptions{
SkipDial: true,
})
if err != nil {
er.RecordError(fmt.Errorf("FindAllShardsInKeyspace(%s): %w", req.Keyspace, err))
er.RecordError(err)
return
}
vtsm := make(map[string]*topodatapb.Shard)
for _, s := range ksm.Shards {
for _, s := range shards {
vtsm[s.Name] = s.Shard
}

Просмотреть файл

@ -124,6 +124,7 @@ func TestFindSchema(t *testing.T) {
Name: "testtable",
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{},
},
shouldErr: false,
},
@ -495,6 +496,7 @@ func TestFindSchema(t *testing.T) {
Name: "testtable",
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{},
},
shouldErr: false,
},
@ -526,6 +528,234 @@ func TestFindSchema(t *testing.T) {
assert.Equal(t, tt.expected, resp)
})
}
t.Run("size aggregation", func(t *testing.T) {
t.Parallel()
c1pb := &vtadminpb.Cluster{
Id: "c1",
Name: "cluster1",
}
c2pb := &vtadminpb.Cluster{
Id: "c2",
Name: "cluster2",
}
c1 := vtadmintestutil.BuildCluster(
vtadmintestutil.TestClusterConfig{
Cluster: c1pb,
VtctldClient: &vtadmintestutil.VtctldClient{
FindAllShardsInKeyspaceResults: map[string]struct {
Response *vtctldatapb.FindAllShardsInKeyspaceResponse
Error error
}{
"testkeyspace": {
Response: &vtctldatapb.FindAllShardsInKeyspaceResponse{
Shards: map[string]*vtctldatapb.Shard{
"-80": {
Keyspace: "testkeyspace",
Name: "-80",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
"80-": {
Keyspace: "testkeyspace",
Name: "80-",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
},
},
},
"ks1": {
Response: &vtctldatapb.FindAllShardsInKeyspaceResponse{
Shards: map[string]*vtctldatapb.Shard{
"-": {
Keyspace: "ks1",
Name: "-",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
},
},
},
},
GetKeyspacesResults: struct {
Keyspaces []*vtctldatapb.Keyspace
Error error
}{
Keyspaces: []*vtctldatapb.Keyspace{
{Name: "testkeyspace"},
{Name: "ks1"},
},
},
GetSchemaResults: map[string]struct {
Response *vtctldatapb.GetSchemaResponse
Error error
}{
"c1zone1-0000000100": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "testtable",
RowCount: 10,
DataLength: 100,
},
},
},
},
},
"c1zone1-0000000200": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "testtable",
RowCount: 20,
DataLength: 200,
},
},
},
},
},
},
},
Tablets: []*vtadminpb.Tablet{
{
Cluster: c1pb,
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "c1zone1",
Uid: 100,
},
Keyspace: "testkeyspace",
Shard: "-80",
},
State: vtadminpb.Tablet_SERVING,
},
{
Cluster: c1pb,
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "c1zone1",
Uid: 200,
},
Keyspace: "testkeyspace",
Shard: "80-",
},
State: vtadminpb.Tablet_SERVING,
},
},
},
)
c2 := vtadmintestutil.BuildCluster(
vtadmintestutil.TestClusterConfig{
Cluster: c2pb,
VtctldClient: &vtadmintestutil.VtctldClient{
FindAllShardsInKeyspaceResults: map[string]struct {
Response *vtctldatapb.FindAllShardsInKeyspaceResponse
Error error
}{
"ks2": {
Response: &vtctldatapb.FindAllShardsInKeyspaceResponse{
Shards: map[string]*vtctldatapb.Shard{
"-": {
Keyspace: "ks2",
Name: "-",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
},
},
},
},
GetKeyspacesResults: struct {
Keyspaces []*vtctldatapb.Keyspace
Error error
}{
Keyspaces: []*vtctldatapb.Keyspace{
{
Name: "ks2",
},
},
},
GetSchemaResults: map[string]struct {
Response *vtctldatapb.GetSchemaResponse
Error error
}{
"c2z1-0000000100": {
Response: &vtctldatapb.GetSchemaResponse{},
},
},
},
Tablets: []*vtadminpb.Tablet{
{
Cluster: c2pb,
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "c2z1",
Uid: 100,
},
Keyspace: "ks2",
Shard: "-",
},
State: vtadminpb.Tablet_SERVING,
},
},
},
)
api := NewAPI([]*cluster.Cluster{c1, c2}, grpcserver.Options{}, http.Options{})
schema, err := api.FindSchema(ctx, &vtadminpb.FindSchemaRequest{
Table: "testtable",
TableSizeOptions: &vtadminpb.GetSchemaTableSizeOptions{
AggregateSizes: true,
},
})
expected := &vtadminpb.Schema{
Cluster: c1pb,
Keyspace: "testkeyspace",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "testtable",
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{
"testtable": {
RowCount: 10 + 20,
DataLength: 100 + 200,
ByShard: map[string]*vtadminpb.Schema_ShardTableSize{
"-80": {
RowCount: 10,
DataLength: 100,
},
"80-": {
RowCount: 20,
DataLength: 200,
},
},
},
},
}
if schema != nil {
for _, td := range schema.TableDefinitions {
// Zero these out because they're non-deterministic and also not
// relevant to the final result.
td.RowCount = 0
td.DataLength = 0
}
}
assert.NoError(t, err)
assert.Equal(t, expected, schema)
})
}
func TestGetClusters(t *testing.T) {
@ -986,6 +1216,7 @@ func TestGetSchema(t *testing.T) {
Name: "testtable",
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{},
},
shouldErr: false,
},
@ -1148,6 +1379,160 @@ func TestGetSchema(t *testing.T) {
})
})
}
t.Run("size aggregation", func(t *testing.T) {
t.Parallel()
c1pb := &vtadminpb.Cluster{
Id: "c1",
Name: "cluster1",
}
c1 := vtadmintestutil.BuildCluster(
vtadmintestutil.TestClusterConfig{
Cluster: c1pb,
VtctldClient: &vtadmintestutil.VtctldClient{
FindAllShardsInKeyspaceResults: map[string]struct {
Response *vtctldatapb.FindAllShardsInKeyspaceResponse
Error error
}{
"testkeyspace": {
Response: &vtctldatapb.FindAllShardsInKeyspaceResponse{
Shards: map[string]*vtctldatapb.Shard{
"-80": {
Keyspace: "testkeyspace",
Name: "-80",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
"80-": {
Keyspace: "testkeyspace",
Name: "80-",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
},
},
},
},
GetSchemaResults: map[string]struct {
Response *vtctldatapb.GetSchemaResponse
Error error
}{
"c1zone1-0000000100": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "testtable",
RowCount: 10,
DataLength: 100,
},
},
},
},
},
"c1zone1-0000000200": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "testtable",
RowCount: 20,
DataLength: 200,
},
},
},
},
},
},
},
Tablets: []*vtadminpb.Tablet{
{
Cluster: c1pb,
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "c1zone1",
Uid: 100,
},
Keyspace: "testkeyspace",
Shard: "-80",
},
State: vtadminpb.Tablet_SERVING,
},
{
Cluster: c1pb,
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "c1zone1",
Uid: 200,
},
Keyspace: "testkeyspace",
Shard: "80-",
},
State: vtadminpb.Tablet_SERVING,
},
},
},
)
c2 := vtadmintestutil.BuildCluster(
vtadmintestutil.TestClusterConfig{
Cluster: &vtadminpb.Cluster{
Id: "c2",
Name: "cluster2",
},
},
)
api := NewAPI([]*cluster.Cluster{c1, c2}, grpcserver.Options{}, http.Options{})
schema, err := api.GetSchema(ctx, &vtadminpb.GetSchemaRequest{
ClusterId: c1.ID,
Keyspace: "testkeyspace",
Table: "testtable",
TableSizeOptions: &vtadminpb.GetSchemaTableSizeOptions{
AggregateSizes: true,
},
})
expected := &vtadminpb.Schema{
Cluster: c1pb,
Keyspace: "testkeyspace",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "testtable",
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{
"testtable": {
RowCount: 10 + 20,
DataLength: 100 + 200,
ByShard: map[string]*vtadminpb.Schema_ShardTableSize{
"-80": {
RowCount: 10,
DataLength: 100,
},
"80-": {
RowCount: 20,
DataLength: 200,
},
},
},
},
}
if schema != nil {
for _, td := range schema.TableDefinitions {
// Zero these out because they're non-deterministic and also not
// relevant to the final result.
td.RowCount = 0
td.DataLength = 0
}
}
assert.NoError(t, err)
assert.Equal(t, expected, schema)
})
}
func TestGetSchemas(t *testing.T) {
@ -1237,6 +1622,7 @@ func TestGetSchemas(t *testing.T) {
},
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{},
},
},
},
@ -1336,6 +1722,7 @@ func TestGetSchemas(t *testing.T) {
},
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{},
},
{
Cluster: &vtadminpb.Cluster{
@ -1359,6 +1746,7 @@ func TestGetSchemas(t *testing.T) {
},
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{},
},
},
},
@ -1460,6 +1848,7 @@ func TestGetSchemas(t *testing.T) {
},
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{},
},
},
},
@ -1655,6 +2044,284 @@ func TestGetSchemas(t *testing.T) {
}, vtctlds...)
})
}
t.Run("size aggregation", func(t *testing.T) {
t.Parallel()
c1pb := &vtadminpb.Cluster{
Id: "c1",
Name: "cluster1",
}
c2pb := &vtadminpb.Cluster{
Id: "c2",
Name: "cluster2",
}
c1 := vtadmintestutil.BuildCluster(
vtadmintestutil.TestClusterConfig{
Cluster: c1pb,
VtctldClient: &vtadmintestutil.VtctldClient{
FindAllShardsInKeyspaceResults: map[string]struct {
Response *vtctldatapb.FindAllShardsInKeyspaceResponse
Error error
}{
"testkeyspace": {
Response: &vtctldatapb.FindAllShardsInKeyspaceResponse{
Shards: map[string]*vtctldatapb.Shard{
"-80": {
Keyspace: "testkeyspace",
Name: "-80",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
"80-": {
Keyspace: "testkeyspace",
Name: "80-",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
},
},
},
"ks1": {
Response: &vtctldatapb.FindAllShardsInKeyspaceResponse{
Shards: map[string]*vtctldatapb.Shard{
"-": {
Keyspace: "ks1",
Name: "-",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
},
},
},
},
GetKeyspacesResults: struct {
Keyspaces []*vtctldatapb.Keyspace
Error error
}{
Keyspaces: []*vtctldatapb.Keyspace{
{Name: "testkeyspace"},
{Name: "ks1"},
},
},
GetSchemaResults: map[string]struct {
Response *vtctldatapb.GetSchemaResponse
Error error
}{
"c1zone1-0000000100": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "testtable",
RowCount: 10,
DataLength: 100,
},
},
},
},
},
"c1zone1-0000000200": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "testtable",
RowCount: 20,
DataLength: 200,
},
},
},
},
},
},
},
Tablets: []*vtadminpb.Tablet{
{
Cluster: c1pb,
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "c1zone1",
Uid: 100,
},
Keyspace: "testkeyspace",
Shard: "-80",
},
State: vtadminpb.Tablet_SERVING,
},
{
Cluster: c1pb,
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "c1zone1",
Uid: 200,
},
Keyspace: "testkeyspace",
Shard: "80-",
},
State: vtadminpb.Tablet_SERVING,
},
},
},
)
c2 := vtadmintestutil.BuildCluster(
vtadmintestutil.TestClusterConfig{
Cluster: c2pb,
VtctldClient: &vtadmintestutil.VtctldClient{
FindAllShardsInKeyspaceResults: map[string]struct {
Response *vtctldatapb.FindAllShardsInKeyspaceResponse
Error error
}{
"ks2": {
Response: &vtctldatapb.FindAllShardsInKeyspaceResponse{
Shards: map[string]*vtctldatapb.Shard{
"-": {
Keyspace: "ks2",
Name: "-",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
},
},
},
},
GetKeyspacesResults: struct {
Keyspaces []*vtctldatapb.Keyspace
Error error
}{
Keyspaces: []*vtctldatapb.Keyspace{
{
Name: "ks2",
},
},
},
GetSchemaResults: map[string]struct {
Response *vtctldatapb.GetSchemaResponse
Error error
}{
"c2z1-0000000100": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "t2",
DataLength: 5,
RowCount: 7,
},
{
Name: "_t2_ghc",
DataLength: 5,
RowCount: 7,
},
},
},
},
},
},
},
Tablets: []*vtadminpb.Tablet{
{
Cluster: c2pb,
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "c2z1",
Uid: 100,
},
Keyspace: "ks2",
Shard: "-",
},
State: vtadminpb.Tablet_SERVING,
},
},
},
)
api := NewAPI([]*cluster.Cluster{c1, c2}, grpcserver.Options{}, http.Options{})
resp, err := api.GetSchemas(ctx, &vtadminpb.GetSchemasRequest{
TableSizeOptions: &vtadminpb.GetSchemaTableSizeOptions{
AggregateSizes: true,
},
})
expected := &vtadminpb.GetSchemasResponse{
Schemas: []*vtadminpb.Schema{
{
Cluster: c1pb,
Keyspace: "testkeyspace",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "testtable",
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{
"testtable": {
RowCount: 10 + 20,
DataLength: 100 + 200,
ByShard: map[string]*vtadminpb.Schema_ShardTableSize{
"-80": {
RowCount: 10,
DataLength: 100,
},
"80-": {
RowCount: 20,
DataLength: 200,
},
},
},
},
},
{
Cluster: c2pb,
Keyspace: "ks2",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{Name: "t2"},
{Name: "_t2_ghc"},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{
"t2": {
DataLength: 5,
RowCount: 7,
ByShard: map[string]*vtadminpb.Schema_ShardTableSize{
"-": {
DataLength: 5,
RowCount: 7,
},
},
},
"_t2_ghc": {
DataLength: 5,
RowCount: 7,
ByShard: map[string]*vtadminpb.Schema_ShardTableSize{
"-": {
DataLength: 5,
RowCount: 7,
},
},
},
},
},
},
}
if resp != nil {
for _, schema := range resp.Schemas {
for _, td := range schema.TableDefinitions {
// Zero these out because they're non-deterministic and also not
// relevant to the final result.
td.RowCount = 0
td.DataLength = 0
}
}
}
assert.NoError(t, err)
assert.ElementsMatch(t, expected.Schemas, resp.Schemas)
})
}
func TestGetTablet(t *testing.T) {

Просмотреть файл

@ -20,6 +20,7 @@ import (
"context"
"database/sql"
"fmt"
"math/rand"
"strings"
"sync"
"time"
@ -38,6 +39,7 @@ import (
"vitess.io/vitess/go/vt/vtadmin/vtsql"
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
"vitess.io/vitess/go/vt/proto/vtadmin"
vtadminpb "vitess.io/vitess/go/vt/proto/vtadmin"
vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata"
)
@ -204,6 +206,42 @@ func (c *Cluster) parseTablet(rows *sql.Rows) (*vtadminpb.Tablet, error) {
return tablet, nil
}
// FindAllShardsInKeyspaceOptions modify the behavior of a cluster's
// FindAllShardsInKeyspace method.
type FindAllShardsInKeyspaceOptions struct {
// SkipDial indicates that the cluster can assume the vtctldclient has
// already dialed up a connection to a vtctld.
SkipDial bool
}
// FindAllShardsInKeyspace proxies a FindAllShardsInKeyspace RPC to a cluster's
// vtctld, unpacking the response struct.
//
// It can also optionally ensure the vtctldclient has a valid connection before
// making the RPC call.
func (c *Cluster) FindAllShardsInKeyspace(ctx context.Context, keyspace string, opts FindAllShardsInKeyspaceOptions) (map[string]*vtctldatapb.Shard, error) {
span, ctx := trace.NewSpan(ctx, "Cluster.FindAllShardsInKeyspace")
defer span.Finish()
AnnotateSpan(c, span)
span.Annotate("keyspace", keyspace)
if !opts.SkipDial {
if err := c.Vtctld.Dial(ctx); err != nil {
return nil, fmt.Errorf("failed to Dial vtctld for cluster = %s for FindAllShardsInKeyspace: %w", c.ID, err)
}
}
resp, err := c.Vtctld.FindAllShardsInKeyspace(ctx, &vtctldatapb.FindAllShardsInKeyspaceRequest{
Keyspace: keyspace,
})
if err != nil {
return nil, fmt.Errorf("FindAllShardsInKeyspace(cluster = %s, keyspace = %s) failed: %w", c.ID, keyspace, err)
}
return resp.Shards, nil
}
// FindWorkflowsOptions is the set of options for FindWorkflows requests.
type FindWorkflowsOptions struct {
ActiveOnly bool
@ -373,50 +411,260 @@ func (c *Cluster) getTablets(ctx context.Context) ([]*vtadminpb.Tablet, error) {
return c.parseTablets(rows)
}
// GetSchema returns the schema for a GetSchemaRequest on the given tablet. The
// caller is responsible for making at least one call to c.Vtctld.Dial prior to
// calling this function.
// GetSchemaOptions contains the options that modify the behavior of the
// (*Cluster).GetSchema method.
type GetSchemaOptions struct {
// Tablets is the starting set of tablets that GetSchema will filter to find
// suitable tablet(s) to make GetSchema RPC(s) to.
//
// If empty, GetSchema will first call (*Cluster).FindTablets() to fetch all
// tablets for the keyspace.
Tablets []*vtadminpb.Tablet
// BaseRequest is used to share some common parameters to use for the
// individual tablet GetSchema RPCs made by (*Cluster).GetSchema, which
// takes a copy of this request in order to makeb certain overrides as
// needed, so these mutations are transparent to the caller.
//
// The TabletAlias field is ignored completely by (*Cluster).GetSchema, as
// it is overwritten for each tablet RPC that method makes.
//
// The TableSizesOnly field is overwritten only in certain tablet RPCs when
// SizeOpts.AggregateSizes is true. In order to move minimal bytes over the
// wire, we assume that schema definitions match across all shards, so we
// can get the full schema from just one tablet, and then just the table
// size information from the other N-1 tablets.
//
// The TableNamesOnly field is untouched by (*Cluster).GetSchema when not
// doing size aggregation. However, when doing size aggregation, if
// TableNamesOnly is true, we log a warning and override it. This is because
// TableNamesOnly is mutually exclusive with TableSizesOnly, and size
// aggregation requires setting TableSizesOnly in the cases described above.
BaseRequest *vtctldatapb.GetSchemaRequest
// TableSizeOptions control whether the (*Cluster).GetSchema method performs
// cross-shard table size aggregation (via the AggregateSizes field).
//
// If the AggregateSizes field is false, the rest of this struct is ignored,
// no size aggregation is done, and (*Cluster).GetSchema will make exactly
// one GetSchema RPC to a SERVING tablet in the keyspace.
//
// If the AggregateSizes field is true, (*Cluster).GetSchema will make a
// FindAllShardsInKeyspace vtctld RPC, and then filter the given Tablets
// (described above) to find one SERVING tablet for each shard in the
// keyspace, skipping any non-serving shards in the keyspace.
TableSizeOptions *vtadminpb.GetSchemaTableSizeOptions
}
// GetSchema returns the schema for a given keyspace. GetSchema has a few
// different behaviors depending on the GetSchemaOptions provided, as follows:
//
// Note that the request's TabletAlias field will be ignored, using the provided
// tablet's Alias instead. This override is done on a copy of the request, so it
// is transparent to the caller.
// (1) If opts.Tablets is empty, we will first use FindTablets to fetch all
// tablets for the keyspace, regardless of their serving state. Additional
// filtering of either this set, or the provided Tablets, will happen later.
//
// This function takes both the request argument and tablet argument to
// (a) set the Keyspace field on the resulting Schema object, which comes from
// the provided tablet; and, (b) allow a caller, like vtadmin.API to collect a
// bunch of tablets once and make a series of GetSchema calls without Cluster
// refetching the tablet list each time.
func (c *Cluster) GetSchema(ctx context.Context, req *vtctldatapb.GetSchemaRequest, tablet *vtadminpb.Tablet) (*vtadminpb.Schema, error) {
// (2) If opts.SizeOpts.AggregateSizes is true, we will also make a call to
// FindAllShardsInKeyspace, in order to fan out GetSchema RPCs to a tablet in
// each shard. If this option is false, we make exactly one GetSchema request to
// a single, randomly-chosen, tablet in the keyspace.
//
// (3) We will only make GetSchema RPCs to tablets that are in SERVING state; we
// don't want to use a tablet that might be in a bad state as the source of
// truth for a schema. Therefore if we can't find a SERVING tablet for the
// keyspace (in non-aggregation mode) or for a shard in that keyspace (in
// aggregation mode), then we will return an error back to the caller.
func (c *Cluster) GetSchema(ctx context.Context, keyspace string, opts GetSchemaOptions) (*vtadminpb.Schema, error) {
span, ctx := trace.NewSpan(ctx, "Cluster.GetSchema")
defer span.Finish()
if opts.TableSizeOptions == nil {
opts.TableSizeOptions = &vtadminpb.GetSchemaTableSizeOptions{
AggregateSizes: false,
}
}
if opts.BaseRequest == nil {
opts.BaseRequest = &vtctldatapb.GetSchemaRequest{}
}
if opts.TableSizeOptions.AggregateSizes && opts.BaseRequest.TableNamesOnly {
log.Warningf("GetSchema(cluster = %s) size aggregation is incompatible with TableNamesOnly, ignoring the latter in favor of aggregating sizes", c.ID)
opts.BaseRequest.TableNamesOnly = false
}
AnnotateSpan(c, span)
span.Annotate("keyspace", keyspace)
annotateGetSchemaRequest(opts.BaseRequest, span)
vtadminproto.AnnotateSpanWithGetSchemaTableSizeOptions(opts.TableSizeOptions, span)
// Copy the request to not mutate the caller's request object.
r := *req
r.TabletAlias = tablet.Tablet.Alias
if len(opts.Tablets) == 0 {
// Fetch all tablets for the keyspace.
var err error
span.Annotate("tablet_alias", topoproto.TabletAliasString(r.TabletAlias))
span.Annotate("exclude_tables", strings.Join(r.ExcludeTables, ","))
span.Annotate("tables", strings.Join(r.Tables, ","))
span.Annotate("include_views", r.IncludeViews)
span.Annotate("table_names_only", r.TableNamesOnly)
span.Annotate("table_sizes_only", r.TableSizesOnly)
opts.Tablets, err = c.FindTablets(ctx, func(tablet *vtadminpb.Tablet) bool {
return tablet.Tablet.Keyspace == keyspace
}, -1)
if err != nil {
return nil, fmt.Errorf("%w for keyspace %s", errors.ErrNoTablet, keyspace)
}
}
schema, err := c.Vtctld.GetSchema(ctx, &r)
if err := c.Vtctld.Dial(ctx); err != nil {
return nil, fmt.Errorf("failed to Dial vtctld for cluster = %s for GetSchema: %w", c.ID, err)
}
tabletsToQuery, err := c.getTabletsToQueryForSchemas(ctx, keyspace, opts)
if err != nil {
return nil, err
}
if schema == nil || schema.Schema == nil {
return nil, nil
return c.getSchemaFromTablets(ctx, keyspace, tabletsToQuery, opts)
}
// Note that for this function we use the tablets parameter, ignoring the
// opts.Tablets value completely.
func (c *Cluster) getSchemaFromTablets(ctx context.Context, keyspace string, tablets []*vtadminpb.Tablet, opts GetSchemaOptions) (*vtadminpb.Schema, error) {
var (
m sync.Mutex
wg sync.WaitGroup
rec concurrency.AllErrorRecorder
schema = &vtadminpb.Schema{
Cluster: c.ToProto(),
Keyspace: keyspace,
TableSizes: map[string]*vtadminpb.Schema_TableSize{},
}
// Instead of starting at false, we start with whatever the base request
// specified. If we have exactly one tablet to query (i.e. we're not
// doing multi-shard aggregation), it's possible the request was to
// literally just get the table sizes; we shouldn't assume. If we have
// more than one tablet to query, then we are doing size aggregation,
// and we'll flip this to true after spawning the first GetSchema rpc.
sizesOnly = opts.BaseRequest.TableSizesOnly
)
for _, tablet := range tablets {
wg.Add(1)
go func(tablet *vtadminpb.Tablet, sizesOnly bool) {
defer wg.Done()
span, ctx := trace.NewSpan(ctx, "Vtctld.GetSchema")
defer span.Finish()
req := *opts.BaseRequest
req.TableSizesOnly = sizesOnly
req.TabletAlias = tablet.Tablet.Alias
AnnotateSpan(c, span)
annotateGetSchemaRequest(&req, span)
span.Annotate("keyspace", keyspace)
span.Annotate("shard", tablet.Tablet.Shard)
resp, err := c.Vtctld.GetSchema(ctx, &req)
if err != nil {
err = fmt.Errorf("GetSchema(cluster = %s, keyspace = %s, tablet = %s) failed: %w", c.ID, keyspace, tablet.Tablet.Alias, err)
rec.RecordError(err)
return
}
if resp == nil || resp.Schema == nil {
return
}
m.Lock()
defer m.Unlock()
if !sizesOnly {
schema.TableDefinitions = resp.Schema.TableDefinitions
}
if !opts.TableSizeOptions.AggregateSizes {
return
}
for _, td := range resp.Schema.TableDefinitions {
tableSize, ok := schema.TableSizes[td.Name]
if !ok {
tableSize = &vtadminpb.Schema_TableSize{
ByShard: map[string]*vtadminpb.Schema_ShardTableSize{},
}
schema.TableSizes[td.Name] = tableSize
}
if _, ok = tableSize.ByShard[tablet.Tablet.Shard]; ok {
err := fmt.Errorf("duplicate shard queries for table %s on shard %s/%s", td.Name, keyspace, tablet.Tablet.Shard)
log.Warningf("Impossible: %s", err)
rec.RecordError(err)
return
}
tableSize.RowCount += td.RowCount
tableSize.DataLength += td.DataLength
tableSize.ByShard[tablet.Tablet.Shard] = &vtadminpb.Schema_ShardTableSize{
RowCount: td.RowCount,
DataLength: td.DataLength,
}
}
}(tablet, sizesOnly)
// If we have more than one tablet to query, we definitely don't want to
// get more than the sizes twice, so invariably set this to true for
// subsequent iterations
sizesOnly = true
}
return &vtadminpb.Schema{
Cluster: c.ToProto(),
Keyspace: tablet.Tablet.Keyspace,
TableDefinitions: schema.Schema.TableDefinitions,
}, nil
wg.Wait()
if rec.HasErrors() {
return nil, rec.Error()
}
return schema, nil
}
func (c *Cluster) getTabletsToQueryForSchemas(ctx context.Context, keyspace string, opts GetSchemaOptions) ([]*vtadminpb.Tablet, error) {
if opts.TableSizeOptions.AggregateSizes {
shards, err := c.FindAllShardsInKeyspace(ctx, keyspace, FindAllShardsInKeyspaceOptions{SkipDial: true})
if err != nil {
return nil, err
}
tabletsToQuery := make([]*vtadminpb.Tablet, 0, len(shards))
for _, shard := range shards {
if !shard.Shard.IsMasterServing {
log.Infof("%s/%s is not serving; ignoring because IncludeNonServingShards=false", keyspace, shard.Name)
continue
}
shardTablets := vtadminproto.FilterTablets(func(tablet *vtadminpb.Tablet) bool {
return tablet.Tablet.Shard == shard.Name && tablet.State == vtadminpb.Tablet_SERVING
}, opts.Tablets, len(opts.Tablets))
if len(shardTablets) == 0 {
return nil, fmt.Errorf("%w for shard %s/%s", errors.ErrNoServingTablet, shard.Keyspace, shard.Name)
}
randomServingTablet := shardTablets[rand.Intn(len(shardTablets))]
tabletsToQuery = append(tabletsToQuery, randomServingTablet)
}
return tabletsToQuery, nil
}
keyspaceTablets := vtadminproto.FilterTablets(func(tablet *vtadminpb.Tablet) bool {
return tablet.Tablet.Keyspace == keyspace && tablet.State == vtadminpb.Tablet_SERVING
}, opts.Tablets, len(opts.Tablets))
if len(keyspaceTablets) == 0 {
err := fmt.Errorf("%w for keyspace %s", errors.ErrNoServingTablet, keyspace)
log.Warningf("%s. Searched tablets: %v", err, vtadminproto.Tablets(opts.Tablets).AliasStringList())
return nil, err
}
randomServingTablet := keyspaceTablets[rand.Intn(len(keyspaceTablets))]
return []*vtadmin.Tablet{randomServingTablet}, nil
}
// GetVSchema returns the vschema for a given keyspace in this cluster. The
@ -568,16 +816,5 @@ func (c *Cluster) findTablets(ctx context.Context, filter func(*vtadminpb.Tablet
span.Annotate("max_result_length", n) // this is a bad name; I didn't want just "n", but it's more like, "requested result length".
}
results := make([]*vtadminpb.Tablet, 0, n)
for _, t := range tablets {
if len(results) >= n {
break
}
if filter(t) {
results = append(results, t)
}
}
return results, nil
return vtadminproto.FilterTablets(filter, tablets, n), nil
}

Просмотреть файл

@ -404,6 +404,7 @@ func TestGetSchema(t *testing.T) {
},
req: &vtctldatapb.GetSchemaRequest{},
tablet: &vtadminpb.Tablet{
State: vtadminpb.Tablet_SERVING,
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
@ -423,6 +424,7 @@ func TestGetSchema(t *testing.T) {
Name: "some_table",
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{},
},
shouldErr: false,
},
@ -440,6 +442,7 @@ func TestGetSchema(t *testing.T) {
},
req: &vtctldatapb.GetSchemaRequest{},
tablet: &vtadminpb.Tablet{
State: vtadminpb.Tablet_SERVING,
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
@ -468,6 +471,7 @@ func TestGetSchema(t *testing.T) {
},
req: &vtctldatapb.GetSchemaRequest{},
tablet: &vtadminpb.Tablet{
State: vtadminpb.Tablet_SERVING,
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
@ -476,7 +480,15 @@ func TestGetSchema(t *testing.T) {
Keyspace: "testkeyspace",
},
},
expected: nil,
expected: &vtadminpb.Schema{
Cluster: &vtadminpb.Cluster{
Id: "c2",
Name: "cluster2",
},
Keyspace: "testkeyspace",
TableDefinitions: nil,
TableSizes: map[string]*vtadminpb.Schema_TableSize{},
},
shouldErr: false,
},
}
@ -490,7 +502,7 @@ func TestGetSchema(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
cluster := testutil.BuildCluster(testutil.TestClusterConfig{
c := testutil.BuildCluster(testutil.TestClusterConfig{
Cluster: &vtadminpb.Cluster{
Id: fmt.Sprintf("c%d", i),
Name: fmt.Sprintf("cluster%d", i),
@ -500,10 +512,13 @@ func TestGetSchema(t *testing.T) {
DBConfig: testutil.Dbcfg{},
})
err := cluster.Vtctld.Dial(ctx)
err := c.Vtctld.Dial(ctx)
require.NoError(t, err, "could not dial test vtctld")
schema, err := cluster.GetSchema(ctx, tt.req, tt.tablet)
schema, err := c.GetSchema(ctx, "testkeyspace", cluster.GetSchemaOptions{
Tablets: []*vtadminpb.Tablet{tt.tablet},
BaseRequest: tt.req,
})
if tt.shouldErr {
assert.Error(t, err)
@ -544,7 +559,7 @@ func TestGetSchema(t *testing.T) {
},
}
cluster := testutil.BuildCluster(testutil.TestClusterConfig{
c := testutil.BuildCluster(testutil.TestClusterConfig{
Cluster: &vtadminpb.Cluster{
Id: "c0",
Name: "cluster0",
@ -552,13 +567,630 @@ func TestGetSchema(t *testing.T) {
VtctldClient: vtctld,
})
err := cluster.Vtctld.Dial(ctx)
err := c.Vtctld.Dial(ctx)
require.NoError(t, err, "could not dial test vtctld")
cluster.GetSchema(ctx, req, tablet)
c.GetSchema(ctx, "testkeyspace", cluster.GetSchemaOptions{
BaseRequest: req,
Tablets: []*vtadminpb.Tablet{tablet},
})
assert.NotEqual(t, req.TabletAlias, tablet.Tablet.Alias, "expected GetSchema to not modify original request object")
})
t.Run("size aggregation", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
cfg testutil.TestClusterConfig
keyspace string
opts cluster.GetSchemaOptions
expected *vtadminpb.Schema
shouldErr bool
}{
{
name: "success",
cfg: testutil.TestClusterConfig{
Cluster: &vtadminpb.Cluster{
Id: "c0",
Name: "cluster0",
},
Tablets: []*vtadminpb.Tablet{
{
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
Uid: 100,
},
Keyspace: "testkeyspace",
Shard: "-80",
},
State: vtadminpb.Tablet_SERVING,
},
{
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
Uid: 200,
},
Keyspace: "testkeyspace",
Shard: "80-",
},
State: vtadminpb.Tablet_SERVING,
},
},
VtctldClient: &testutil.VtctldClient{
FindAllShardsInKeyspaceResults: map[string]struct {
Response *vtctldatapb.FindAllShardsInKeyspaceResponse
Error error
}{
"testkeyspace": {
Response: &vtctldatapb.FindAllShardsInKeyspaceResponse{
Shards: map[string]*vtctldatapb.Shard{
"-80": {
Name: "-80",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
"80-": {
Name: "80-",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
"-": {
Name: "-",
Shard: &topodatapb.Shard{
IsMasterServing: false,
},
},
},
},
},
},
GetSchemaResults: map[string]struct {
Response *vtctldatapb.GetSchemaResponse
Error error
}{
"zone1-0000000100": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
DatabaseSchema: "CREATE DATABASE vt_testkeyspcae",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "foo",
Schema: "CREATE TABLE foo (\n\tid INT(11) NOT NULL\n) ENGINE=InnoDB",
DataLength: 100,
RowCount: 5,
},
},
},
},
},
"zone1-0000000200": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
DatabaseSchema: "CREATE DATABASE vt_testkeyspcae",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "foo",
Schema: "CREATE TABLE foo (\n\tid INT(11) NOT NULL\n) ENGINE=InnoDB",
DataLength: 200,
RowCount: 420,
},
},
},
},
},
},
},
},
keyspace: "testkeyspace",
opts: cluster.GetSchemaOptions{
TableSizeOptions: &vtadminpb.GetSchemaTableSizeOptions{
AggregateSizes: true,
},
},
expected: &vtadminpb.Schema{
Cluster: &vtadminpb.Cluster{
Id: "c0",
Name: "cluster0",
},
Keyspace: "testkeyspace",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "foo",
Schema: "CREATE TABLE foo (\n\tid INT(11) NOT NULL\n) ENGINE=InnoDB",
DataLength: 0,
RowCount: 0,
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{
"foo": {
DataLength: 100 + 200,
RowCount: 5 + 420,
ByShard: map[string]*vtadminpb.Schema_ShardTableSize{
"-80": {
DataLength: 100,
RowCount: 5,
},
"80-": {
DataLength: 200,
RowCount: 420,
},
},
},
},
},
shouldErr: false,
},
{
name: "no serving tablets found for shard",
cfg: testutil.TestClusterConfig{
Cluster: &vtadminpb.Cluster{
Id: "c0",
Name: "cluster0",
},
Tablets: []*vtadminpb.Tablet{
{
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
Uid: 100,
},
Keyspace: "testkeyspace",
Shard: "-80",
},
State: vtadminpb.Tablet_NOT_SERVING,
},
{
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
Uid: 200,
},
Keyspace: "testkeyspace",
Shard: "80-",
},
State: vtadminpb.Tablet_SERVING,
},
},
VtctldClient: &testutil.VtctldClient{
FindAllShardsInKeyspaceResults: map[string]struct {
Response *vtctldatapb.FindAllShardsInKeyspaceResponse
Error error
}{
"testkeyspace": {
Response: &vtctldatapb.FindAllShardsInKeyspaceResponse{
Shards: map[string]*vtctldatapb.Shard{
"-80": {
Name: "-80",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
"80-": {
Name: "80-",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
"-": {
Name: "-",
Shard: &topodatapb.Shard{
IsMasterServing: false,
},
},
},
},
},
},
GetSchemaResults: map[string]struct {
Response *vtctldatapb.GetSchemaResponse
Error error
}{
"zone1-0000000100": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
DatabaseSchema: "CREATE DATABASE vt_testkeyspcae",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "foo",
Schema: "CREATE TABLE foo (\n\tid INT(11) NOT NULL\n) ENGINE=InnoDB",
DataLength: 100,
RowCount: 5,
},
},
},
},
},
"zone1-0000000200": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
DatabaseSchema: "CREATE DATABASE vt_testkeyspcae",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "foo",
Schema: "CREATE TABLE foo (\n\tid INT(11) NOT NULL\n) ENGINE=InnoDB",
DataLength: 200,
RowCount: 420,
},
},
},
},
},
},
},
},
keyspace: "testkeyspace",
opts: cluster.GetSchemaOptions{
TableSizeOptions: &vtadminpb.GetSchemaTableSizeOptions{
AggregateSizes: true,
},
},
expected: nil,
shouldErr: true,
},
{
name: "ignore TableNamesOnly",
cfg: testutil.TestClusterConfig{
Cluster: &vtadminpb.Cluster{
Id: "c0",
Name: "cluster0",
},
Tablets: []*vtadminpb.Tablet{
{
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
Uid: 100,
},
Keyspace: "testkeyspace",
Shard: "-80",
},
State: vtadminpb.Tablet_SERVING,
},
{
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
Uid: 200,
},
Keyspace: "testkeyspace",
Shard: "80-",
},
State: vtadminpb.Tablet_SERVING,
},
},
VtctldClient: &testutil.VtctldClient{
FindAllShardsInKeyspaceResults: map[string]struct {
Response *vtctldatapb.FindAllShardsInKeyspaceResponse
Error error
}{
"testkeyspace": {
Response: &vtctldatapb.FindAllShardsInKeyspaceResponse{
Shards: map[string]*vtctldatapb.Shard{
"-80": {
Name: "-80",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
"80-": {
Name: "80-",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
"-": {
Name: "-",
Shard: &topodatapb.Shard{
IsMasterServing: false,
},
},
},
},
},
},
GetSchemaResults: map[string]struct {
Response *vtctldatapb.GetSchemaResponse
Error error
}{
"zone1-0000000100": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
DatabaseSchema: "CREATE DATABASE vt_testkeyspcae",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "foo",
Schema: "CREATE TABLE foo (\n\tid INT(11) NOT NULL\n) ENGINE=InnoDB",
DataLength: 100,
RowCount: 5,
},
},
},
},
},
"zone1-0000000200": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
DatabaseSchema: "CREATE DATABASE vt_testkeyspcae",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "foo",
Schema: "CREATE TABLE foo (\n\tid INT(11) NOT NULL\n) ENGINE=InnoDB",
DataLength: 200,
RowCount: 420,
},
},
},
},
},
},
},
},
keyspace: "testkeyspace",
opts: cluster.GetSchemaOptions{
BaseRequest: &vtctldatapb.GetSchemaRequest{
TableNamesOnly: true, // Just checking things to blow up if this gets set.
},
TableSizeOptions: &vtadminpb.GetSchemaTableSizeOptions{
AggregateSizes: true,
},
},
expected: &vtadminpb.Schema{
Cluster: &vtadminpb.Cluster{
Id: "c0",
Name: "cluster0",
},
Keyspace: "testkeyspace",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "foo",
Schema: "CREATE TABLE foo (\n\tid INT(11) NOT NULL\n) ENGINE=InnoDB",
DataLength: 0,
RowCount: 0,
},
},
TableSizes: map[string]*vtadminpb.Schema_TableSize{
"foo": {
DataLength: 100 + 200,
RowCount: 5 + 420,
ByShard: map[string]*vtadminpb.Schema_ShardTableSize{
"-80": {
DataLength: 100,
RowCount: 5,
},
"80-": {
DataLength: 200,
RowCount: 420,
},
},
},
},
},
shouldErr: false,
},
{
name: "single GetSchema error fails the request",
cfg: testutil.TestClusterConfig{
Cluster: &vtadminpb.Cluster{
Id: "c0",
Name: "cluster0",
},
Tablets: []*vtadminpb.Tablet{
{
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
Uid: 100,
},
Keyspace: "testkeyspace",
Shard: "-80",
},
State: vtadminpb.Tablet_SERVING,
},
{
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
Uid: 200,
},
Keyspace: "testkeyspace",
Shard: "80-",
},
State: vtadminpb.Tablet_SERVING,
},
},
VtctldClient: &testutil.VtctldClient{
FindAllShardsInKeyspaceResults: map[string]struct {
Response *vtctldatapb.FindAllShardsInKeyspaceResponse
Error error
}{
"testkeyspace": {
Response: &vtctldatapb.FindAllShardsInKeyspaceResponse{
Shards: map[string]*vtctldatapb.Shard{
"-80": {
Name: "-80",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
"80-": {
Name: "80-",
Shard: &topodatapb.Shard{
IsMasterServing: true,
},
},
"-": {
Name: "-",
Shard: &topodatapb.Shard{
IsMasterServing: false,
},
},
},
},
},
},
GetSchemaResults: map[string]struct {
Response *vtctldatapb.GetSchemaResponse
Error error
}{
"zone1-0000000100": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
DatabaseSchema: "CREATE DATABASE vt_testkeyspcae",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "foo",
Schema: "CREATE TABLE foo (\n\tid INT(11) NOT NULL\n) ENGINE=InnoDB",
DataLength: 100,
RowCount: 5,
},
},
},
},
},
"zone1-0000000200": {
Error: assert.AnError,
},
},
},
},
keyspace: "testkeyspace",
opts: cluster.GetSchemaOptions{
TableSizeOptions: &vtadminpb.GetSchemaTableSizeOptions{
AggregateSizes: true,
},
},
expected: nil,
shouldErr: true,
},
{
name: "FindAllShardsInKeyspace error",
cfg: testutil.TestClusterConfig{
Cluster: &vtadminpb.Cluster{
Id: "c0",
Name: "cluster0",
},
Tablets: []*vtadminpb.Tablet{
{
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
Uid: 100,
},
Keyspace: "testkeyspace",
Shard: "-80",
},
State: vtadminpb.Tablet_SERVING,
},
{
Tablet: &topodatapb.Tablet{
Alias: &topodatapb.TabletAlias{
Cell: "zone1",
Uid: 200,
},
Keyspace: "testkeyspace",
Shard: "80-",
},
State: vtadminpb.Tablet_SERVING,
},
},
VtctldClient: &testutil.VtctldClient{
FindAllShardsInKeyspaceResults: map[string]struct {
Response *vtctldatapb.FindAllShardsInKeyspaceResponse
Error error
}{
"testkeyspace": {
Error: assert.AnError,
},
},
GetSchemaResults: map[string]struct {
Response *vtctldatapb.GetSchemaResponse
Error error
}{
"zone1-0000000100": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
DatabaseSchema: "CREATE DATABASE vt_testkeyspcae",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "foo",
Schema: "CREATE TABLE foo (\n\tid INT(11) NOT NULL\n) ENGINE=InnoDB",
DataLength: 100,
RowCount: 5,
},
},
},
},
},
"zone1-0000000200": {
Response: &vtctldatapb.GetSchemaResponse{
Schema: &tabletmanagerdatapb.SchemaDefinition{
DatabaseSchema: "CREATE DATABASE vt_testkeyspcae",
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
Name: "foo",
Schema: "CREATE TABLE foo (\n\tid INT(11) NOT NULL\n) ENGINE=InnoDB",
DataLength: 200,
RowCount: 420,
},
},
},
},
},
},
},
},
keyspace: "testkeyspace",
opts: cluster.GetSchemaOptions{
TableSizeOptions: &vtadminpb.GetSchemaTableSizeOptions{
AggregateSizes: true,
},
},
expected: nil,
shouldErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if tt.keyspace == "" {
t.SkipNow()
}
c := testutil.BuildCluster(tt.cfg)
schema, err := c.GetSchema(ctx, tt.keyspace, tt.opts)
if tt.shouldErr {
assert.Error(t, err)
return
}
if schema.TableDefinitions != nil {
// For simplicity, we're going to assert only on the state
// of the aggregated sizes (in schema.TableSizes), since the
// TableDefinitions size values depends on tablet iteration
// order, and that's not something we're interested in
// coupling the implementation to.
for _, td := range schema.TableDefinitions {
td.DataLength = 0
td.RowCount = 0
}
}
assert.NoError(t, err)
testutil.AssertSchemaSlicesEqual(t, []*vtadminpb.Schema{tt.expected}, []*vtadminpb.Schema{schema})
})
}
})
}
func TestFindWorkflows(t *testing.T) {

Просмотреть файл

@ -17,8 +17,13 @@ limitations under the License.
package cluster
import (
"strings"
"vitess.io/vitess/go/trace"
"vitess.io/vitess/go/vt/topo/topoproto"
"vitess.io/vitess/go/vt/vtadmin/vtadminproto"
vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata"
)
// AnnotateSpan adds the cluster_id and cluster_name to a span.
@ -27,3 +32,16 @@ func AnnotateSpan(c *Cluster, span trace.Span) {
// (TODO:@ajm188) add support for discovery impls to add annotations to a
// span, like `discovery_impl` and any parameters that might be relevant.
}
// (TODO: @ajm188) perhaps we want a ./go/vt/vtctl/vtctlproto package for this?
func annotateGetSchemaRequest(req *vtctldatapb.GetSchemaRequest, span trace.Span) {
if req.TabletAlias != nil {
span.Annotate("tablet_alias", topoproto.TabletAliasString(req.TabletAlias))
}
span.Annotate("exclude_tables", strings.Join(req.ExcludeTables, ","))
span.Annotate("tables", strings.Join(req.Tables, ","))
span.Annotate("include_views", req.IncludeViews)
span.Annotate("table_names_only", req.TableNamesOnly)
span.Annotate("table_sizes_only", req.TableSizesOnly)
}

Просмотреть файл

@ -16,7 +16,10 @@ limitations under the License.
package errors
import "errors"
import (
"errors"
"fmt"
)
var (
// ErrAmbiguousSchema occurs when more than one schema is found for a given
@ -35,6 +38,10 @@ var (
// ErrNoSchema occurs when a schema definition cannot be found for a given
// set of filter criteria.
ErrNoSchema = errors.New("no such schema")
// ErrNoServingTablet occurs when a tablet with state SERVING cannot be
// found for a given set of filter criteria. It is a more specific form of
// ErrNoTablet
ErrNoServingTablet = fmt.Errorf("%w with state=SERVING", ErrNoTablet)
// ErrNoSrvVSchema occurs when no SrvVSchema is found for a given keyspace.
ErrNoSrvVSchema = errors.New("SrvVSchema not found")
// ErrNoTablet occurs when a tablet cannot be found for a given set of

Просмотреть файл

@ -28,9 +28,15 @@ func FindSchema(ctx context.Context, r Request, api *API) *JSONResponse {
vars := r.Vars()
query := r.URL.Query()
sizeOpts, err := getTableSizeOpts(r)
if err != nil {
return NewJSONResponse(nil, err)
}
schema, err := api.server.FindSchema(ctx, &vtadminpb.FindSchemaRequest{
Table: vars["table"],
ClusterIds: query["cluster"],
Table: vars["table"],
ClusterIds: query["cluster"],
TableSizeOptions: sizeOpts,
})
return NewJSONResponse(schema, err)
@ -41,10 +47,16 @@ func FindSchema(ctx context.Context, r Request, api *API) *JSONResponse {
func GetSchema(ctx context.Context, r Request, api *API) *JSONResponse {
vars := r.Vars()
sizeOpts, err := getTableSizeOpts(r)
if err != nil {
return NewJSONResponse(nil, err)
}
schema, err := api.server.GetSchema(ctx, &vtadminpb.GetSchemaRequest{
ClusterId: vars["cluster_id"],
Keyspace: vars["keyspace"],
Table: vars["table"],
ClusterId: vars["cluster_id"],
Keyspace: vars["keyspace"],
Table: vars["table"],
TableSizeOptions: sizeOpts,
})
return NewJSONResponse(schema, err)
@ -53,9 +65,26 @@ func GetSchema(ctx context.Context, r Request, api *API) *JSONResponse {
// GetSchemas implements the http wrapper for the /schemas[?cluster=[&cluster=]
// route.
func GetSchemas(ctx context.Context, r Request, api *API) *JSONResponse {
sizeOpts, err := getTableSizeOpts(r)
if err != nil {
return NewJSONResponse(nil, err)
}
schemas, err := api.server.GetSchemas(ctx, &vtadminpb.GetSchemasRequest{
ClusterIds: r.URL.Query()["cluster"],
ClusterIds: r.URL.Query()["cluster"],
TableSizeOptions: sizeOpts,
})
return NewJSONResponse(schemas, err)
}
func getTableSizeOpts(r Request) (*vtadminpb.GetSchemaTableSizeOptions, error) {
aggregateSizes, err := r.ParseQueryParamAsBool("aggregate_sizes", true)
if err != nil {
return nil, err
}
return &vtadminpb.GetSchemaTableSizeOptions{
AggregateSizes: aggregateSizes,
}, nil
}

Просмотреть файл

@ -34,6 +34,10 @@ import (
type VtctldClient struct {
vtctldclient.VtctldClient
FindAllShardsInKeyspaceResults map[string]struct {
Response *vtctldatapb.FindAllShardsInKeyspaceResponse
Error error
}
GetKeyspacesResults struct {
Keyspaces []*vtctldatapb.Keyspace
Error error
@ -56,6 +60,19 @@ type VtctldClient struct {
// incorrectly.
var _ vtctldclient.VtctldClient = (*VtctldClient)(nil)
// FindAllShardsInKeyspace is part of the vtctldclient.VtctldClient interface.
func (fake *VtctldClient) FindAllShardsInKeyspace(ctx context.Context, req *vtctldatapb.FindAllShardsInKeyspaceRequest, opts ...grpc.CallOption) (*vtctldatapb.FindAllShardsInKeyspaceResponse, error) {
if fake.FindAllShardsInKeyspaceResults == nil {
return nil, fmt.Errorf("%w: FindAllShardsInKeyspaceResults not set on fake vtctldclient", assert.AnError)
}
if result, ok := fake.FindAllShardsInKeyspaceResults[req.Keyspace]; ok {
return result.Response, result.Error
}
return nil, fmt.Errorf("%w: no result set for keyspace %s", assert.AnError, req.Keyspace)
}
// GetKeyspaces is part of the vtctldclient.VtctldClient interface.
func (fake *VtctldClient) GetKeyspaces(ctx context.Context, req *vtctldatapb.GetKeyspacesRequest, opts ...grpc.CallOption) (*vtctldatapb.GetKeyspacesResponse, error) {
if fake.GetKeyspacesResults.Error != nil {

Просмотреть файл

@ -16,7 +16,50 @@ limitations under the License.
package vtadminproto
import vtadminpb "vitess.io/vitess/go/vt/proto/vtadmin"
import (
"vitess.io/vitess/go/vt/topo/topoproto"
vtadminpb "vitess.io/vitess/go/vt/proto/vtadmin"
)
// Tablets is a list of Tablet protobuf objects.
type Tablets []*vtadminpb.Tablet
// AliasStringList returns a list of TabletAlias strings for each tablet in the
// list.
func (tablets Tablets) AliasStringList() []string {
aliases := make([]string, len(tablets))
for i, tablet := range tablets {
aliases[i] = topoproto.TabletAliasString(tablet.Tablet.Alias)
}
return aliases
}
// FilterTablets returns a subset of tablets (not exceeding maxResults) that
// satisfy the given condition.
//
// If maxResults is negative, len(tablets) is used instead.
func FilterTablets(condition func(tablet *vtadminpb.Tablet) bool, tablets []*vtadminpb.Tablet, maxResults int) []*vtadminpb.Tablet {
if maxResults < 0 {
maxResults = len(tablets)
}
results := make([]*vtadminpb.Tablet, 0, maxResults)
for _, tablet := range tablets {
if len(results) >= maxResults {
break
}
if condition(tablet) {
results = append(results, tablet)
}
}
return results
}
// ParseTabletServingState returns a ServingState value from the given string.
// If the string does not map to a valid value, this function returns UNKNOWN.

Просмотреть файл

@ -27,3 +27,13 @@ func AnnotateClusterSpan(c *vtadminpb.Cluster, span trace.Span) {
span.Annotate("cluster_id", c.Id)
span.Annotate("cluster_name", c.Name)
}
// AnnotateSpanWithGetSchemaTableSizeOptions adds the aggregate_table_sizes to a
// span. It is a noop if the size options object is nil.
func AnnotateSpanWithGetSchemaTableSizeOptions(opts *vtadminpb.GetSchemaTableSizeOptions, span trace.Span) {
if opts == nil {
opts = &vtadminpb.GetSchemaTableSizeOptions{}
}
span.Annotate("aggregate_table_sizes", opts.AggregateSizes)
}

Просмотреть файл

@ -96,6 +96,21 @@ message Schema {
string keyspace = 2;
repeated tabletmanagerdata.TableDefinition table_definitions = 3;
// TableSizes is a mapping of table name to TableSize information.
map<string, TableSize> table_sizes = 4;
message ShardTableSize {
uint64 row_count = 1;
uint64 data_length = 2;
}
// TableSize aggregates table size information across all shards containing
// in the given keyspace and cluster, as well as per-shard size information.
message TableSize {
uint64 row_count = 1;
uint64 data_length = 2;
map<string, ShardTableSize> by_shard = 3;
}
}
// Tablet groups the topo information of a tablet together with the Vitess
@ -154,6 +169,7 @@ message Workflow {
message FindSchemaRequest {
string table = 1;
repeated string cluster_ids = 2;
GetSchemaTableSizeOptions table_size_options = 3;
}
message GetClustersRequest {}
@ -182,16 +198,22 @@ message GetSchemaRequest {
string cluster_id = 1;
string keyspace = 2;
string table = 3;
GetSchemaTableSizeOptions table_size_options = 4;
}
message GetSchemasRequest {
repeated string cluster_ids = 1;
GetSchemaTableSizeOptions table_size_options = 2;
}
message GetSchemasResponse {
repeated Schema schemas = 1;
}
message GetSchemaTableSizeOptions {
bool aggregate_sizes = 1;
}
message GetTabletRequest {
string hostname = 1;
// ClusterIDs is an optional parameter to narrow the scope of the search, if

315
web/vtadmin/src/proto/vtadmin.d.ts поставляемый
Просмотреть файл

@ -604,6 +604,9 @@ export namespace vtadmin {
/** Schema table_definitions */
table_definitions?: (tabletmanagerdata.ITableDefinition[]|null);
/** Schema table_sizes */
table_sizes?: ({ [k: string]: vtadmin.Schema.ITableSize }|null);
}
/** Represents a Schema. */
@ -624,6 +627,9 @@ export namespace vtadmin {
/** Schema table_definitions. */
public table_definitions: tabletmanagerdata.ITableDefinition[];
/** Schema table_sizes. */
public table_sizes: { [k: string]: vtadmin.Schema.ITableSize };
/**
* Creates a new Schema instance using the specified properties.
* @param [properties] Properties to set
@ -695,6 +701,207 @@ export namespace vtadmin {
public toJSON(): { [k: string]: any };
}
namespace Schema {
/** Properties of a ShardTableSize. */
interface IShardTableSize {
/** ShardTableSize row_count */
row_count?: (number|Long|null);
/** ShardTableSize data_length */
data_length?: (number|Long|null);
}
/** Represents a ShardTableSize. */
class ShardTableSize implements IShardTableSize {
/**
* Constructs a new ShardTableSize.
* @param [properties] Properties to set
*/
constructor(properties?: vtadmin.Schema.IShardTableSize);
/** ShardTableSize row_count. */
public row_count: (number|Long);
/** ShardTableSize data_length. */
public data_length: (number|Long);
/**
* Creates a new ShardTableSize instance using the specified properties.
* @param [properties] Properties to set
* @returns ShardTableSize instance
*/
public static create(properties?: vtadmin.Schema.IShardTableSize): vtadmin.Schema.ShardTableSize;
/**
* Encodes the specified ShardTableSize message. Does not implicitly {@link vtadmin.Schema.ShardTableSize.verify|verify} messages.
* @param message ShardTableSize message or plain object to encode
* @param [writer] Writer to encode to
* @returns Writer
*/
public static encode(message: vtadmin.Schema.IShardTableSize, writer?: $protobuf.Writer): $protobuf.Writer;
/**
* Encodes the specified ShardTableSize message, length delimited. Does not implicitly {@link vtadmin.Schema.ShardTableSize.verify|verify} messages.
* @param message ShardTableSize message or plain object to encode
* @param [writer] Writer to encode to
* @returns Writer
*/
public static encodeDelimited(message: vtadmin.Schema.IShardTableSize, writer?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes a ShardTableSize message from the specified reader or buffer.
* @param reader Reader or buffer to decode from
* @param [length] Message length if known beforehand
* @returns ShardTableSize
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): vtadmin.Schema.ShardTableSize;
/**
* Decodes a ShardTableSize message from the specified reader or buffer, length delimited.
* @param reader Reader or buffer to decode from
* @returns ShardTableSize
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): vtadmin.Schema.ShardTableSize;
/**
* Verifies a ShardTableSize message.
* @param message Plain object to verify
* @returns `null` if valid, otherwise the reason why it is not
*/
public static verify(message: { [k: string]: any }): (string|null);
/**
* Creates a ShardTableSize message from a plain object. Also converts values to their respective internal types.
* @param object Plain object
* @returns ShardTableSize
*/
public static fromObject(object: { [k: string]: any }): vtadmin.Schema.ShardTableSize;
/**
* Creates a plain object from a ShardTableSize message. Also converts values to other types if specified.
* @param message ShardTableSize
* @param [options] Conversion options
* @returns Plain object
*/
public static toObject(message: vtadmin.Schema.ShardTableSize, options?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this ShardTableSize to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}
/** Properties of a TableSize. */
interface ITableSize {
/** TableSize row_count */
row_count?: (number|Long|null);
/** TableSize data_length */
data_length?: (number|Long|null);
/** TableSize by_shard */
by_shard?: ({ [k: string]: vtadmin.Schema.IShardTableSize }|null);
}
/** Represents a TableSize. */
class TableSize implements ITableSize {
/**
* Constructs a new TableSize.
* @param [properties] Properties to set
*/
constructor(properties?: vtadmin.Schema.ITableSize);
/** TableSize row_count. */
public row_count: (number|Long);
/** TableSize data_length. */
public data_length: (number|Long);
/** TableSize by_shard. */
public by_shard: { [k: string]: vtadmin.Schema.IShardTableSize };
/**
* Creates a new TableSize instance using the specified properties.
* @param [properties] Properties to set
* @returns TableSize instance
*/
public static create(properties?: vtadmin.Schema.ITableSize): vtadmin.Schema.TableSize;
/**
* Encodes the specified TableSize message. Does not implicitly {@link vtadmin.Schema.TableSize.verify|verify} messages.
* @param message TableSize message or plain object to encode
* @param [writer] Writer to encode to
* @returns Writer
*/
public static encode(message: vtadmin.Schema.ITableSize, writer?: $protobuf.Writer): $protobuf.Writer;
/**
* Encodes the specified TableSize message, length delimited. Does not implicitly {@link vtadmin.Schema.TableSize.verify|verify} messages.
* @param message TableSize message or plain object to encode
* @param [writer] Writer to encode to
* @returns Writer
*/
public static encodeDelimited(message: vtadmin.Schema.ITableSize, writer?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes a TableSize message from the specified reader or buffer.
* @param reader Reader or buffer to decode from
* @param [length] Message length if known beforehand
* @returns TableSize
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): vtadmin.Schema.TableSize;
/**
* Decodes a TableSize message from the specified reader or buffer, length delimited.
* @param reader Reader or buffer to decode from
* @returns TableSize
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): vtadmin.Schema.TableSize;
/**
* Verifies a TableSize message.
* @param message Plain object to verify
* @returns `null` if valid, otherwise the reason why it is not
*/
public static verify(message: { [k: string]: any }): (string|null);
/**
* Creates a TableSize message from a plain object. Also converts values to their respective internal types.
* @param object Plain object
* @returns TableSize
*/
public static fromObject(object: { [k: string]: any }): vtadmin.Schema.TableSize;
/**
* Creates a plain object from a TableSize message. Also converts values to other types if specified.
* @param message TableSize
* @param [options] Conversion options
* @returns Plain object
*/
public static toObject(message: vtadmin.Schema.TableSize, options?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this TableSize to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}
}
/** Properties of a Tablet. */
interface ITablet {
@ -1229,6 +1436,9 @@ export namespace vtadmin {
/** FindSchemaRequest cluster_ids */
cluster_ids?: (string[]|null);
/** FindSchemaRequest table_size_options */
table_size_options?: (vtadmin.IGetSchemaTableSizeOptions|null);
}
/** Represents a FindSchemaRequest. */
@ -1246,6 +1456,9 @@ export namespace vtadmin {
/** FindSchemaRequest cluster_ids. */
public cluster_ids: string[];
/** FindSchemaRequest table_size_options. */
public table_size_options?: (vtadmin.IGetSchemaTableSizeOptions|null);
/**
* Creates a new FindSchemaRequest instance using the specified properties.
* @param [properties] Properties to set
@ -1862,6 +2075,9 @@ export namespace vtadmin {
/** GetSchemaRequest table */
table?: (string|null);
/** GetSchemaRequest table_size_options */
table_size_options?: (vtadmin.IGetSchemaTableSizeOptions|null);
}
/** Represents a GetSchemaRequest. */
@ -1882,6 +2098,9 @@ export namespace vtadmin {
/** GetSchemaRequest table. */
public table: string;
/** GetSchemaRequest table_size_options. */
public table_size_options?: (vtadmin.IGetSchemaTableSizeOptions|null);
/**
* Creates a new GetSchemaRequest instance using the specified properties.
* @param [properties] Properties to set
@ -1958,6 +2177,9 @@ export namespace vtadmin {
/** GetSchemasRequest cluster_ids */
cluster_ids?: (string[]|null);
/** GetSchemasRequest table_size_options */
table_size_options?: (vtadmin.IGetSchemaTableSizeOptions|null);
}
/** Represents a GetSchemasRequest. */
@ -1972,6 +2194,9 @@ export namespace vtadmin {
/** GetSchemasRequest cluster_ids. */
public cluster_ids: string[];
/** GetSchemasRequest table_size_options. */
public table_size_options?: (vtadmin.IGetSchemaTableSizeOptions|null);
/**
* Creates a new GetSchemasRequest instance using the specified properties.
* @param [properties] Properties to set
@ -2133,6 +2358,96 @@ export namespace vtadmin {
public toJSON(): { [k: string]: any };
}
/** Properties of a GetSchemaTableSizeOptions. */
interface IGetSchemaTableSizeOptions {
/** GetSchemaTableSizeOptions aggregate_sizes */
aggregate_sizes?: (boolean|null);
}
/** Represents a GetSchemaTableSizeOptions. */
class GetSchemaTableSizeOptions implements IGetSchemaTableSizeOptions {
/**
* Constructs a new GetSchemaTableSizeOptions.
* @param [properties] Properties to set
*/
constructor(properties?: vtadmin.IGetSchemaTableSizeOptions);
/** GetSchemaTableSizeOptions aggregate_sizes. */
public aggregate_sizes: boolean;
/**
* Creates a new GetSchemaTableSizeOptions instance using the specified properties.
* @param [properties] Properties to set
* @returns GetSchemaTableSizeOptions instance
*/
public static create(properties?: vtadmin.IGetSchemaTableSizeOptions): vtadmin.GetSchemaTableSizeOptions;
/**
* Encodes the specified GetSchemaTableSizeOptions message. Does not implicitly {@link vtadmin.GetSchemaTableSizeOptions.verify|verify} messages.
* @param message GetSchemaTableSizeOptions message or plain object to encode
* @param [writer] Writer to encode to
* @returns Writer
*/
public static encode(message: vtadmin.IGetSchemaTableSizeOptions, writer?: $protobuf.Writer): $protobuf.Writer;
/**
* Encodes the specified GetSchemaTableSizeOptions message, length delimited. Does not implicitly {@link vtadmin.GetSchemaTableSizeOptions.verify|verify} messages.
* @param message GetSchemaTableSizeOptions message or plain object to encode
* @param [writer] Writer to encode to
* @returns Writer
*/
public static encodeDelimited(message: vtadmin.IGetSchemaTableSizeOptions, writer?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes a GetSchemaTableSizeOptions message from the specified reader or buffer.
* @param reader Reader or buffer to decode from
* @param [length] Message length if known beforehand
* @returns GetSchemaTableSizeOptions
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): vtadmin.GetSchemaTableSizeOptions;
/**
* Decodes a GetSchemaTableSizeOptions message from the specified reader or buffer, length delimited.
* @param reader Reader or buffer to decode from
* @returns GetSchemaTableSizeOptions
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): vtadmin.GetSchemaTableSizeOptions;
/**
* Verifies a GetSchemaTableSizeOptions message.
* @param message Plain object to verify
* @returns `null` if valid, otherwise the reason why it is not
*/
public static verify(message: { [k: string]: any }): (string|null);
/**
* Creates a GetSchemaTableSizeOptions message from a plain object. Also converts values to their respective internal types.
* @param object Plain object
* @returns GetSchemaTableSizeOptions
*/
public static fromObject(object: { [k: string]: any }): vtadmin.GetSchemaTableSizeOptions;
/**
* Creates a plain object from a GetSchemaTableSizeOptions message. Also converts values to other types if specified.
* @param message GetSchemaTableSizeOptions
* @param [options] Conversion options
* @returns Plain object
*/
public static toObject(message: vtadmin.GetSchemaTableSizeOptions, options?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this GetSchemaTableSizeOptions to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}
/** Properties of a GetTabletRequest. */
interface IGetTabletRequest {

Разница между файлами не показана из-за своего большого размера Загрузить разницу