This is an automated email from the ASF dual-hosted git repository.
abhishek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new dba0246aca7 Added UI support for waitTillSegmentsLoad (#15110)
dba0246aca7 is described below
commit dba0246aca7cabbff3a5f8819467847834040077
Author: Sébastien <[email protected]>
AuthorDate: Wed Oct 11 06:48:42 2023 -0400
Added UI support for waitTillSegmentsLoad (#15110)
This relies on the work done in #14322 and #15076. It allows the user to
set waitTillSegmentsLoad in the query context (if they want, else it defaults
to true) and shows the results in the UI :
---
.../src/druid-models/execution/execution.spec.ts | 3 ++
.../src/druid-models/execution/execution.ts | 50 ++++++++++++++++++++++
.../druid-models/query-context/query-context.tsx | 16 +++++++
.../workbench-query/workbench-query.spec.ts | 1 +
.../workbench-query/workbench-query.ts | 1 +
.../src/helpers/execution/sql-task-execution.ts | 13 +++++-
.../execution-details-pane.spec.tsx.snap | 5 +++
.../execution-details-pane.tsx | 30 ++++++++++++-
.../execution-progress-bar-pane.spec.tsx.snap | 3 ++
.../execution-progress-bar-pane.tsx | 4 ++
.../ingest-success-pane.spec.tsx.snap | 1 +
.../ingest-success-pane/ingest-success-pane.tsx | 6 ++-
.../views/workbench-view/run-panel/run-panel.tsx | 12 ++++++
13 files changed, 141 insertions(+), 4 deletions(-)
diff --git a/web-console/src/druid-models/execution/execution.spec.ts
b/web-console/src/druid-models/execution/execution.spec.ts
index a6b55db6808..fac129baf9b 100644
--- a/web-console/src/druid-models/execution/execution.spec.ts
+++ b/web-console/src/druid-models/execution/execution.spec.ts
@@ -268,6 +268,7 @@ describe('Execution', () => {
"maxNumTasks": 2,
},
"result": undefined,
+ "segmentStatus": undefined,
"sqlQuery": "REPLACE INTO \\"kttm_simple\\" OVERWRITE ALL
SELECT
TIME_PARSE(\\"timestamp\\") AS \\"__time\\",
@@ -643,6 +644,7 @@ describe('Execution', () => {
"sqlQuery": undefined,
"sqlQueryId": undefined,
},
+ "segmentStatus": undefined,
"sqlQuery": undefined,
"stages": undefined,
"startTime": 2023-07-05T21:33:19.147Z,
@@ -679,6 +681,7 @@ describe('Execution', () => {
"nativeQuery": undefined,
"queryContext": undefined,
"result": undefined,
+ "segmentStatus": undefined,
"sqlQuery": undefined,
"stages": undefined,
"startTime": 2023-07-05T21:40:39.986Z,
diff --git a/web-console/src/druid-models/execution/execution.ts
b/web-console/src/druid-models/execution/execution.ts
index 8f30711b283..1899f126072 100644
--- a/web-console/src/druid-models/execution/execution.ts
+++ b/web-console/src/druid-models/execution/execution.ts
@@ -164,6 +164,18 @@ function formatPendingMessage(
}
}
+interface SegmentStatus {
+ duration: number;
+ onDemandSegments: number;
+ pendingSegments: number;
+ precachedSegments: number;
+ startTime: Date;
+ state: 'INIT' | 'WAITING' | 'SUCCESS';
+ totalSegments: number;
+ unknownSegments: number;
+ usedSegments: number;
+}
+
export interface ExecutionValue {
engine: DruidEngine;
id: string;
@@ -182,6 +194,7 @@ export interface ExecutionValue {
warnings?: ExecutionError[];
capacityInfo?: CapacityInfo;
_payload?: MsqTaskPayloadResponse;
+ segmentStatus?: SegmentStatus;
}
export class Execution {
@@ -292,6 +305,11 @@ export class Execution {
const startTime = new Date(deepGet(taskReport,
'multiStageQuery.payload.status.startTime'));
const durationMs = deepGet(taskReport,
'multiStageQuery.payload.status.durationMs');
+ const segmentLoaderStatus = deepGet(
+ taskReport,
+ 'multiStageQuery.payload.status.segmentLoadWaiterStatus',
+ );
+
let result: QueryResult | undefined;
const resultsPayload: {
signature: { name: string; type: string }[];
@@ -313,6 +331,7 @@ export class Execution {
engine: 'sql-msq-task',
id,
status: Execution.normalizeTaskStatus(status),
+ segmentStatus: segmentLoaderStatus,
startTime: isNaN(startTime.getTime()) ? undefined : startTime,
duration: typeof durationMs === 'number' ? durationMs : undefined,
usageInfo: getUsageInfoFromStatusPayload(
@@ -369,6 +388,7 @@ export class Execution {
public readonly error?: ExecutionError;
public readonly warnings?: ExecutionError[];
public readonly capacityInfo?: CapacityInfo;
+ public readonly segmentStatus?: SegmentStatus;
public readonly _payload?: { payload: any; task: string };
@@ -390,6 +410,7 @@ export class Execution {
this.error = value.error;
this.warnings = nonEmptyArray(value.warnings) ? value.warnings : undefined;
this.capacityInfo = value.capacityInfo;
+ this.segmentStatus = value.segmentStatus;
this._payload = value._payload;
}
@@ -412,6 +433,7 @@ export class Execution {
error: this.error,
warnings: this.warnings,
capacityInfo: this.capacityInfo,
+ segmentStatus: this.segmentStatus,
_payload: this._payload,
};
@@ -526,6 +548,34 @@ export class Execution {
return status !== 'SUCCESS' && status !== 'FAILED';
}
+ public getSegmentStatusDescription() {
+ const { segmentStatus } = this;
+
+ let label = '';
+
+ switch (segmentStatus?.state) {
+ case 'INIT':
+ label = 'Waiting for segments loading to start...';
+ break;
+
+ case 'WAITING':
+ label = 'Waiting for segments loading to complete...';
+ break;
+
+ case 'SUCCESS':
+ label = 'Segments loaded successfully in ' + segmentStatus.duration +
'ms.';
+ break;
+
+ default:
+ break;
+ }
+
+ return {
+ label,
+ ...segmentStatus,
+ };
+ }
+
public isFullyComplete(): boolean {
if (this.isWaitingForQuery()) return false;
diff --git a/web-console/src/druid-models/query-context/query-context.tsx
b/web-console/src/druid-models/query-context/query-context.tsx
index d09fa73868e..cdaf8dd84e3 100644
--- a/web-console/src/druid-models/query-context/query-context.tsx
+++ b/web-console/src/druid-models/query-context/query-context.tsx
@@ -162,6 +162,22 @@ export function changeFinalizeAggregations(
: deepDelete(context, 'finalizeAggregations');
}
+// waitTillSegmentsLoad
+
+export function getWaitTillSegmentsLoad(context: QueryContext): boolean |
undefined {
+ const { waitTillSegmentsLoad } = context;
+ return typeof waitTillSegmentsLoad === 'boolean' ? waitTillSegmentsLoad :
undefined;
+}
+
+export function changeWaitTillSegmentsLoad(
+ context: QueryContext,
+ waitTillSegmentsLoad: boolean | undefined,
+): QueryContext {
+ return typeof waitTillSegmentsLoad === 'boolean'
+ ? deepSet(context, 'waitTillSegmentsLoad', waitTillSegmentsLoad)
+ : deepDelete(context, 'waitTillSegmentsLoad');
+}
+
// groupByEnableMultiValueUnnesting
export function getGroupByEnableMultiValueUnnesting(context: QueryContext):
boolean | undefined {
diff --git
a/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
b/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
index 8732b93d424..079ccde5a2d 100644
--- a/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
+++ b/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
@@ -423,6 +423,7 @@ describe('WorkbenchQuery', () => {
finalizeAggregations: false,
groupByEnableMultiValueUnnesting: false,
useCache: false,
+ waitTillSegmentsLoad: true,
},
header: true,
query: 'INSERT INTO wiki2 SELECT * FROM wikipedia',
diff --git a/web-console/src/druid-models/workbench-query/workbench-query.ts
b/web-console/src/druid-models/workbench-query/workbench-query.ts
index d7847287fa6..43fe3ea6528 100644
--- a/web-console/src/druid-models/workbench-query/workbench-query.ts
+++ b/web-console/src/druid-models/workbench-query/workbench-query.ts
@@ -552,6 +552,7 @@ export class WorkbenchQuery {
apiQuery.context.executionMode ??= 'async';
apiQuery.context.finalizeAggregations ??= !ingestQuery;
apiQuery.context.groupByEnableMultiValueUnnesting ??= !ingestQuery;
+ apiQuery.context.waitTillSegmentsLoad ??= true;
}
if (Array.isArray(queryParameters) && queryParameters.length) {
diff --git a/web-console/src/helpers/execution/sql-task-execution.ts
b/web-console/src/helpers/execution/sql-task-execution.ts
index d41370df16c..75b82d17b86 100644
--- a/web-console/src/helpers/execution/sql-task-execution.ts
+++ b/web-console/src/helpers/execution/sql-task-execution.ts
@@ -57,7 +57,13 @@ export interface SubmitTaskQueryOptions {
export async function submitTaskQuery(
options: SubmitTaskQueryOptions,
): Promise<Execution | IntermediateQueryState<Execution>> {
- const { query, context, prefixLines, cancelToken, preserveOnTermination,
onSubmitted } = options;
+ const { query, prefixLines, cancelToken, preserveOnTermination, onSubmitted
} = options;
+
+ // setting waitTillSegmentsLoad to true by default
+ const context = {
+ waitTillSegmentsLoad: true,
+ ...(options.context || {}),
+ };
let sqlQuery: string;
let jsonQuery: Record<string, any>;
@@ -261,6 +267,11 @@ export async function
updateExecutionWithDatasourceLoadedIfNeeded(
return execution;
}
+ // This means we don't have to perform the SQL query to check if the
segments are loaded
+ if (execution.queryContext?.waitTillSegmentsLoad === true) {
+ return execution.markDestinationDatasourceLoaded();
+ }
+
const endTime = execution.getEndTime();
if (
!endTime || // If endTime is not set (this is not expected to happen) then
just bow out
diff --git
a/web-console/src/views/workbench-view/execution-details-pane/__snapshots__/execution-details-pane.spec.tsx.snap
b/web-console/src/views/workbench-view/execution-details-pane/__snapshots__/execution-details-pane.spec.tsx.snap
index 6f3c23bee00..df9acdfb2cc 100644
---
a/web-console/src/views/workbench-view/execution-details-pane/__snapshots__/execution-details-pane.spec.tsx.snap
+++
b/web-console/src/views/workbench-view/execution-details-pane/__snapshots__/execution-details-pane.spec.tsx.snap
@@ -22,6 +22,7 @@ exports[`ExecutionDetailsPane matches snapshot no init tab
1`] = `
"id": "native",
"label": "Native query",
},
+ false,
undefined,
undefined,
Object {
@@ -286,6 +287,7 @@ PARTITIONED BY DAY",
"maxParseExceptions": 2,
},
"result": undefined,
+ "segmentStatus": undefined,
"sqlQuery": "REPLACE INTO \\"kttm-blank-lines\\" OVERWRITE ALL
SELECT
TIME_PARSE(\\"timestamp\\") AS \\"__time\\",
@@ -909,6 +911,7 @@ PARTITIONED BY DAY",
"maxParseExceptions": 2,
},
"result": undefined,
+ "segmentStatus": undefined,
"sqlQuery": "REPLACE INTO \\"kttm-blank-lines\\" OVERWRITE ALL
SELECT
TIME_PARSE(\\"timestamp\\") AS \\"__time\\",
@@ -1319,6 +1322,7 @@ exports[`ExecutionDetailsPane matches snapshot with init
tab 1`] = `
"id": "native",
"label": "Native query",
},
+ false,
undefined,
undefined,
Object {
@@ -1576,6 +1580,7 @@ PARTITIONED BY DAY",
"maxParseExceptions": 2,
},
"result": undefined,
+ "segmentStatus": undefined,
"sqlQuery": "REPLACE INTO \\"kttm-blank-lines\\" OVERWRITE ALL
SELECT
TIME_PARSE(\\"timestamp\\") AS \\"__time\\",
diff --git
a/web-console/src/views/workbench-view/execution-details-pane/execution-details-pane.tsx
b/web-console/src/views/workbench-view/execution-details-pane/execution-details-pane.tsx
index 72a6350d7ba..0f1200a8661 100644
---
a/web-console/src/views/workbench-view/execution-details-pane/execution-details-pane.tsx
+++
b/web-console/src/views/workbench-view/execution-details-pane/execution-details-pane.tsx
@@ -23,7 +23,7 @@ import React, { useState } from 'react';
import { FancyTabPane } from '../../../components';
import type { Execution } from '../../../druid-models';
-import { pluralIfNeeded } from '../../../utils';
+import { formatDuration, formatDurationWithMs, pluralIfNeeded } from
'../../../utils';
import { DestinationPagesPane } from
'../destination-pages-pane/destination-pages-pane';
import { ExecutionErrorPane } from
'../execution-error-pane/execution-error-pane';
import { ExecutionStagesPane } from
'../execution-stages-pane/execution-stages-pane';
@@ -40,7 +40,8 @@ export type ExecutionDetailsTab =
| 'result'
| 'pages'
| 'error'
- | 'warnings';
+ | 'warnings'
+ | 'segmentStatus';
interface ExecutionDetailsPaneProps {
execution: Execution;
@@ -53,6 +54,7 @@ export const ExecutionDetailsPane = React.memo(function
ExecutionDetailsPane(
) {
const { execution, initTab, goToTask } = props;
const [activeTab, setActiveTab] = useState<ExecutionDetailsTab>(initTab ||
'general');
+ const segmentStatusDescription = execution.getSegmentStatusDescription();
function renderContent() {
switch (activeTab) {
@@ -120,6 +122,25 @@ export const ExecutionDetailsPane = React.memo(function
ExecutionDetailsPane(
case 'warnings':
return <ExecutionWarningsPane execution={execution} />;
+ case 'segmentStatus':
+ return (
+ <>
+ <p>
+ Duration:{' '}
+ {segmentStatusDescription.duration
+ ? formatDurationWithMs(segmentStatusDescription.duration)
+ : '-'}
+ {execution.duration
+ ? ` (query duration was ${formatDuration(execution.duration)})`
+ : ''}
+ </p>
+ <p>Total segments: {segmentStatusDescription.totalSegments ??
'-'}</p>
+ <p>Used segments: {segmentStatusDescription.usedSegments ??
'-'}</p>
+ <p>Precached segments: {segmentStatusDescription.precachedSegments
?? '-'}</p>
+ <p>On demand segments: {segmentStatusDescription.onDemandSegments
?? '-'}</p>
+ </>
+ );
+
default:
return;
}
@@ -146,6 +167,11 @@ export const ExecutionDetailsPane = React.memo(function
ExecutionDetailsPane(
label: 'Native query',
icon: IconNames.COG,
},
+ Boolean(execution.segmentStatus) && {
+ id: 'segmentStatus',
+ label: 'Segments',
+ icon: IconNames.HEAT_GRID,
+ },
execution.result && {
id: 'result',
label: 'Results',
diff --git
a/web-console/src/views/workbench-view/execution-progress-bar-pane/__snapshots__/execution-progress-bar-pane.spec.tsx.snap
b/web-console/src/views/workbench-view/execution-progress-bar-pane/__snapshots__/execution-progress-bar-pane.spec.tsx.snap
index 68a8e3103c9..3e2b45ec2f1 100644
---
a/web-console/src/views/workbench-view/execution-progress-bar-pane/__snapshots__/execution-progress-bar-pane.spec.tsx.snap
+++
b/web-console/src/views/workbench-view/execution-progress-bar-pane/__snapshots__/execution-progress-bar-pane.spec.tsx.snap
@@ -20,5 +20,8 @@ exports[`ExecutionProgressBarPane matches snapshot 1`] = `
className="overall"
intent="primary"
/>
+ <Unknown>
+
+ </Unknown>
</div>
`;
diff --git
a/web-console/src/views/workbench-view/execution-progress-bar-pane/execution-progress-bar-pane.tsx
b/web-console/src/views/workbench-view/execution-progress-bar-pane/execution-progress-bar-pane.tsx
index 349bdaff93d..4520c20a39b 100644
---
a/web-console/src/views/workbench-view/execution-progress-bar-pane/execution-progress-bar-pane.tsx
+++
b/web-console/src/views/workbench-view/execution-progress-bar-pane/execution-progress-bar-pane.tsx
@@ -50,6 +50,9 @@ export const ExecutionProgressBarPane = React.memo(function
ExecutionProgressBar
const idx = stages ? stages.currentStageIndex() : -1;
const waitingForSegments = stages && !execution.isWaitingForQuery();
+
+ const segmentStatusDescription = execution?.getSegmentStatusDescription();
+
return (
<div className="execution-progress-bar-pane">
<Label>
@@ -78,6 +81,7 @@ export const ExecutionProgressBarPane = React.memo(function
ExecutionProgressBar
intent={stages ? Intent.PRIMARY : undefined}
value={stages && execution.isWaitingForQuery() ?
stages.overallProgress() : undefined}
/>
+ {segmentStatusDescription &&
<Label>{segmentStatusDescription.label}</Label>}
{stages && idx >= 0 && (
<>
<Label>{`Current stage (${idx + 1} of
${stages.stageCount()})`}</Label>
diff --git
a/web-console/src/views/workbench-view/ingest-success-pane/__snapshots__/ingest-success-pane.spec.tsx.snap
b/web-console/src/views/workbench-view/ingest-success-pane/__snapshots__/ingest-success-pane.spec.tsx.snap
index 8e987fca7c2..7c6d702e560 100644
---
a/web-console/src/views/workbench-view/ingest-success-pane/__snapshots__/ingest-success-pane.spec.tsx.snap
+++
b/web-console/src/views/workbench-view/ingest-success-pane/__snapshots__/ingest-success-pane.spec.tsx.snap
@@ -9,6 +9,7 @@ exports[`IngestSuccessPane matches snapshot 1`] = `
</p>
<p>
Insert query took 0:00:23.
+
<span
className="action"
onClick={[Function]}
diff --git
a/web-console/src/views/workbench-view/ingest-success-pane/ingest-success-pane.tsx
b/web-console/src/views/workbench-view/ingest-success-pane/ingest-success-pane.tsx
index 539ad234e7e..ac543842699 100644
---
a/web-console/src/views/workbench-view/ingest-success-pane/ingest-success-pane.tsx
+++
b/web-console/src/views/workbench-view/ingest-success-pane/ingest-success-pane.tsx
@@ -44,7 +44,9 @@ export const IngestSuccessPane = React.memo(function
IngestSuccessPane(
const warnings = execution.stages?.getWarningCount() || 0;
- const duration = execution.duration;
+ const { duration } = execution;
+ const segmentStatusDescription = execution.getSegmentStatusDescription();
+
return (
<div className="ingest-success-pane">
<p>
@@ -63,10 +65,12 @@ export const IngestSuccessPane = React.memo(function
IngestSuccessPane(
</p>
<p>
{duration ? `Insert query took ${formatDuration(duration)}. ` :
`Insert query completed. `}
+ {segmentStatusDescription ? segmentStatusDescription.label + ' ' : ''}
<span className="action" onClick={() => onDetails(execution.id)}>
Show details
</span>
</p>
+
{onQueryTab && (
<p>
Open new tab with:{' '}
diff --git a/web-console/src/views/workbench-view/run-panel/run-panel.tsx
b/web-console/src/views/workbench-view/run-panel/run-panel.tsx
index ec1b95ad38a..6c976bbf404 100644
--- a/web-console/src/views/workbench-view/run-panel/run-panel.tsx
+++ b/web-console/src/views/workbench-view/run-panel/run-panel.tsx
@@ -45,6 +45,7 @@ import {
changeUseApproximateCountDistinct,
changeUseApproximateTopN,
changeUseCache,
+ changeWaitTillSegmentsLoad,
getDurableShuffleStorage,
getFinalizeAggregations,
getGroupByEnableMultiValueUnnesting,
@@ -53,6 +54,7 @@ import {
getUseApproximateCountDistinct,
getUseApproximateTopN,
getUseCache,
+ getWaitTillSegmentsLoad,
summarizeIndexSpec,
} from '../../../druid-models';
import { deepGet, deepSet, pluralIfNeeded, tickIcon } from '../../../utils';
@@ -110,6 +112,7 @@ export const RunPanel = React.memo(function RunPanel(props:
RunPanelProps) {
const maxParseExceptions = getMaxParseExceptions(queryContext);
const finalizeAggregations = getFinalizeAggregations(queryContext);
+ const waitTillSegmentsLoad = getWaitTillSegmentsLoad(queryContext);
const groupByEnableMultiValueUnnesting =
getGroupByEnableMultiValueUnnesting(queryContext);
const sqlJoinAlgorithm = queryContext.sqlJoinAlgorithm ?? 'broadcast';
const selectDestination = queryContext.selectDestination ?? 'taskReport';
@@ -311,6 +314,15 @@ export const RunPanel = React.memo(function
RunPanel(props: RunPanelProps) {
changeQueryContext(changeFinalizeAggregations(queryContext, v))
}
/>
+ <MenuTristate
+ icon={IconNames.STOPWATCH}
+ text="Wait until segments have loaded"
+ value={waitTillSegmentsLoad}
+ undefinedEffectiveValue /* ={true} */
+ onValueChange={v =>
+
changeQueryContext(changeWaitTillSegmentsLoad(queryContext, v))
+ }
+ />
<MenuTristate
icon={IconNames.FORK}
text="Enable GroupBy multi-value unnesting"
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]