Skip to content

Commit cbd5cf9

Browse files
committed
ui: add isolation level information to active statements/transactions/sessions
This change introduces 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: [#152688](#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.
1 parent 3833756 commit cbd5cf9

File tree

13 files changed

+69
-5
lines changed

13 files changed

+69
-5
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

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
@@ -4467,6 +4467,7 @@ func (ex *connExecutor) serialize() serverpb.Session {
44674467
IsFullScan: query.isFullScan,
44684468
PlanGist: query.planGist,
44694469
Database: query.database,
4470+
IsolationLevel: activeTxnInfo.IsolationLevel,
44704471
})
44714472
}
44724473
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 &

pkg/ui/workspaces/cluster-ui/src/sessions/sessionsPage.fixture.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export const idleTransactionSession: SessionInfo = {
8484
implicit: false,
8585
num_retries: 5,
8686
num_auto_retries: 3,
87+
isolation_level: "SERIALIZABLE",
8788
},
8889
last_active_query_no_constants: "SHOW database",
8990
active_queries: [],
@@ -113,6 +114,7 @@ export const activeSession: SessionInfo = {
113114
phase: Phase.EXECUTING,
114115
txn_id: toUuid("e8NTvpOvScO1tSMreygtcg=="),
115116
sql_no_constants: "SELECT pg_sleep(_)",
117+
isolation_level: "SERIALIZABLE",
116118
},
117119
],
118120
start: {
@@ -141,6 +143,7 @@ export const activeSession: SessionInfo = {
141143
implicit: true,
142144
num_retries: 5,
143145
num_auto_retries: 3,
146+
isolation_level: "SERIALIZABLE",
144147
},
145148
last_active_query_no_constants: "SHOW database",
146149
status: Status.ACTIVE,

0 commit comments

Comments
 (0)