Skip to content

Commit 4dd6f9e

Browse files
craig[bot]jasonlmfong
andcommitted
Merge #153617
153617: ui: add isolation level information to SQL activity pages r=jasonlmfong a=jasonlmfong Introduce a column for 'Isolation Level' to the active stmts/txns details pages, as well as the sessions page. The change is achieved by augmenting the query to `crdb_internal.cluster_locks` table via the SQL api in `/api/v2/`. closes: [https://github.com/cockroachdb/cockroach/issues/152688](https://github.com/cockroachdb/cockroach/issues/152688) Epic: None Release note (ui change): A new section, 'Isolation Level' has been added to the active statement and transaction details page and session page. Co-authored-by: Jason Fong <[email protected]>
2 parents d94e6a6 + cbd5cf9 commit 4dd6f9e

File tree

14 files changed

+70
-6
lines changed

14 files changed

+70
-6
lines changed

docs/generated/http/full.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,6 +2342,7 @@ ActiveQuery represents a query in flight on some Session.
23422342
| plan_gist | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | | The compressed plan that can be converted back into the statement's logical plan. Empty if the statement is in the PREPARING state. | [reserved](#support-status) |
23432343
| placeholders | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | repeated | The placeholders if any. | [reserved](#support-status) |
23442344
| database | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | | The database the statement was executed on. | [reserved](#support-status) |
2345+
| isolation_level | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | | The isolation level the query was run in. | [reserved](#support-status) |
23452346

23462347

23472348

@@ -2493,6 +2494,7 @@ ActiveQuery represents a query in flight on some Session.
24932494
| plan_gist | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | | The compressed plan that can be converted back into the statement's logical plan. Empty if the statement is in the PREPARING state. | [reserved](#support-status) |
24942495
| placeholders | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | repeated | The placeholders if any. | [reserved](#support-status) |
24952496
| database | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | | The database the statement was executed on. | [reserved](#support-status) |
2497+
| isolation_level | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | | The isolation level the query was run in. | [reserved](#support-status) |
24962498

24972499

24982500

docs/tech-notes/observability/sql_stats.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ cleanup jobs run (see [Data Cleanup](#data-cleanup) below).
7979
## Data Aggregation and Cardinality
8080
When the statement is being recorded in memory, it gets aggregated with other
8181
executions of the same fingerprint, and when the flush happens it gets aggregated with
82-
all other executions for thar fingerprint on the current aggregation timestamp, which is
82+
all other executions for that fingerprint on the current aggregation timestamp, which is
8383
defined by `sql.stats.aggregation.interval` (default 1h). This mean everything executed
8484
on hour 1:XX will be stored as hour 1:00.
8585

pkg/server/serverpb/status.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,9 @@ message ActiveQuery {
10221022

10231023
// The database the statement was executed on.
10241024
string database = 14;
1025+
1026+
// The isolation level the query was run in.
1027+
string isolation_level = 15;
10251028
}
10261029

10271030
// Request object for ListSessions and ListLocalSessions.

pkg/sql/conn_executor.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4450,6 +4450,7 @@ func (ex *connExecutor) serialize() serverpb.Session {
44504450
IsFullScan: query.isFullScan,
44514451
PlanGist: query.planGist,
44524452
Database: query.database,
4453+
IsolationLevel: activeTxnInfo.IsolationLevel,
44534454
})
44544455
}
44554456
lastActiveQuery := ""

pkg/ui/workspaces/cluster-ui/src/activeExecutions/activeStatementUtils.spec.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ const defaultActiveStatement: ActiveStatement = {
5656
user: "user",
5757
clientAddress: "clientAddress",
5858
isFullScan: false,
59+
isolationLevel: "SERIALIZABLE",
5960
};
6061

6162
// makeActiveStatement creates an ActiveStatement object with the default active statement above
@@ -181,22 +182,26 @@ describe("test activeStatementUtils", () => {
181182
});
182183

183184
describe("getActiveExecutionsFromSessions", () => {
184-
it("should convert sessions response to active statements result", () => {
185+
it("should convert sessions response to active statements result with isolation levels", () => {
185186
const sessionsResponse: SessionsResponse = {
186187
sessions: [
187188
{
188189
id: new Uint8Array(),
189190
username: "bar",
190191
application_name: "application",
191192
client_address: "clientAddress",
192-
active_queries: [makeActiveQuery({ id: "1" })],
193+
active_queries: [
194+
makeActiveQuery({ id: "1", isolation_level: "SERIALIZABLE" }),
195+
],
193196
},
194197
{
195198
id: new Uint8Array(),
196199
username: "foo",
197200
application_name: "application2",
198201
client_address: "clientAddress2",
199-
active_queries: [makeActiveQuery({ id: "2" })],
202+
active_queries: [
203+
makeActiveQuery({ id: "2", isolation_level: "READ COMMITTED" }),
204+
],
200205
},
201206
{
202207
id: new Uint8Array(),
@@ -221,13 +226,14 @@ describe("test activeStatementUtils", () => {
221226
if (stmt.user === "bar") {
222227
expect(stmt.application).toBe("application");
223228
expect(stmt.clientAddress).toBe("clientAddress");
229+
expect(stmt.isolationLevel).toBe("SERIALIZABLE");
224230
} else if (stmt.user === "foo") {
225231
expect(stmt.application).toBe("application2");
226232
expect(stmt.clientAddress).toBe("clientAddress2");
233+
expect(stmt.isolationLevel).toBe("READ COMMITTED");
227234
} else {
228235
fail(`stmt user should be foo or bar, got ${stmt.user}`);
229236
}
230-
// expect(stmt.transactionID).toBe(defaultActiveStatement.transactionID);
231237
expect(stmt.status).toBe(ExecutionStatus.Executing);
232238
expect(stmt.start.unix()).toBe(
233239
TimestampToMoment(defaultActiveQuery.start).unix(),
@@ -252,6 +258,7 @@ describe("test activeStatementUtils", () => {
252258
}),
253259
num_auto_retries: 3,
254260
num_statements_executed: 4,
261+
isolation_level: "SERIALIZABLE",
255262
},
256263
},
257264
{
@@ -267,6 +274,7 @@ describe("test activeStatementUtils", () => {
267274
}),
268275
num_auto_retries: 4,
269276
num_statements_executed: 3,
277+
isolation_level: "READ COMMITTED",
270278
},
271279
},
272280
{
@@ -328,6 +336,11 @@ describe("test activeStatementUtils", () => {
328336
expect(txn.start.unix()).toBe(
329337
TimestampToMoment(defaultActiveQuery.start).unix(),
330338
);
339+
if (txn.application === "application") {
340+
expect(txn.isolationLevel).toBe("SERIALIZABLE");
341+
} else if (txn.application === "application2") {
342+
expect(txn.isolationLevel).toBe("READ COMMITTED");
343+
}
331344
});
332345

333346
expect(executingCnt).toEqual(2);

pkg/ui/workspaces/cluster-ui/src/activeExecutions/activeStatementUtils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ export function getActiveExecutionsFromSessions(
132132
clientAddress: session.client_address,
133133
isFullScan: query.is_full_scan || false, // Or here is for conversion in case the field is null.
134134
planGist: query.plan_gist,
135+
isolationLevel: query.isolation_level,
135136
};
136137

137138
statements.push(activeStmt);
@@ -158,6 +159,7 @@ export function getActiveExecutionsFromSessions(
158159
statementCount: activeTxn.num_statements_executed,
159160
lastAutoRetryReason: activeTxn.last_auto_retry_reason,
160161
priority: activeTxn.priority,
162+
isolationLevel: activeTxn.isolation_level,
161163
});
162164
});
163165

pkg/ui/workspaces/cluster-ui/src/activeExecutions/activeStatementsTable/activeStatementsTable.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export function makeActiveStatementsColumns(
3939
activeStatementColumnsFromCommon.startTime,
4040
activeStatementColumnsFromCommon.elapsedTime,
4141
!isTenant ? activeStatementColumnsFromCommon.timeSpentWaiting : null,
42+
activeStatementColumnsFromCommon.isolationLevel,
4243
activeStatementColumnsFromCommon.applicationName,
4344
].filter(col => col != null);
4445
}

pkg/ui/workspaces/cluster-ui/src/activeExecutions/activeTransactionsTable/activeTransactionsTable.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export function makeActiveTransactionsColumns(
5959
cell: (item: ActiveTransaction) => item.retries,
6060
sort: (item: ActiveTransaction) => item.retries,
6161
},
62+
activeTransactionColumnsFromCommon.isolationLevel,
6263
activeTransactionColumnsFromCommon.applicationName,
6364
].filter(col => col != null);
6465
}

pkg/ui/workspaces/cluster-ui/src/activeExecutions/execTableCommon.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ export type ExecutionsColumn =
2626
| "statementCount"
2727
| "status"
2828
| "timeSpentBlocking"
29-
| "timeSpentWaiting";
29+
| "timeSpentWaiting"
30+
| "isolationLevel";
3031

3132
export const executionsColumnLabels: Record<
3233
ExecutionsColumn,
@@ -55,6 +56,7 @@ export const executionsColumnLabels: Record<
5556
status: () => "Status",
5657
timeSpentBlocking: () => "Time Spent Blocking",
5758
timeSpentWaiting: () => "Time Spent Waiting",
59+
isolationLevel: () => "Isolation Level",
5860
};
5961

6062
export type ExecutionsTableColumnKeys = keyof typeof executionsColumnLabels;
@@ -148,6 +150,15 @@ export const executionsTableTitles: ExecutionsTableTitleType = {
148150
{getLabel("timeSpentWaiting")}
149151
</Tooltip>
150152
),
153+
isolationLevel: () => (
154+
<Tooltip
155+
placement="bottom"
156+
style="tableTitle"
157+
content={<p>Isolation level of this transaction.</p>}
158+
>
159+
{getLabel("isolationLevel")}
160+
</Tooltip>
161+
),
151162
};
152163

153164
function getID(item: ActiveExecution, execType: ExecutionType) {
@@ -215,6 +226,12 @@ function makeActiveExecutionColumns(
215226
cell: (item: ActiveExecution) => item.application,
216227
sort: (item: ActiveExecution) => item.application,
217228
},
229+
isolationLevel: {
230+
name: "isolationLevel",
231+
title: executionsTableTitles.isolationLevel(execType),
232+
cell: (item: ActiveExecution) => item.isolationLevel,
233+
sort: (item: ActiveExecution) => item.isolationLevel,
234+
},
218235
};
219236
}
220237

pkg/ui/workspaces/cluster-ui/src/activeExecutions/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export interface ActiveExecution {
3737
database?: string;
3838
query?: string; // For transactions, this is the latest query executed.
3939
timeSpentWaiting?: moment.Duration;
40+
isolationLevel?: string;
4041
}
4142

4243
export type ActiveStatement = ActiveExecution &

0 commit comments

Comments
 (0)