From 653f0521f68531331048b4bab092a765008a5991 Mon Sep 17 00:00:00 2001 From: Eric Harmeling Date: Tue, 6 Sep 2022 09:35:30 -0400 Subject: [PATCH] ui: update txn contention insights to use waiting txns as event This commit updates the transaction workload insights pages to use the waiting contended transaction as the primary contention event, rather than the blocking transaction. Fixes #87284. Release justification: bug fixes and low-risk updates to new functionality Release note: None --- .../cluster-ui/src/api/insightsApi.ts | 121 +++++++++--------- .../detailsPanels/waitTimeInsightsPanel.tsx | 6 +- .../cluster-ui/src/insights/types.ts | 6 +- .../transactionInsightDetails.tsx | 12 +- .../statementInsightsView.tsx | 4 +- .../transactionInsightsView.tsx | 4 +- 6 files changed, 79 insertions(+), 74 deletions(-) diff --git a/pkg/ui/workspaces/cluster-ui/src/api/insightsApi.ts b/pkg/ui/workspaces/cluster-ui/src/api/insightsApi.ts index 16dbcb122edf..be568981d64f 100644 --- a/pkg/ui/workspaces/cluster-ui/src/api/insightsApi.ts +++ b/pkg/ui/workspaces/cluster-ui/src/api/insightsApi.ts @@ -52,14 +52,14 @@ export type TransactionContentionEventsResponse = // txnContentionQuery selects all relevant transaction contention events. const txnContentionQuery = `SELECT * - FROM (SELECT blocking_txn_id, + FROM (SELECT waiting_txn_id, encode( - blocking_txn_fingerprint_id, 'hex' - ) AS blocking_txn_fingerprint_id, + waiting_txn_fingerprint_id, 'hex' + ) AS waiting_txn_fingerprint_id, collection_ts, contention_duration, row_number() over ( - PARTITION BY blocking_txn_fingerprint_id + PARTITION BY waiting_txn_fingerprint_id ORDER BY collection_ts DESC ) AS rank, @@ -67,7 +67,7 @@ const txnContentionQuery = `SELECT * FROM (SELECT "sql.insights.latency_threshold" :: INTERVAL AS threshold FROM [SHOW CLUSTER SETTING sql.insights.latency_threshold]), - (SELECT DISTINCT ON (blocking_txn_id) * + (SELECT DISTINCT ON (waiting_txn_id) * FROM crdb_internal.transaction_contention_events tce), (SELECT txn_id FROM crdb_internal.cluster_execution_insights) WHERE contention_duration > threshold @@ -75,8 +75,8 @@ const txnContentionQuery = `SELECT * WHERE rank = 1`; type TransactionContentionResponseColumns = { - blocking_txn_id: string; - blocking_txn_fingerprint_id: string; + waiting_txn_id: string; + waiting_txn_fingerprint_id: string; collection_ts: string; contention_duration: string; threshold: string; @@ -84,15 +84,15 @@ type TransactionContentionResponseColumns = { function transactionContentionResultsToEventState( response: SqlExecutionResponse, -): TransactionContentionEventState[] { +): TransactionContentionEventsResponse { if (!response.execution.txn_results[0].rows) { // No transaction contention events. return []; } return response.execution.txn_results[0].rows.map(row => ({ - transactionID: row.blocking_txn_id, - fingerprintID: row.blocking_txn_fingerprint_id, + transactionID: row.waiting_txn_id, + fingerprintID: row.waiting_txn_fingerprint_id, startTime: moment(row.collection_ts), contentionDuration: moment.duration(row.contention_duration), contentionThreshold: moment.duration(row.threshold).asMilliseconds(), @@ -196,7 +196,7 @@ export function getTransactionInsightEventState(): Promise row.blocking_txn_fingerprint_id); + const txnFingerprintIDs = res.map(row => row.waiting_txn_fingerprint_id); const txnFingerprintRequest: SqlExecutionRequest = { statements: [ { @@ -209,10 +209,12 @@ export function getTransactionInsightEventState(): Promise( txnFingerprintRequest, ).then(txnStmtFingerprintResults => { - const stmtFingerprintIDs = - txnStmtFingerprintResults.execution.txn_results[0].rows?.map( - row => row.query_ids, - ); + const txnStmtRes = + txnStmtFingerprintResults.execution.txn_results[0].rows; + if (!txnStmtRes || txnStmtRes.length < 1) { + return; + } + const stmtFingerprintIDs = txnStmtRes.map(row => row.query_ids); const fingerprintStmtsRequest: SqlExecutionRequest = { statements: [ { @@ -238,7 +240,7 @@ export function getTransactionInsightEventState(): Promise; export type TransactionContentionEventDetailsResponse = @@ -324,17 +326,17 @@ const txnContentionDetailsQuery = (id: string) => `SELECT collection_ts, LEFT OUTER JOIN crdb_internal.ranges AS ranges ON tce.contending_key BETWEEN ranges.start_key AND ranges.end_key - WHERE blocking_txn_id = '${id}' + WHERE waiting_txn_id = '${id}' `; type TxnContentionDetailsResponseColumns = { - blocking_txn_id: string; + waiting_txn_id: string; + waiting_txn_fingerprint_id: string; collection_ts: string; contention_duration: string; threshold: string; + blocking_txn_id: string; blocking_txn_fingerprint_id: string; - waiting_txn_id: string; - waiting_txn_fingerprint_id: string; schema_name: string; database_name: string; table_name: string; @@ -351,13 +353,13 @@ function transactionContentionDetailsResultsToEventState( } const row = response.execution.txn_results[0].rows[0]; return { - executionID: row.blocking_txn_id, + executionID: row.waiting_txn_id, + fingerprintID: row.waiting_txn_fingerprint_id, startTime: moment(row.collection_ts), elapsedTime: moment.duration(row.contention_duration).asMilliseconds(), contentionThreshold: moment.duration(row.threshold).asMilliseconds(), - fingerprintID: row.blocking_txn_fingerprint_id, - waitingExecutionID: row.waiting_txn_id, - waitingFingerprintID: row.waiting_txn_fingerprint_id, + blockingExecutionID: row.blocking_txn_id, + blockingFingerprintID: row.blocking_txn_fingerprint_id, schemaName: row.schema_name, databaseName: row.database_name, tableName: row.table_name, @@ -388,64 +390,63 @@ export function getTransactionInsightEventDetailsState( if (!res || res.length < 1) { return; } - const blockingTxnFingerprintId = res[0].blocking_txn_fingerprint_id; - const blockingTxnFingerprintRequest: SqlExecutionRequest = { + const waitingTxnFingerprintId = res[0].waiting_txn_fingerprint_id; + const waitingTxnFingerprintRequest: SqlExecutionRequest = { statements: [ { - sql: `${txnStmtFingerprintsQuery(blockingTxnFingerprintId)}`, + sql: `${txnStmtFingerprintsQuery(waitingTxnFingerprintId)}`, }, ], execute: true, max_result_size: 50000, // 50 kib }; return executeInternalSql( - blockingTxnFingerprintRequest, - ).then(blockingTxnStmtFingerprintIDs => { - const blockingStmtFingerprintIDs = - blockingTxnStmtFingerprintIDs.execution.txn_results[0].rows[0] - .query_ids; - const blockingFingerprintStmtsRequest: SqlExecutionRequest = { + waitingTxnFingerprintRequest, + ).then(waitingTxnStmtFingerprintIDs => { + const waitingStmtFingerprintIDs = + waitingTxnStmtFingerprintIDs.execution.txn_results[0].rows[0].query_ids; + const waitingFingerprintStmtsRequest: SqlExecutionRequest = { statements: [ { - sql: `${fingerprintStmtsQuery(blockingStmtFingerprintIDs)}`, + sql: `${fingerprintStmtsQuery(waitingStmtFingerprintIDs)}`, }, ], execute: true, max_result_size: 50000, // 50 kib }; return executeInternalSql( - blockingFingerprintStmtsRequest, - ).then(blockingTxnStmtQueries => { - const waitingTxnFingerprintId = + waitingFingerprintStmtsRequest, + ).then(waitingTxnStmtQueries => { + const blockingTxnFingerprintId = contentionResults.execution.txn_results[0].rows[0] - .waiting_txn_fingerprint_id; - const waitingTxnFingerprintRequest: SqlExecutionRequest = { + .blocking_txn_fingerprint_id; + const blockingTxnFingerprintRequest: SqlExecutionRequest = { statements: [ { - sql: `${txnStmtFingerprintsQuery(waitingTxnFingerprintId)}`, + sql: `${txnStmtFingerprintsQuery(blockingTxnFingerprintId)}`, }, ], execute: true, max_result_size: 50000, // 50 kib }; return executeInternalSql( - waitingTxnFingerprintRequest, - ).then(waitingTxnStmtFingerprintIDs => { - const waitingStmtFingerprintIDs = - waitingTxnStmtFingerprintIDs.execution.txn_results[0].rows[0] + blockingTxnFingerprintRequest, + ).then(blockingTxnStmtFingerprintIDs => { + const blockingStmtFingerprintIDs = + blockingTxnStmtFingerprintIDs.execution.txn_results[0].rows[0] .query_ids; - const waitingFingerprintStmtsRequest: SqlExecutionRequest = { + const blockingFingerprintStmtsRequest: SqlExecutionRequest = { statements: [ { - sql: `${fingerprintStmtsQuery(waitingStmtFingerprintIDs)}`, + sql: `${fingerprintStmtsQuery(blockingStmtFingerprintIDs)}`, }, ], execute: true, max_result_size: 50000, // 50 kib }; return executeInternalSql( - waitingFingerprintStmtsRequest, - ).then(waitingTxnStmtQueries => { + blockingFingerprintStmtsRequest, + ).then(blockingTxnStmtQueries => { return combineTransactionInsightEventDetailsState( transactionContentionDetailsResultsToEventState( contentionResults, @@ -454,10 +455,10 @@ export function getTransactionInsightEventDetailsState( blockingTxnStmtFingerprintIDs, ), txnStmtFingerprintsResultsToEventState( - waitingTxnStmtFingerprintIDs, + blockingTxnStmtFingerprintIDs, ), - fingerprintStmtsResultsToEventState(blockingTxnStmtQueries), fingerprintStmtsResultsToEventState(waitingTxnStmtQueries), + fingerprintStmtsResultsToEventState(blockingTxnStmtQueries), ); }); }); @@ -468,31 +469,31 @@ export function getTransactionInsightEventDetailsState( export function combineTransactionInsightEventDetailsState( txnContentionDetailsState: TransactionContentionEventDetailsResponse, - blockingTxnFingerprintState: TxnStmtFingerprintEventsResponse, waitingTxnFingerprintState: TxnStmtFingerprintEventsResponse, - blockingFingerprintStmtState: FingerprintStmtsEventsResponse, + blockingTxnFingerprintState: TxnStmtFingerprintEventsResponse, waitingFingerprintStmtState: FingerprintStmtsEventsResponse, + blockingFingerprintStmtState: FingerprintStmtsEventsResponse, ): TransactionInsightEventDetailsState { let res: TransactionInsightEventDetailsState; if ( txnContentionDetailsState && - blockingTxnFingerprintState && waitingTxnFingerprintState && - blockingFingerprintStmtState && - waitingFingerprintStmtState + blockingTxnFingerprintState && + waitingFingerprintStmtState && + blockingFingerprintStmtState ) { res = { ...txnContentionDetailsState, application: blockingTxnFingerprintState[0].application, - queries: blockingTxnFingerprintState[0].queryIDs.map( + queries: waitingTxnFingerprintState[0].queryIDs.map( id => - blockingFingerprintStmtState.find( + waitingFingerprintStmtState.find( stmt => stmt.stmtFingerprintID === id, )?.query, ), - waitingQueries: waitingTxnFingerprintState[0].queryIDs.map( + blockingQueries: blockingTxnFingerprintState[0].queryIDs.map( id => - waitingFingerprintStmtState.find( + blockingFingerprintStmtState.find( stmt => stmt.stmtFingerprintID === id, )?.query, ), diff --git a/pkg/ui/workspaces/cluster-ui/src/detailsPanels/waitTimeInsightsPanel.tsx b/pkg/ui/workspaces/cluster-ui/src/detailsPanels/waitTimeInsightsPanel.tsx index e16679d49613..8fcb5114efee 100644 --- a/pkg/ui/workspaces/cluster-ui/src/detailsPanels/waitTimeInsightsPanel.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/detailsPanels/waitTimeInsightsPanel.tsx @@ -37,8 +37,12 @@ export const WaitTimeInsightsLabels = { `${capitalize(execType)} ID: ${id} waiting on`, WAITING_TXNS_TABLE_TITLE: (id: string, execType: ExecutionType): string => `${capitalize(execType)}s waiting for ID: ${id}`, + BLOCKED_TXNS_TABLE_TITLE: (id: string, execType: ExecutionType): string => + `${capitalize(execType)} with ID ${id} waited on`, WAITED_TXNS_TABLE_TITLE: (id: string, execType: ExecutionType): string => - `${capitalize(execType)}s that waited for ID: ${id}`, + `${capitalize(execType)}s that waited for ${capitalize( + execType, + )}s with ID ${id}`, }; type WaitTimeInsightsPanelProps = { diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/types.ts b/pkg/ui/workspaces/cluster-ui/src/insights/types.ts index bbe76ceb1d26..97d22ac78347 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/types.ts +++ b/pkg/ui/workspaces/cluster-ui/src/insights/types.ts @@ -47,9 +47,9 @@ export type TransactionInsightEventDetails = { contentionThreshold: number; application: string; fingerprintID: string; - waitingExecutionID: string; - waitingFingerprintID: string; - waitingQueries: string[]; + blockingExecutionID: string; + blockingFingerprintID: string; + blockingQueries: string[]; contendedKey: string; schemaName: string; databaseName: string; diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetails.tsx index a098561c1ad3..9ce58c547686 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetails.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetails.tsx @@ -119,11 +119,11 @@ export class TransactionInsightDetails extends React.Component - {WaitTimeInsightsLabels.WAITED_TXNS_TABLE_TITLE( + {WaitTimeInsightsLabels.BLOCKED_TXNS_TABLE_TITLE( insightDetails.executionID, insightDetails.execType, )}
diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx index 680f99b96259..ee61bcc88700 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx @@ -251,7 +251,7 @@ export const StatementInsightsView: React.FC = (
InsightsError()} @@ -280,7 +280,7 @@ export const StatementInsightsView: React.FC = ( renderNoResult={ 0 && filteredStatements?.length > 0 + search?.length > 0 && filteredStatements?.length === 0 } /> } diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/transactionInsights/transactionInsightsView.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/transactionInsights/transactionInsightsView.tsx index 8cc59f44056e..3cad40750804 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/transactionInsights/transactionInsightsView.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/transactionInsights/transactionInsightsView.tsx @@ -211,7 +211,7 @@ export const TransactionInsightsView: React.FC = (
InsightsError()} @@ -235,7 +235,7 @@ export const TransactionInsightsView: React.FC = ( renderNoResult={ 0 && filteredTransactions?.length == 0 + search?.length > 0 && filteredTransactions?.length === 0 } /> }