diff --git a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx
index d231ed4ecd80..35cb7139c02c 100644
--- a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx
+++ b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx
@@ -635,20 +635,18 @@ export class StatementDetails extends React.Component<
{!isTenant && (
- <>
- (
- nodes.map(n => ),
- ", ",
- )}
- />
- (regions, ", ")}
- />
- >
+ (
+ nodes.map(n => ),
+ ", ",
+ )}
+ />
)}
+ (regions, ", ")}
+ />
{
isLoading: isLoading,
statementsError: lastError,
timeScale: selectTimeScale(state),
+ // TODO(todd): Remove this unused property!
nodeNames: selectIsTenant(state) ? {} : nodeDisplayNameByIDSelector(state),
- nodeRegions: selectIsTenant(state) ? {} : nodeRegionsByIDSelector(state),
+ nodeRegions: nodeRegionsByIDSelector(state),
diagnosticsReports:
selectIsTenant(state) || selectHasViewActivityRedactedRole(state)
? []
diff --git a/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPage.tsx b/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPage.tsx
index 106dfaab1f48..33cce77060ad 100644
--- a/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPage.tsx
+++ b/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPage.tsx
@@ -525,10 +525,7 @@ export class StatementsPage extends React.Component<
.filter(
// The statement must contain at least one value from the selected regions
// list if the list is not empty.
- // If the cluster is a tenant cluster we don't care
- // about regions.
statement =>
- isTenant ||
regions.length == 0 ||
(statement.stats.nodes &&
containAny(
@@ -578,7 +575,7 @@ export class StatementsPage extends React.Component<
const isEmptySearchResults = statements?.length > 0 && search?.length > 0;
// If the cluster is a tenant cluster we don't show info
// about nodes/regions.
- populateRegionNodeForStatements(statements, nodeRegions, isTenant);
+ populateRegionNodeForStatements(statements, nodeRegions);
// Creates a list of all possible columns,
// hiding nodeRegions if is not multi-region and
@@ -595,6 +592,7 @@ export class StatementsPage extends React.Component<
onSelectDiagnosticsReportDropdownOption,
onStatementClick,
)
+ .filter(c => !(c.name === "regions" && regions.length < 2))
.filter(c => !(c.name === "regionNodes" && regions.length < 2))
.filter(c => !(isTenant && c.hideIfTenant));
@@ -673,14 +671,14 @@ export class StatementsPage extends React.Component<
nodeRegions,
} = this.props;
- const nodes = isTenant
- ? []
- : Object.keys(nodeRegions)
- .map(n => Number(n))
- .sort();
- const regions = isTenant
- ? []
- : unique(nodes.map(node => nodeRegions[node.toString()])).sort();
+ const nodes = Object.keys(nodeRegions)
+ .map(n => Number(n))
+ .sort();
+
+ const regions = unique(
+ nodes.map(node => nodeRegions[node.toString()]),
+ ).sort();
+
const { filters, activeFilters } = this.state;
const longLoadingMessage = isNil(this.props.statements) &&
@@ -716,7 +714,7 @@ export class StatementsPage extends React.Component<
showSqlType={true}
showScan={true}
showRegions={regions.length > 1}
- showNodes={nodes.length > 1}
+ showNodes={!isTenant && nodes.length > 1}
/>
diff --git a/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPageConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPageConnected.tsx
index 45c5a377f70b..23fc03ecfc96 100644
--- a/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPageConnected.tsx
+++ b/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPageConnected.tsx
@@ -88,9 +88,7 @@ export const ConnectedStatementsPage = withRouter(
isTenant: selectIsTenant(state),
hasViewActivityRedactedRole: selectHasViewActivityRedactedRole(state),
lastReset: selectLastReset(state),
- nodeRegions: selectIsTenant(state)
- ? {}
- : nodeRegionsByIDSelector(state),
+ nodeRegions: nodeRegionsByIDSelector(state),
search: selectSearch(state),
sortSetting: selectSortSetting(state),
statements: selectStatements(state, props),
diff --git a/pkg/ui/workspaces/cluster-ui/src/statementsTable/statementsTable.tsx b/pkg/ui/workspaces/cluster-ui/src/statementsTable/statementsTable.tsx
index df1d33fb07f3..c8f440c8b41d 100644
--- a/pkg/ui/workspaces/cluster-ui/src/statementsTable/statementsTable.tsx
+++ b/pkg/ui/workspaces/cluster-ui/src/statementsTable/statementsTable.tsx
@@ -72,6 +72,7 @@ export interface AggregateStatistics {
diagnosticsReports?: StatementDiagnosticsReport[];
// totalWorkload is the sum of service latency of all statements listed on the table.
totalWorkload?: Long;
+ regions?: string[];
regionNodes?: string[];
}
@@ -250,16 +251,7 @@ export function makeStatementsColumns(
(stmt.stats.service_lat.mean * longToInt(stmt.stats.count)) /
totalWorkload,
},
- {
- name: "regionNodes",
- title: statisticsTableTitles.regionNodes(statType),
- className: cx("statements-table__col-regions"),
- cell: (stmt: AggregateStatistics) => {
- return longListWithTooltip(stmt.regionNodes.sort().join(", "), 50);
- },
- sort: (stmt: AggregateStatistics) => stmt.regionNodes.sort().join(", "),
- hideIfTenant: true,
- },
+ makeRegionsColumn(statType, isTenant),
{
name: "lastExecTimestamp",
title: statisticsTableTitles.lastExecTimestamp(statType),
@@ -302,6 +294,33 @@ export function makeStatementsColumns(
return columns;
}
+function makeRegionsColumn(
+ statType: StatisticType,
+ isTenant: boolean,
+): ColumnDescriptor {
+ if (isTenant) {
+ return {
+ name: "regions",
+ title: statisticsTableTitles.regions(statType),
+ className: cx("statements-table__col-regions"),
+ cell: (stmt: AggregateStatistics) => {
+ return longListWithTooltip(stmt.regions.sort().join(", "), 50);
+ },
+ sort: (stmt: AggregateStatistics) => stmt.regions.sort().join(", "),
+ };
+ } else {
+ return {
+ name: "regionNodes",
+ title: statisticsTableTitles.regionNodes(statType),
+ className: cx("statements-table__col-regions"),
+ cell: (stmt: AggregateStatistics) => {
+ return longListWithTooltip(stmt.regionNodes.sort().join(", "), 50);
+ },
+ sort: (stmt: AggregateStatistics) => stmt.regionNodes.sort().join(", "),
+ };
+ }
+}
+
/**
* For each statement, generate the list of regions and nodes it was
* executed on. Each node is assigned to only one region and a region can
@@ -311,19 +330,12 @@ export function makeStatementsColumns(
* node it was executed on.
* @param nodeRegions: object with keys being the node id and the value
* which region it belongs to.
- * @param isTenant: boolean indicating if the cluster is tenant, since
- * node information doesn't need to be populated on this case.
*/
export function populateRegionNodeForStatements(
statements: AggregateStatistics[],
nodeRegions: { [p: string]: string },
- isTenant: boolean,
): void {
statements.forEach(stmt => {
- if (isTenant) {
- stmt.regionNodes = [];
- return;
- }
const regions: { [region: string]: Set } = {};
// For each region, populate a list of all nodes where the statement was executed.
// E.g. {"gcp-us-east1" : [1,3,4]}
@@ -350,6 +362,7 @@ export function populateRegionNodeForStatements(
")",
);
});
+ stmt.regions = Object.keys(regions).sort();
stmt.regionNodes = regionNodes;
});
}
diff --git a/pkg/ui/workspaces/cluster-ui/src/statsTableUtil/statsTableUtil.tsx b/pkg/ui/workspaces/cluster-ui/src/statsTableUtil/statsTableUtil.tsx
index a6f162dd529f..ba3e747c7cc5 100644
--- a/pkg/ui/workspaces/cluster-ui/src/statsTableUtil/statsTableUtil.tsx
+++ b/pkg/ui/workspaces/cluster-ui/src/statsTableUtil/statsTableUtil.tsx
@@ -51,6 +51,7 @@ export const statisticsColumnLabels = {
executionCount: "Execution Count",
maxMemUsage: "Max Memory",
networkBytes: "Network",
+ regions: "Regions",
regionNodes: "Regions/Nodes",
retries: "Retries",
rowsProcessed: "Rows Processed",
@@ -782,6 +783,27 @@ export const statisticsTableTitles: StatisticTableTitleType = {
);
},
+ regions: (statType: StatisticType) => {
+ let contentModifier = "";
+ switch (statType) {
+ case "transaction":
+ contentModifier = contentModifiers.transaction;
+ break;
+ case "statement":
+ contentModifier = contentModifiers.statement;
+ break;
+ }
+
+ return (
+ Regions in which the {contentModifier} was executed.}
+ >
+ {getLabel("regions")}
+
+ );
+ },
regionNodes: (statType: StatisticType) => {
let contentModifier = "";
switch (statType) {
diff --git a/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx
index 660655a169b1..a6e5c747be6b 100644
--- a/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx
+++ b/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx
@@ -319,11 +319,7 @@ export class TransactionDetails extends React.Component<
const aggregatedStatements = aggregateStatements(
statementsForTransaction,
);
- populateRegionNodeForStatements(
- aggregatedStatements,
- nodeRegions,
- isTenant,
- );
+ populateRegionNodeForStatements(aggregatedStatements, nodeRegions);
const duration = (v: number) => Duration(v * 1e9);
const transactionSampled =
diff --git a/pkg/ui/workspaces/cluster-ui/src/transactionsPage/transactionsPage.tsx b/pkg/ui/workspaces/cluster-ui/src/transactionsPage/transactionsPage.tsx
index 58812518f1e3..05e8fb93939c 100644
--- a/pkg/ui/workspaces/cluster-ui/src/transactionsPage/transactionsPage.tsx
+++ b/pkg/ui/workspaces/cluster-ui/src/transactionsPage/transactionsPage.tsx
@@ -29,6 +29,7 @@ import { TableStatistics } from "../tableStatistics";
import { statisticsClasses } from "./transactionsPageClasses";
import {
aggregateAcrossNodeIDs,
+ generateRegion,
generateRegionNode,
getTrxAppFilterOptions,
searchTransactionsData,
@@ -409,14 +410,14 @@ export class TransactionsPage extends React.Component<
// If the cluster is a tenant cluster we don't show info
// about nodes/regions.
- const nodes = isTenant
- ? []
- : Object.keys(nodeRegions)
- .map(n => Number(n))
- .sort();
- const regions = isTenant
- ? []
- : unique(nodes.map(node => nodeRegions[node.toString()])).sort();
+ const nodes = Object.keys(nodeRegions)
+ .map(n => Number(n))
+ .sort();
+
+ const regions = unique(
+ nodes.map(node => nodeRegions[node.toString()]),
+ ).sort();
+
// We apply the search filters and app name filters prior to aggregating across Node IDs
// in order to match what's done on the Statements Page.
//
@@ -466,7 +467,7 @@ export class TransactionsPage extends React.Component<
activeFilters={activeFilters}
filters={filters}
showRegions={regions.length > 1}
- showNodes={nodes.length > 1}
+ showNodes={!isTenant && nodes.length > 1}
/>
@@ -495,9 +496,8 @@ export class TransactionsPage extends React.Component<
t => ({
stats_data: t.stats_data,
node_id: t.node_id,
- regionNodes: isTenant
- ? []
- : generateRegionNode(t, statements, nodeRegions),
+ regions: generateRegion(t, statements, nodeRegions),
+ regionNodes: generateRegionNode(t, statements, nodeRegions),
}),
);
const { current, pageSize } = pagination;
@@ -513,6 +513,7 @@ export class TransactionsPage extends React.Component<
isTenant,
search,
)
+ .filter(c => !(c.name === "regions" && regions.length < 2))
.filter(c => !(c.name === "regionNodes" && regions.length < 2))
.filter(c => !(isTenant && c.hideIfTenant));
diff --git a/pkg/ui/workspaces/cluster-ui/src/transactionsPage/utils.ts b/pkg/ui/workspaces/cluster-ui/src/transactionsPage/utils.ts
index 2278c235e04c..1bd1e5363485 100644
--- a/pkg/ui/workspaces/cluster-ui/src/transactionsPage/utils.ts
+++ b/pkg/ui/workspaces/cluster-ui/src/transactionsPage/utils.ts
@@ -215,10 +215,9 @@ export const filterTransactions = (
// and regions list (if the list is not empty).
if (regions.length == 0 && nodes.length == 0) return true;
// If the cluster is a tenant cluster we don't care
- // about node/regions.
- if (isTenant) return true;
+ // about nodes.
let foundRegion: boolean = regions.length == 0;
- let foundNode: boolean = nodes.length == 0;
+ let foundNode: boolean = isTenant || nodes.length == 0;
getStatementsByFingerprintId(
t.stats_data.statement_fingerprint_ids,
@@ -245,6 +244,38 @@ export const filterTransactions = (
};
};
+/**
+ * For each transaction, generate the list of regions all
+ * its statements were executed on.
+ * E.g. of one element of the list: `gcp-us-east1`
+ * @param transaction: list of transactions.
+ * @param statements: list of all statements collected.
+ * @param nodeRegions: object with keys being the node id and the value
+ * which region it belongs to.
+ */
+export const generateRegion = (
+ transaction: Transaction,
+ statements: Statement[],
+ nodeRegions: { [p: string]: string },
+): string[] => {
+ const regions: Set = new Set();
+ // Get the list of statements that were executed on the transaction. Combine all
+ // nodes and regions of all the statements to a single list of `region: nodes`
+ // for the transaction.
+ // E.g. {"gcp-us-east1" : [1,3,4]}
+ getStatementsByFingerprintId(
+ transaction.stats_data.statement_fingerprint_ids,
+ statements,
+ ).forEach(stmt => {
+ stmt.stats.nodes &&
+ stmt.stats.nodes.forEach(n => {
+ regions.add(nodeRegions[n.toString()]);
+ });
+ });
+
+ return Array.from(regions).sort();
+};
+
/**
* For each transaction, generate the list of regions and nodes all
* its statements were executed on.
diff --git a/pkg/ui/workspaces/cluster-ui/src/transactionsTable/transactionsTable.tsx b/pkg/ui/workspaces/cluster-ui/src/transactionsTable/transactionsTable.tsx
index 0c3e28e8d951..8053e956a25e 100644
--- a/pkg/ui/workspaces/cluster-ui/src/transactionsTable/transactionsTable.tsx
+++ b/pkg/ui/workspaces/cluster-ui/src/transactionsTable/transactionsTable.tsx
@@ -61,6 +61,7 @@ interface TransactionsTable {
}
export interface TransactionInfo extends Transaction {
+ regions: string[];
regionNodes: string[];
}
@@ -228,16 +229,7 @@ export function makeTransactionsColumns(
sort: (item: TransactionInfo) =>
longToInt(Number(item.stats_data.stats.max_retries)),
},
- {
- name: "regionNodes",
- title: statisticsTableTitles.regionNodes(statType),
- className: cx("statements-table__col-regions"),
- cell: (item: TransactionInfo) => {
- return longListWithTooltip(item.regionNodes.sort().join(", "), 50);
- },
- sort: (item: TransactionInfo) => item.regionNodes.sort().join(", "),
- hideIfTenant: true,
- },
+ makeRegionsColumn(isTenant),
{
name: "statementsCount",
title: statisticsTableTitles.statementsCount(statType),
@@ -257,7 +249,33 @@ export function makeTransactionsColumns(
item.stats_data?.transaction_fingerprint_id.toString(16),
showByDefault: false,
},
- ].filter(c => !(isTenant && c.hideIfTenant));
+ ];
+}
+
+function makeRegionsColumn(
+ isTenant: boolean,
+): ColumnDescriptor {
+ if (isTenant) {
+ return {
+ name: "regions",
+ title: statisticsTableTitles.regions("transaction"),
+ className: cx("statements-table__col-regions"),
+ cell: (item: TransactionInfo) => {
+ return longListWithTooltip(item.regions.sort().join(", "), 50);
+ },
+ sort: (item: TransactionInfo) => item.regions.sort().join(", "),
+ };
+ } else {
+ return {
+ name: "regionNodes",
+ title: statisticsTableTitles.regionNodes("transaction"),
+ className: cx("statements-table__col-regions"),
+ cell: (item: TransactionInfo) => {
+ return longListWithTooltip(item.regionNodes.sort().join(", "), 50);
+ },
+ sort: (item: TransactionInfo) => item.regionNodes.sort().join(", "),
+ };
+ }
}
export const TransactionsTable: React.FC = props => {