add useConcurrentLocks toggle (#16899)

This commit is contained in:
Vadim Ogievetsky 2024-08-14 13:44:53 -07:00 committed by GitHub
parent ca82ecd352
commit 8181ef627a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 286 additions and 38 deletions

View File

@ -40,6 +40,7 @@ export interface QueryContext {
sqlJoinAlgorithm?: SqlJoinAlgorithm;
failOnEmptyInsert?: boolean;
waitUntilSegmentsLoad?: boolean;
useConcurrentLocks?: boolean;
[key: string]: any;
}
@ -61,6 +62,7 @@ export const DEFAULT_SERVER_QUERY_CONTEXT: QueryContext = {
sqlJoinAlgorithm: 'broadcast',
failOnEmptyInsert: false,
waitUntilSegmentsLoad: false,
useConcurrentLocks: false,
};
export interface QueryWithContext {

View File

@ -0,0 +1,176 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`RunPanel matches snapshot on msq (auto) query 1`] = `
<div
class="run-panel"
>
<button
class="bp5-button bp5-intent-primary"
type="button"
>
<span
aria-hidden="true"
class="bp5-icon bp5-icon-caret-right"
>
<svg
data-icon="caret-right"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
>
<path
d="M11 8c0-.15-.07-.28-.17-.37l-4-3.5A.495.495 0 006 4.5v7a.495.495 0 00.83.37l4-3.5c.1-.09.17-.22.17-.37z"
fill-rule="evenodd"
/>
</svg>
</span>
<span
class="bp5-button-text"
>
Run
</span>
</button>
<div
class="bp5-button-group"
>
<span
class="bp5-popover-target"
>
<button
aria-expanded="false"
aria-haspopup="menu"
class="bp5-button"
type="button"
>
<span
class="bp5-button-text"
>
Engine: sql-msq-task
</span>
<span
aria-hidden="true"
class="bp5-icon bp5-icon-caret-down"
>
<svg
data-icon="caret-down"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
>
<path
d="M12 6.5c0-.28-.22-.5-.5-.5h-7a.495.495 0 00-.37.83l3.5 4c.09.1.22.17.37.17s.28-.07.37-.17l3.5-4c.08-.09.13-.2.13-.33z"
fill-rule="evenodd"
/>
</svg>
</span>
</button>
</span>
<span
class="max-tasks-button bp5-popover-target"
>
<button
aria-expanded="false"
aria-haspopup="menu"
class="bp5-button"
type="button"
>
<span
class="bp5-button-text"
>
Max tasks: 9 (full cluster capacity)
</span>
<span
aria-hidden="true"
class="bp5-icon bp5-icon-caret-down"
>
<svg
data-icon="caret-down"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
>
<path
d="M12 6.5c0-.28-.22-.5-.5-.5h-7a.495.495 0 00-.37.83l3.5 4c.09.1.22.17.37.17s.28-.07.37-.17l3.5-4c.08-.09.13-.2.13-.33z"
fill-rule="evenodd"
/>
</svg>
</span>
</button>
</span>
</div>
</div>
`;
exports[`RunPanel matches snapshot on native (auto) query 1`] = `
<div
class="run-panel"
>
<button
class="bp5-button bp5-intent-primary"
type="button"
>
<span
aria-hidden="true"
class="bp5-icon bp5-icon-caret-right"
>
<svg
data-icon="caret-right"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
>
<path
d="M11 8c0-.15-.07-.28-.17-.37l-4-3.5A.495.495 0 006 4.5v7a.495.495 0 00.83.37l4-3.5c.1-.09.17-.22.17-.37z"
fill-rule="evenodd"
/>
</svg>
</span>
<span
class="bp5-button-text"
>
Run
</span>
</button>
<div
class="bp5-button-group"
>
<span
class="bp5-popover-target"
>
<button
aria-expanded="false"
aria-haspopup="menu"
class="bp5-button"
type="button"
>
<span
class="bp5-button-text"
>
Engine: auto (sql-native)
</span>
<span
aria-hidden="true"
class="bp5-icon bp5-icon-caret-down"
>
<svg
data-icon="caret-down"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
>
<path
d="M12 6.5c0-.28-.22-.5-.5-.5h-7a.495.495 0 00-.37.83l3.5 4c.09.1.22.17.37.17s.28-.07.37-.17l3.5-4c.08-.09.13-.2.13-.33z"
fill-rule="evenodd"
/>
</svg>
</span>
</button>
</span>
</div>
</div>
`;

View File

@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { render } from '@testing-library/react';
import React from 'react';
import { DEFAULT_SERVER_QUERY_CONTEXT, DRUID_ENGINES, WorkbenchQuery } from '../../../druid-models';
import { RunPanel } from './run-panel';
describe('RunPanel', () => {
it('matches snapshot on native (auto) query', () => {
const runPanel = (
<RunPanel
query={WorkbenchQuery.blank().changeQueryString(`SELECT * FROM wikipedia`)}
onQueryChange={() => {}}
running={false}
onRun={() => {}}
queryEngines={DRUID_ENGINES}
clusterCapacity={9}
defaultQueryContext={DEFAULT_SERVER_QUERY_CONTEXT}
/>
);
const { container } = render(runPanel);
expect(container.firstChild).toMatchSnapshot();
});
it('matches snapshot on msq (auto) query', () => {
const runPanel = (
<RunPanel
query={WorkbenchQuery.blank()
.changeQueryString(`SELECT * FROM wikipedia`)
.changeEngine('sql-msq-task')}
onQueryChange={() => {}}
running={false}
onRun={() => {}}
queryEngines={DRUID_ENGINES}
clusterCapacity={9}
defaultQueryContext={DEFAULT_SERVER_QUERY_CONTEXT}
/>
);
const { container } = render(runPanel);
expect(container.firstChild).toMatchSnapshot();
});
});

View File

@ -103,7 +103,6 @@ export interface RunPanelProps
query: WorkbenchQuery;
onQueryChange(query: WorkbenchQuery): void;
running: boolean;
small?: boolean;
onRun(preview: boolean): void | Promise<void>;
queryEngines: DruidEngine[];
clusterCapacity: number | undefined;
@ -120,7 +119,6 @@ export const RunPanel = React.memo(function RunPanel(props: RunPanelProps) {
onRun,
moreMenu,
running,
small,
queryEngines,
clusterCapacity,
defaultQueryContext,
@ -166,6 +164,11 @@ export const RunPanel = React.memo(function RunPanel(props: RunPanelProps) {
queryContext,
defaultQueryContext,
);
const useConcurrentLocks = getQueryContextKey(
'useConcurrentLocks',
queryContext,
defaultQueryContext,
);
const finalizeAggregations = queryContext.finalizeAggregations;
const waitUntilSegmentsLoad = queryContext.waitUntilSegmentsLoad;
const groupByEnableMultiValueUnnesting = queryContext.groupByEnableMultiValueUnnesting;
@ -198,7 +201,6 @@ export const RunPanel = React.memo(function RunPanel(props: RunPanelProps) {
}, [onRun]);
const hotkeys = useMemo(() => {
if (small) return [];
return [
{
allowInInput: true,
@ -217,7 +219,7 @@ export const RunPanel = React.memo(function RunPanel(props: RunPanelProps) {
onKeyDown: handlePreview,
},
];
}, [small, handleRun, handlePreview]);
}, [handleRun, handlePreview]);
useHotkeys(hotkeys);
@ -264,9 +266,7 @@ export const RunPanel = React.memo(function RunPanel(props: RunPanelProps) {
icon={IconNames.CARET_RIGHT}
onClick={() => void onRun(false)}
text="Run"
intent={!emptyQuery && !small ? Intent.PRIMARY : undefined}
small={small}
minimal={small}
intent={!emptyQuery ? Intent.PRIMARY : undefined}
/>
{ingestMode && (
<Button
@ -274,11 +274,9 @@ export const RunPanel = React.memo(function RunPanel(props: RunPanelProps) {
icon={IconNames.EYE_OPEN}
onClick={() => void onRun(true)}
text="Preview"
small={small}
minimal={small}
/>
)}
{!small && onQueryChange && (
{onQueryChange && (
<ButtonGroup>
<Popover
position={Position.BOTTOM_LEFT}
@ -366,6 +364,45 @@ export const RunPanel = React.memo(function RunPanel(props: RunPanelProps) {
)}
{effectiveEngine === 'sql-msq-task' ? (
<>
<MenuItem icon={IconNames.BRING_DATA} text="INSERT / REPLACE specific context">
<MenuCheckbox
checked={useConcurrentLocks}
text="Use concurrent locks"
onChange={() =>
changeQueryContext({
...queryContext,
useConcurrentLocks: !useConcurrentLocks,
})
}
/>
<MenuTristate
icon={IconNames.DISABLE}
text="Fail on empty insert"
value={failOnEmptyInsert}
undefinedEffectiveValue={false}
onValueChange={failOnEmptyInsert =>
changeQueryContext({ ...queryContext, failOnEmptyInsert })
}
/>
<MenuTristate
icon={IconNames.STOPWATCH}
text="Wait until segments have loaded"
value={waitUntilSegmentsLoad}
undefinedEffectiveValue={ingestMode}
onValueChange={waitUntilSegmentsLoad =>
changeQueryContext({ ...queryContext, waitUntilSegmentsLoad })
}
/>
<MenuItem
icon={IconNames.TH_DERIVED}
text="Edit index spec"
label={summarizeIndexSpec(indexSpec)}
shouldDismissPopover={false}
onClick={() => {
setIndexSpecDialogSpec(indexSpec || {});
}}
/>
</MenuItem>
<MenuItem
icon={IconNames.ERROR}
text="Max parse exceptions"
@ -383,15 +420,6 @@ export const RunPanel = React.memo(function RunPanel(props: RunPanelProps) {
/>
))}
</MenuItem>
<MenuTristate
icon={IconNames.DISABLE}
text="Fail on empty insert"
value={failOnEmptyInsert}
undefinedEffectiveValue={false}
onValueChange={failOnEmptyInsert =>
changeQueryContext({ ...queryContext, failOnEmptyInsert })
}
/>
<MenuTristate
icon={IconNames.TRANSLATE}
text="Finalize aggregations"
@ -401,15 +429,6 @@ export const RunPanel = React.memo(function RunPanel(props: RunPanelProps) {
changeQueryContext({ ...queryContext, finalizeAggregations })
}
/>
<MenuTristate
icon={IconNames.STOPWATCH}
text="Wait until segments have loaded"
value={waitUntilSegmentsLoad}
undefinedEffectiveValue={ingestMode}
onValueChange={waitUntilSegmentsLoad =>
changeQueryContext({ ...queryContext, waitUntilSegmentsLoad })
}
/>
<MenuTristate
icon={IconNames.FORK}
text="Enable GroupBy multi-value unnesting"
@ -477,15 +496,6 @@ export const RunPanel = React.memo(function RunPanel(props: RunPanelProps) {
})
}
/>
<MenuItem
icon={IconNames.TH_DERIVED}
text="Edit index spec"
label={summarizeIndexSpec(indexSpec)}
shouldDismissPopover={false}
onClick={() => {
setIndexSpecDialogSpec(indexSpec || {});
}}
/>
</>
) : (
<>
@ -602,7 +612,7 @@ export const RunPanel = React.memo(function RunPanel(props: RunPanelProps) {
)}
{moreMenu && (
<Popover position={Position.BOTTOM_LEFT} content={moreMenu}>
<Button small={small} minimal={small} rightIcon={IconNames.MORE} />
<Button rightIcon={IconNames.MORE} />
</Popover>
)}
{editContextDialogOpen && (