From c02b4d038520e62ad2ae595115148897f6a63d88 Mon Sep 17 00:00:00 2001 From: Alex Sarkesian Date: Thu, 7 Apr 2022 22:53:19 +0000 Subject: [PATCH] sql: add virtual indexes to crdb_internal.cluster_locks virtual table This change adds virtual indexes on the `table_id`, `database_name`, and `table_name` columns of the `crdb_internal.cluster_locks` virtual table, so that when queried, the `kv.Batch`es with `QueryLocksRequest`s can be constrained to query only specific tables or databases. This allows the requests to be much more limited, rather than needing to request all of the ranges that comprise the key spans of all tables accessible by the user. Release note (sql change): Improved query performance for `crdb_internal.cluster_locks` when issued with constraints in the WHERE clause on `table_id`, `database_name`, or `table_name` columns. --- pkg/sql/crdb_internal.go | 115 ++++++++++++++++-- .../testdata/logic_test/cluster_locks | 29 +++++ .../testdata/logic_test/create_statements | 24 ++-- 3 files changed, 153 insertions(+), 15 deletions(-) diff --git a/pkg/sql/crdb_internal.go b/pkg/sql/crdb_internal.go index 6b4eee7dce88..f9070d53f631 100644 --- a/pkg/sql/crdb_internal.go +++ b/pkg/sql/crdb_internal.go @@ -5814,9 +5814,9 @@ var crdbInternalClusterLocksTable = virtualSchemaTable{ CREATE TABLE crdb_internal.cluster_locks ( range_id INT NOT NULL, table_id INT NOT NULL, - database_name STRING, + database_name STRING NOT NULL, schema_name STRING, - table_name STRING, + table_name STRING NOT NULL, index_name STRING, lock_key BYTES NOT NULL, lock_key_pretty STRING NOT NULL, @@ -5825,11 +5825,57 @@ CREATE TABLE crdb_internal.cluster_locks ( lock_strength STRING, durability STRING, granted BOOL, - contended BOOL, - duration INTERVAL + contended BOOL NOT NULL, + duration INTERVAL, + INDEX(table_id), + INDEX(database_name), + INDEX(table_name), + INDEX(contended) );`, - indexes: nil, - generator: func(ctx context.Context, p *planner, db catalog.DatabaseDescriptor, stopper *stop.Stopper) (virtualTableGenerator, cleanupFunc, error) { + indexes: []virtualIndex{ + { + populate: genPopulateClusterLocksWithIndex("table_id" /* idxColumnName */, func(filters *clusterLocksFilters, idxConstraint tree.Datum) { + if tableID, ok := tree.AsDInt(idxConstraint); ok { + filters.tableID = (*int64)(&tableID) + } + }), + }, + { + populate: genPopulateClusterLocksWithIndex("database_name" /* idxColumnName */, func(filters *clusterLocksFilters, idxConstraint tree.Datum) { + if dbName, ok := tree.AsDString(idxConstraint); ok { + filters.databaseName = (*string)(&dbName) + } + }), + }, + { + populate: genPopulateClusterLocksWithIndex("table_name" /* idxColumnName */, func(filters *clusterLocksFilters, idxConstraint tree.Datum) { + if tableName, ok := tree.AsDString(idxConstraint); ok { + filters.tableName = (*string)(&tableName) + } + }), + }, + { + populate: genPopulateClusterLocksWithIndex("contended" /* idxColumnName */, func(filters *clusterLocksFilters, idxConstraint tree.Datum) { + if contended, ok := tree.AsDBool(idxConstraint); ok { + filters.contended = (*bool)(&contended) + } + }), + }, + }, + generator: genClusterLocksGenerator(clusterLocksFilters{}), +} + +type clusterLocksFilters struct { + tableID *int64 + databaseName *string + tableName *string + contended *bool +} + +func genClusterLocksGenerator( + filters clusterLocksFilters, +) func(ctx context.Context, p *planner, db catalog.DatabaseDescriptor, stopper *stop.Stopper) (virtualTableGenerator, cleanupFunc, error) { + return func(ctx context.Context, p *planner, _ catalog.DatabaseDescriptor, _ *stop.Stopper) (virtualTableGenerator, cleanupFunc, error) { // TODO(sarkesian): remove gate for 22.2 release if !p.ExecCfg().Settings.Version.IsActive(ctx, clusterversion.ClusterLocksVirtualTable) { return nil, nil, pgerror.New(pgcode.FeatureNotSupported, @@ -5879,6 +5925,15 @@ CREATE TABLE crdb_internal.cluster_locks ( } switch desc := desc.(type) { case catalog.TableDescriptor: + if filters.tableName != nil && *filters.tableName != desc.GetName() { + continue + } + if filters.tableID != nil && descpb.ID(*filters.tableID) != desc.GetID() { + continue + } + if filters.databaseName != nil && *filters.databaseName != dbNames[uint32(desc.GetParentID())] { + continue + } spansToQuery = append(spansToQuery, desc.TableSpan(p.execCfg.Codec)) } } @@ -5910,6 +5965,10 @@ CREATE TABLE crdb_internal.cluster_locks ( }, IncludeUncontended: true, } + if filters.contended != nil && *filters.contended { + queryLocksRequest.IncludeUncontended = false + } + b.AddRawRequest(queryLocksRequest) b.Header.MaxSpanRequestKeys = int64(rowinfra.ProductionKVBatchSize) @@ -6047,5 +6106,47 @@ CREATE TABLE crdb_internal.cluster_locks ( }, nil }, nil, nil - }, + } +} + +func genPopulateClusterLocksWithIndex( + idxColumnName string, setFilters func(filters *clusterLocksFilters, idxConstraint tree.Datum), +) func(context.Context, tree.Datum, *planner, catalog.DatabaseDescriptor, func(...tree.Datum) error) (bool, error) { + return func(ctx context.Context, idxConstraint tree.Datum, p *planner, db catalog.DatabaseDescriptor, addRow func(...tree.Datum) error) (matched bool, err error) { + var filters clusterLocksFilters + setFilters(&filters, idxConstraint) + + if filters.tableID == nil && filters.databaseName == nil && filters.tableName == nil && filters.contended == nil { + return false, errors.AssertionFailedf("unexpected type %T for %s column in virtual table crdb_internal.cluster_locks", idxConstraint, idxColumnName) + } + + return populateClusterLocksWithFilter(ctx, p, db, addRow, filters) + } +} + +func populateClusterLocksWithFilter( + ctx context.Context, + p *planner, + db catalog.DatabaseDescriptor, + addRow func(...tree.Datum) error, + filters clusterLocksFilters, +) (matched bool, err error) { + var rowGenerator virtualTableGenerator + generator := genClusterLocksGenerator(filters) + rowGenerator, _, err = generator(ctx, p, db, nil /* stopper */) + if err != nil { + return false, err + } + var row tree.Datums + row, err = rowGenerator() + for row != nil && err == nil { + err = addRow(row...) + if err != nil { + break + } + matched = true + + row, err = rowGenerator() + } + return matched, err } diff --git a/pkg/sql/logictest/testdata/logic_test/cluster_locks b/pkg/sql/logictest/testdata/logic_test/cluster_locks index 74faccf186fa..759c7ecdc184 100644 --- a/pkg/sql/logictest/testdata/logic_test/cluster_locks +++ b/pkg/sql/logictest/testdata/logic_test/cluster_locks @@ -145,6 +145,35 @@ test public t ยท Exclusive Repli user root +query TTTTTTBB colnames,retry +SELECT database_name, schema_name, table_name, lock_key_pretty, lock_strength, durability, granted, contended FROM crdb_internal.cluster_locks WHERE database_name='test' +---- +database_name schema_name table_name lock_key_pretty lock_strength durability granted contended +test public t /Table/106/1/"b"/0 Exclusive Replicated true true +test public t /Table/106/1/"b"/0 None Replicated false true +test public t /Table/106/1/"c"/0 Exclusive Replicated true false + +query TTTTTTBB colnames,retry +SELECT database_name, schema_name, table_name, lock_key_pretty, lock_strength, durability, granted, contended FROM crdb_internal.cluster_locks WHERE table_id='t'::regclass::oid::int +---- +database_name schema_name table_name lock_key_pretty lock_strength durability granted contended +test public t /Table/106/1/"b"/0 Exclusive Replicated true true +test public t /Table/106/1/"b"/0 None Replicated false true +test public t /Table/106/1/"c"/0 Exclusive Replicated true false + +query TTTTTTBB colnames,retry +SELECT database_name, schema_name, table_name, lock_key_pretty, lock_strength, durability, granted, contended FROM crdb_internal.cluster_locks WHERE contended=true +---- +database_name schema_name table_name lock_key_pretty lock_strength durability granted contended +test public t /Table/106/1/"b"/0 Exclusive Replicated true true +test public t /Table/106/1/"b"/0 None Replicated false true + +query TTTTTTBB colnames,retry +SELECT database_name, schema_name, table_name, lock_key_pretty, lock_strength, durability, granted, contended FROM crdb_internal.cluster_locks WHERE contended=false +---- +database_name schema_name table_name lock_key_pretty lock_strength durability granted contended +test public t /Table/106/1/"c"/0 Exclusive Replicated true false + query I SELECT count(*) FROM crdb_internal.cluster_locks WHERE table_name = 't' ---- diff --git a/pkg/sql/logictest/testdata/logic_test/create_statements b/pkg/sql/logictest/testdata/logic_test/create_statements index e5af8180fa46..3c5f8b3a7ca7 100644 --- a/pkg/sql/logictest/testdata/logic_test/create_statements +++ b/pkg/sql/logictest/testdata/logic_test/create_statements @@ -253,9 +253,9 @@ CREATE TABLE crdb_internal.cluster_inflight_traces ( CREATE TABLE crdb_internal.cluster_locks ( range_id INT8 NOT NULL, table_id INT8 NOT NULL, - database_name STRING NULL, + database_name STRING NOT NULL, schema_name STRING NULL, - table_name STRING NULL, + table_name STRING NOT NULL, index_name STRING NULL, lock_key BYTES NOT NULL, lock_key_pretty STRING NOT NULL, @@ -264,14 +264,18 @@ CREATE TABLE crdb_internal.cluster_locks ( lock_strength STRING NULL, durability STRING NULL, granted BOOL NULL, - contended BOOL NULL, - duration INTERVAL NULL + contended BOOL NOT NULL, + duration INTERVAL NULL, + INDEX cluster_locks_table_id_idx (table_id ASC) STORING (range_id, database_name, schema_name, table_name, index_name, lock_key, lock_key_pretty, txn_id, ts, lock_strength, durability, granted, contended, duration), + INDEX cluster_locks_database_name_idx (database_name ASC) STORING (range_id, table_id, schema_name, table_name, index_name, lock_key, lock_key_pretty, txn_id, ts, lock_strength, durability, granted, contended, duration), + INDEX cluster_locks_table_name_idx (table_name ASC) STORING (range_id, table_id, database_name, schema_name, index_name, lock_key, lock_key_pretty, txn_id, ts, lock_strength, durability, granted, contended, duration), + INDEX cluster_locks_contended_idx (contended ASC) STORING (range_id, table_id, database_name, schema_name, table_name, index_name, lock_key, lock_key_pretty, txn_id, ts, lock_strength, durability, granted, duration) ) CREATE TABLE crdb_internal.cluster_locks ( range_id INT8 NOT NULL, table_id INT8 NOT NULL, - database_name STRING NULL, + database_name STRING NOT NULL, schema_name STRING NULL, - table_name STRING NULL, + table_name STRING NOT NULL, index_name STRING NULL, lock_key BYTES NOT NULL, lock_key_pretty STRING NOT NULL, @@ -280,8 +284,12 @@ CREATE TABLE crdb_internal.cluster_locks ( lock_strength STRING NULL, durability STRING NULL, granted BOOL NULL, - contended BOOL NULL, - duration INTERVAL NULL + contended BOOL NOT NULL, + duration INTERVAL NULL, + INDEX cluster_locks_table_id_idx (table_id ASC) STORING (range_id, database_name, schema_name, table_name, index_name, lock_key, lock_key_pretty, txn_id, ts, lock_strength, durability, granted, contended, duration), + INDEX cluster_locks_database_name_idx (database_name ASC) STORING (range_id, table_id, schema_name, table_name, index_name, lock_key, lock_key_pretty, txn_id, ts, lock_strength, durability, granted, contended, duration), + INDEX cluster_locks_table_name_idx (table_name ASC) STORING (range_id, table_id, database_name, schema_name, index_name, lock_key, lock_key_pretty, txn_id, ts, lock_strength, durability, granted, contended, duration), + INDEX cluster_locks_contended_idx (contended ASC) STORING (range_id, table_id, database_name, schema_name, table_name, index_name, lock_key, lock_key_pretty, txn_id, ts, lock_strength, durability, granted, duration) ) {} {} CREATE TABLE crdb_internal.cluster_queries ( query_id STRING NULL,