Skip to content
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
104 changes: 57 additions & 47 deletions pkg/sql/crdb_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,12 @@ var crdbInternal = virtualSchema{
}

// SupportedCRDBInternal are the crdb_internal tables that are "supported" for real
// customer use in production for legacy reasons. Avoid adding to this list if
// possible and prefer to add new customer-facing tables that should be public
// under the non-"internal" namespace of information_schema.
// customer use in production for legacy reasons.
var SupportedCRDBInternalTables = map[string]struct{}{
// LOCKED: Do not add to this list.
// Supported tables now go in pkg/sql/vtable/information_schema_crdb.go
// More information can be found at the below document:
// https://docs.google.com/document/d/1STbb8bljTzK_jXRIJrxtijWsPhGErdH1vZdunzPwXvs/edit?tab=t.0
`cluster_contended_indexes`: {},
`cluster_contended_keys`: {},
`cluster_contended_tables`: {},
Expand Down Expand Up @@ -6875,6 +6877,57 @@ CREATE TABLE crdb_internal.default_privileges (
},
}

func indexUsageStatisticsGenerator(
ctx context.Context,
p *planner,
dbContext catalog.DatabaseDescriptor,
_ int64,
stopper *stop.Stopper,
) (virtualTableGenerator, cleanupFunc, error) {
// Perform RPC Fanout.
stats, err :=
p.extendedEvalCtx.SQLStatusServer.IndexUsageStatistics(ctx, &serverpb.IndexUsageStatisticsRequest{})
if err != nil {
return nil, nil, err
}
indexStats := idxusage.NewLocalIndexUsageStatsFromExistingStats(&idxusage.Config{}, stats.Statistics)

const numDatums = 4
row := make(tree.Datums, numDatums)
worker := func(ctx context.Context, pusher rowPusher) error {
opts := forEachTableDescOptions{virtualOpts: hideVirtual, allowAdding: true}
return forEachTableDesc(ctx, p, dbContext, opts,
func(ctx context.Context, descCtx tableDescContext) error {
table := descCtx.table
tableID := table.GetID()
return catalog.ForEachIndex(table, catalog.IndexOpts{}, func(idx catalog.Index) error {
indexID := idx.GetID()
stats := indexStats.Get(roachpb.TableID(tableID), roachpb.IndexID(indexID))
lastScanTs := tree.DNull
if !stats.LastRead.IsZero() {
lastScanTs, err = tree.MakeDTimestampTZ(stats.LastRead, time.Nanosecond)
if err != nil {
return err
}
}
row = append(row[:0],
tree.NewDInt(tree.DInt(tableID)), // tableID
tree.NewDInt(tree.DInt(indexID)), // indexID
tree.NewDInt(tree.DInt(stats.TotalReadCount)), // total_reads
lastScanTs, // last_scan
)
if buildutil.CrdbTestBuild {
if len(row) != numDatums {
return errors.AssertionFailedf("expected %d datums, got %d", numDatums, len(row))
}
}
return pusher.pushRow(row...)
})
})
}
return setupGenerator(ctx, worker, stopper)
}

var crdbInternalIndexUsageStatistics = virtualSchemaTable{
comment: `cluster-wide index usage statistics (in-memory, not durable).` +
`Querying this table is an expensive operation since it creates a` +
Expand All @@ -6886,50 +6939,7 @@ CREATE TABLE crdb_internal.index_usage_statistics (
total_reads INT NOT NULL,
last_read TIMESTAMPTZ
);`,
generator: func(ctx context.Context, p *planner, dbContext catalog.DatabaseDescriptor, _ int64, stopper *stop.Stopper) (virtualTableGenerator, cleanupFunc, error) {
// Perform RPC Fanout.
stats, err :=
p.extendedEvalCtx.SQLStatusServer.IndexUsageStatistics(ctx, &serverpb.IndexUsageStatisticsRequest{})
if err != nil {
return nil, nil, err
}
indexStats := idxusage.NewLocalIndexUsageStatsFromExistingStats(&idxusage.Config{}, stats.Statistics)

const numDatums = 4
row := make(tree.Datums, numDatums)
worker := func(ctx context.Context, pusher rowPusher) error {
opts := forEachTableDescOptions{virtualOpts: hideVirtual, allowAdding: true}
return forEachTableDesc(ctx, p, dbContext, opts,
func(ctx context.Context, descCtx tableDescContext) error {
table := descCtx.table
tableID := table.GetID()
return catalog.ForEachIndex(table, catalog.IndexOpts{}, func(idx catalog.Index) error {
indexID := idx.GetID()
stats := indexStats.Get(roachpb.TableID(tableID), roachpb.IndexID(indexID))
lastScanTs := tree.DNull
if !stats.LastRead.IsZero() {
lastScanTs, err = tree.MakeDTimestampTZ(stats.LastRead, time.Nanosecond)
if err != nil {
return err
}
}
row = append(row[:0],
tree.NewDInt(tree.DInt(tableID)), // tableID
tree.NewDInt(tree.DInt(indexID)), // indexID
tree.NewDInt(tree.DInt(stats.TotalReadCount)), // total_reads
lastScanTs, // last_scan
)
if buildutil.CrdbTestBuild {
if len(row) != numDatums {
return errors.AssertionFailedf("expected %d datums, got %d", numDatums, len(row))
}
}
return pusher.pushRow(row...)
})
})
}
return setupGenerator(ctx, worker, stopper)
},
generator: indexUsageStatisticsGenerator,
}

// crdb_internal.cluster_statement_statistics contains cluster-wide statement statistics
Expand Down
46 changes: 46 additions & 0 deletions pkg/sql/crdb_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1834,3 +1834,49 @@ func TestMVCCValueHeaderSystemColumns(t *testing.T) {
})
}
}

// TestSupportedCRDBInternalTablesNotChanged verifies that the
// SupportedCRDBInternalTables map has not changed from its expected values.
// This test ensures no tables are inadvertently added to this locked list.
func TestSupportedCRDBInternalTablesNotChanged(t *testing.T) {
defer leaktest.AfterTest(t)()

// Hardcoded expected values for SupportedCRDBInternalTables
// IMPORTANT: This list is LOCKED and should NOT be modified.
// New tables should be added to information_schema instead.
expectedTables := map[string]struct{}{
`cluster_contended_indexes`: {},
`cluster_contended_keys`: {},
`cluster_contended_tables`: {},
`cluster_contention_events`: {},
`cluster_locks`: {},
`cluster_queries`: {},
`cluster_sessions`: {},
`cluster_transactions`: {},
`index_usage_statistics`: {},
`statement_statistics`: {},
`transaction_contention_events`: {},
`transaction_statistics`: {},
`zones`: {},
}

// Check that the actual map matches the expected map
if len(sql.SupportedCRDBInternalTables) != len(expectedTables) {
t.Fatalf("FAILURE: SupportedCRDBInternalTables has been modified!\n"+
"This list is LOCKED and should NOT be changed.\n"+
"New crdb_internal tables should be added to information_schema instead.\n"+
"Expected %d tables, but found %d tables.\n"+
"See: https://docs.google.com/document/d/1STbb8bljTzK_jXRIJrxtijWsPhGErdH1vZdunzPwXvs/edit",
len(expectedTables), len(sql.SupportedCRDBInternalTables))
}

// Check each expected table is present
for table := range expectedTables {
if _, ok := sql.SupportedCRDBInternalTables[table]; !ok {
t.Fatalf("FAILURE: SupportedCRDBInternalTables has been modified!\n" +
"This list is LOCKED and should NOT be changed.\n" +
"New crdb_internal tables should be added to information_schema instead.\n" +
"See: https://docs.google.com/document/d/1STbb8bljTzK_jXRIJrxtijWsPhGErdH1vZdunzPwXvs/edit")
}
}
}
9 changes: 9 additions & 0 deletions pkg/sql/information_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ var informationSchema = virtualSchema{
catconstants.InformationSchemaViewRoutineUsageTableID: informationSchemaViewRoutineUsageTable,
catconstants.InformationSchemaViewTableUsageTableID: informationSchemaViewTableUsageTable,
catconstants.InformationSchemaViewsTableID: informationSchemaViewsTable,
catconstants.InformationSchemaCrdbIndexUsageStatsiticsTableID: informationSchemaCrdbIndexUsageStatsTable,
},
tableValidator: validateInformationSchemaTable,
validWithNoDatabaseContext: true,
Expand Down Expand Up @@ -2541,6 +2542,14 @@ var informationSchemaViewTableUsageTable = virtualSchemaTable{
unimplemented: true,
}

var informationSchemaCrdbIndexUsageStatsTable = virtualSchemaTable{
comment: `cluster-wide index usage statistics (in-memory, not durable).` +
`Querying this table is an expensive operation since it creates a` +
`cluster-wide RPC fanout.`,
schema: vtable.CRDBIndexUsageStatistics,
generator: indexUsageStatisticsGenerator,
}

// forEachSchema iterates over the physical and virtual schemas.
func forEachSchema(
ctx context.Context,
Expand Down
Loading
Loading