Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: add statement fingerprint to insights #96872

Merged
merged 1 commit into from
Feb 13, 2023
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
129 changes: 62 additions & 67 deletions pkg/sql/crdb_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/sql/catalog/systemschema"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/typedesc"
"github.com/cockroachdb/cockroach/pkg/sql/clusterunique"
"github.com/cockroachdb/cockroach/pkg/sql/contentionpb"
"github.com/cockroachdb/cockroach/pkg/sql/idxusage"
"github.com/cockroachdb/cockroach/pkg/sql/isql"
"github.com/cockroachdb/cockroach/pkg/sql/parser"
Expand Down Expand Up @@ -6473,9 +6474,15 @@ CREATE TABLE crdb_internal.transaction_contention_events (

contention_duration INTERVAL NOT NULL,
contending_key BYTES NOT NULL,

waiting_stmt_id string NOT NULL,
waiting_stmt_fingerprint_id BYTES NOT NULL
contending_pretty_key STRING NOT NULL,

waiting_stmt_id string NOT NULL,
waiting_stmt_fingerprint_id BYTES NOT NULL,

database_name STRING NOT NULL,
schema_name STRING NOT NULL,
table_name STRING NOT NULL,
index_name STRING
);`,
generator: func(ctx context.Context, p *planner, db catalog.DatabaseDescriptor, stopper *stop.Stopper) (virtualTableGenerator, cleanupFunc, error) {
// Check permission first before making RPC fanout.
Expand Down Expand Up @@ -6541,28 +6548,41 @@ CREATE TABLE crdb_internal.transaction_contention_events (
types.DefaultIntervalTypeMetadata,
)

contendingPrettyKey := tree.NewDString("")
contendingKey := tree.NewDBytes("")
if !shouldRedactContendingKey {
decodedKey, _, _ := keys.DecodeTenantPrefix(resp.Events[i].BlockingEvent.Key)
contendingPrettyKey = tree.NewDString(keys.PrettyPrint(nil /* valDirs */, decodedKey))
contendingKey = tree.NewDBytes(
tree.DBytes(resp.Events[i].BlockingEvent.Key))
tree.DBytes(decodedKey))
}

waitingStmtFingerprintID := tree.NewDBytes(
tree.DBytes(sqlstatsutil.EncodeUint64ToBytes(uint64(resp.Events[i].WaitingStmtFingerprintID))))

waitingStmtId := tree.NewDString(hex.EncodeToString(resp.Events[i].WaitingStmtID.GetBytes()))

schemaName, dbName, tableName, indexName, err := getContentionEventInfo(ctx, p, resp.Events[i])
if err != nil {
return err
}

row = row[:0]
row = append(row,
collectionTs, // collection_ts
tree.NewDUuid(tree.DUuid{UUID: resp.Events[i].BlockingEvent.TxnMeta.ID}), // blocking_txn_id
blockingFingerprintID, // blocking_fingerprint_id
tree.NewDUuid(tree.DUuid{UUID: resp.Events[i].WaitingTxnID}), // waiting_txn_id
waitingFingerprintID, // waiting_fingerprint_id
contentionDuration, // contention_duration
contendingKey, // contending_key,
waitingStmtId, // waiting_stmt_id
waitingStmtFingerprintID, // waiting_stmt_fingerprint_id
waitingFingerprintID, // waiting_fingerprint_id
contentionDuration, // contention_duration
contendingKey, // contending_key,
contendingPrettyKey, // contending_pretty_key
waitingStmtId, // waiting_stmt_id
waitingStmtFingerprintID, // waiting_stmt_fingerprint_id
tree.NewDString(dbName), // database_name
tree.NewDString(schemaName), // schema_name
tree.NewDString(tableName), // table_name
tree.NewDString(indexName), // index_name
)

if err = pusher.pushRow(row...); err != nil {
Expand Down Expand Up @@ -7207,7 +7227,6 @@ CREATE TABLE crdb_internal.%s (
last_retry_reason STRING,
exec_node_ids INT[] NOT NULL,
contention INTERVAL,
contention_events JSONB,
index_recommendations STRING[] NOT NULL,
implicit_txn BOOL NOT NULL,
cpu_sql_nanos INT8
Expand Down Expand Up @@ -7295,17 +7314,6 @@ func populateStmtInsights(
)
}

contentionEvents := tree.DNull
if len(s.ContentionEvents) > 0 {
var contentionEventsJSON json.JSON
contentionEventsJSON, err = convertContentionEventsToJSON(ctx, p, s.ContentionEvents)
if err != nil {
return err
}

contentionEvents = tree.NewDJSON(contentionEventsJSON)
}

indexRecommendations := tree.NewDArray(types.String)
for _, recommendation := range s.IndexRecommendations {
if err = indexRecommendations.Append(tree.NewDString(recommendation)); err != nil {
Expand Down Expand Up @@ -7337,7 +7345,6 @@ func populateStmtInsights(
autoRetryReason,
execNodeIDs,
contentionTime,
contentionEvents,
indexRecommendations,
tree.MakeDBool(tree.DBool(insight.Transaction.ImplicitTxn)),
tree.NewDInt(tree.DInt(s.CPUSQLNanos)),
Expand All @@ -7347,57 +7354,45 @@ func populateStmtInsights(
return
}

func convertContentionEventsToJSON(
ctx context.Context, p *planner, contentionEvents []roachpb.ContentionEvent,
) (json json.JSON, err error) {
func getContentionEventInfo(
ctx context.Context, p *planner, contentionEvent contentionpb.ExtendedContentionEvent,
) (schemaName, dbName, tableName, indexName string, err error) {

eventWithNames := make([]sqlstatsutil.ContentionEventWithNames, len(contentionEvents))
for i, contentionEvent := range contentionEvents {
_, tableID, err := p.ExecCfg().Codec.DecodeTablePrefix(contentionEvent.Key)
if err != nil {
return nil, err
}
_, _, indexID, err := p.ExecCfg().Codec.DecodeIndexPrefix(contentionEvent.Key)
if err != nil {
return nil, err
}

desc := p.Descriptors()
var tableDesc catalog.TableDescriptor
tableDesc, err = desc.ByIDWithLeased(p.txn).WithoutNonPublic().Get().Table(ctx, descpb.ID(tableID))
if err != nil {
return nil, err
}
_, tableID, err := p.ExecCfg().Codec.DecodeTablePrefix(contentionEvent.BlockingEvent.Key)
if err != nil {
return "", "", "", "", err
}
_, _, indexID, err := p.ExecCfg().Codec.DecodeIndexPrefix(contentionEvent.BlockingEvent.Key)
if err != nil {
return "", "", "", "", err
}

idxDesc, err := catalog.MustFindIndexByID(tableDesc, descpb.IndexID(indexID))
if err != nil {
return nil, err
}
desc := p.Descriptors()
var tableDesc catalog.TableDescriptor
tableDesc, err = desc.ByIDWithLeased(p.txn).WithoutNonPublic().Get().Table(ctx, descpb.ID(tableID))
if err != nil {
return "", "", "", "", err
}

dbDesc, err := desc.ByIDWithLeased(p.txn).WithoutNonPublic().Get().Database(ctx, tableDesc.GetParentID())
if err != nil {
return nil, err
}
idxDesc, err := catalog.MustFindIndexByID(tableDesc, descpb.IndexID(indexID))
if err != nil {
return "", "", "", "", err
}

schemaDesc, err := desc.ByIDWithLeased(p.txn).WithoutNonPublic().Get().Schema(ctx, tableDesc.GetParentSchemaID())
if err != nil {
return nil, err
}
dbDesc, err := desc.ByIDWithLeased(p.txn).WithoutNonPublic().Get().Database(ctx, tableDesc.GetParentID())
if err != nil {
return "", "", "", "", err
}

var idxName string
if idxDesc != nil {
idxName = idxDesc.GetName()
}
schemaDesc, err := desc.ByIDWithLeased(p.txn).WithoutNonPublic().Get().Schema(ctx, tableDesc.GetParentSchemaID())
if err != nil {
return "", "", "", "", err
}

eventWithNames[i] = sqlstatsutil.ContentionEventWithNames{
BlockingTransactionID: contentionEvent.TxnMeta.ID.String(),
SchemaName: schemaDesc.GetName(),
DatabaseName: dbDesc.GetName(),
TableName: tableDesc.GetName(),
IndexName: idxName,
DurationInMs: float64(contentionEvent.Duration) / float64(time.Millisecond),
}
var idxName string
if idxDesc != nil {
idxName = idxDesc.GetName()
}

return sqlstatsutil.BuildContentionEventsJSON(eventWithNames)
return schemaDesc.GetName(), dbDesc.GetName(), tableDesc.GetName(), idxName, nil
}
30 changes: 26 additions & 4 deletions pkg/sql/crdb_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,12 @@ func TestTxnContentionEventsTable(t *testing.T) {
waiting_stmt_id,
encode(
waiting_txn_fingerprint_id, 'hex'
) AS waiting_txn_fingerprint_id
) AS waiting_txn_fingerprint_id,
contending_pretty_key,
database_name,
schema_name,
table_name,
index_name
FROM crdb_internal.transaction_contention_events tce
inner join (
select
Expand All @@ -1001,7 +1006,8 @@ func TestTxnContentionEventsTable(t *testing.T) {
rowCount++

var blockingTxnId, waitingTxnId, waitingStmtId, waitingStmtFingerprint string
errVerify = rows.Scan(&blockingTxnId, &waitingTxnId, &waitingStmtId, &waitingStmtFingerprint)
var prettyKey, dbName, schemaName, tableName, indexName string
errVerify = rows.Scan(&blockingTxnId, &waitingTxnId, &waitingStmtId, &waitingStmtFingerprint, &prettyKey, &dbName, &schemaName, &tableName, &indexName)
if errVerify != nil {
return errVerify
}
Expand All @@ -1015,8 +1021,24 @@ func TestTxnContentionEventsTable(t *testing.T) {
return fmt.Errorf("transaction_contention_events had default waiting txn id %s, blocking txn id %s", waitingTxnId, blockingTxnId)
}

if waitingStmtId == defaultIdString {
return fmt.Errorf("transaction_contention_events had default waiting stmt id %s, blocking txn id %s, waiting txn id %s", waitingStmtId, blockingTxnId, waitingTxnId)
if !strings.HasPrefix(prettyKey, "/Table/") {
return fmt.Errorf("prettyKey should be defaultdb: %s, %s, %s, %s, %s", prettyKey, dbName, schemaName, tableName, indexName)
}

if dbName != "defaultdb" {
return fmt.Errorf("dbName should be defaultdb: %s, %s, %s, %s, %s", prettyKey, dbName, schemaName, tableName, indexName)
}

if schemaName != "public" {
return fmt.Errorf("schemaName should be public: %s, %s, %s, %s, %s", prettyKey, dbName, schemaName, tableName, indexName)
}

if tableName != "t" {
return fmt.Errorf("tableName should be t: %s, %s, %s, %s, %s", prettyKey, dbName, schemaName, tableName, indexName)
}

if indexName != "t_pkey" {
return fmt.Errorf("indexName should be t_pkey: %s, %s, %s, %s, %s", prettyKey, dbName, schemaName, tableName, indexName)
}
}

Expand Down
Loading