mirror of
https://github.com/apache/druid.git
synced 2025-02-17 07:25:02 +00:00
Web console: Fix concurrent tasks (#15649)
* Improve handling of concurrent tasks option * Update snapshots
This commit is contained in:
parent
747d973752
commit
85b8cf9f37
@ -72,10 +72,6 @@ export interface Field<M> {
|
|||||||
hide?: Functor<M, boolean>;
|
hide?: Functor<M, boolean>;
|
||||||
hideInMore?: Functor<M, boolean>;
|
hideInMore?: Functor<M, boolean>;
|
||||||
valueAdjustment?: (value: any) => any;
|
valueAdjustment?: (value: any) => any;
|
||||||
/**
|
|
||||||
* An optional callback to transform the value before it is set on the input
|
|
||||||
*/
|
|
||||||
adjustValue?: (value: any) => any;
|
|
||||||
adjustment?: (model: Partial<M>, oldModel: Partial<M>) => Partial<M>;
|
adjustment?: (model: Partial<M>, oldModel: Partial<M>) => Partial<M>;
|
||||||
issueWithValue?: (value: any) => string | undefined;
|
issueWithValue?: (value: any) => string | undefined;
|
||||||
|
|
||||||
@ -382,14 +378,12 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent
|
|||||||
const disabled = AutoForm.evaluateFunctor(field.disabled, model, false);
|
const disabled = AutoForm.evaluateFunctor(field.disabled, model, false);
|
||||||
const intent = required && modelValue == null ? AutoForm.REQUIRED_INTENT : undefined;
|
const intent = required && modelValue == null ? AutoForm.REQUIRED_INTENT : undefined;
|
||||||
|
|
||||||
const adjustedValue = field.adjustValue ? field.adjustValue(shownValue) : shownValue;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonGroup large={large}>
|
<ButtonGroup large={large}>
|
||||||
<Button
|
<Button
|
||||||
intent={intent}
|
intent={intent}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
active={adjustedValue === false}
|
active={shownValue === false}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.fieldChange(field, false);
|
this.fieldChange(field, false);
|
||||||
if (onFinalize) onFinalize();
|
if (onFinalize) onFinalize();
|
||||||
@ -400,7 +394,7 @@ export class AutoForm<T extends Record<string, any>> extends React.PureComponent
|
|||||||
<Button
|
<Button
|
||||||
intent={intent}
|
intent={intent}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
active={adjustedValue === true}
|
active={shownValue === true}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.fieldChange(field, true);
|
this.fieldChange(field, true);
|
||||||
if (onFinalize) onFinalize();
|
if (onFinalize) onFinalize();
|
||||||
|
@ -15,6 +15,7 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (dynamic
|
|||||||
<div
|
<div
|
||||||
className="content"
|
className="content"
|
||||||
>
|
>
|
||||||
|
<React.Fragment>
|
||||||
<AutoForm
|
<AutoForm
|
||||||
fields={
|
fields={
|
||||||
Array [
|
Array [
|
||||||
@ -335,17 +336,6 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (dynamic
|
|||||||
"name": "tuningConfig.splitHintSpec.maxNumFiles",
|
"name": "tuningConfig.splitHintSpec.maxNumFiles",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
},
|
},
|
||||||
Object {
|
|
||||||
"adjustValue": [Function],
|
|
||||||
"defaultValue": undefined,
|
|
||||||
"info": <p>
|
|
||||||
Allows or forbids concurrent compactions.
|
|
||||||
</p>,
|
|
||||||
"label": "Allow concurrent compactions (experimental)",
|
|
||||||
"name": "taskContext.taskLockType",
|
|
||||||
"type": "boolean",
|
|
||||||
"valueAdjustment": [Function],
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
model={
|
model={
|
||||||
@ -360,6 +350,12 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (dynamic
|
|||||||
}
|
}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
|
<Blueprint4.Switch
|
||||||
|
checked={false}
|
||||||
|
label="Allow concurrent compactions (experimental)"
|
||||||
|
onChange={[Function]}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="bp4-dialog-footer"
|
className="bp4-dialog-footer"
|
||||||
@ -408,6 +404,7 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (hashed p
|
|||||||
<div
|
<div
|
||||||
className="content"
|
className="content"
|
||||||
>
|
>
|
||||||
|
<React.Fragment>
|
||||||
<AutoForm
|
<AutoForm
|
||||||
fields={
|
fields={
|
||||||
Array [
|
Array [
|
||||||
@ -728,17 +725,6 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (hashed p
|
|||||||
"name": "tuningConfig.splitHintSpec.maxNumFiles",
|
"name": "tuningConfig.splitHintSpec.maxNumFiles",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
},
|
},
|
||||||
Object {
|
|
||||||
"adjustValue": [Function],
|
|
||||||
"defaultValue": undefined,
|
|
||||||
"info": <p>
|
|
||||||
Allows or forbids concurrent compactions.
|
|
||||||
</p>,
|
|
||||||
"label": "Allow concurrent compactions (experimental)",
|
|
||||||
"name": "taskContext.taskLockType",
|
|
||||||
"type": "boolean",
|
|
||||||
"valueAdjustment": [Function],
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
model={
|
model={
|
||||||
@ -753,6 +739,12 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (hashed p
|
|||||||
}
|
}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
|
<Blueprint4.Switch
|
||||||
|
checked={false}
|
||||||
|
label="Allow concurrent compactions (experimental)"
|
||||||
|
onChange={[Function]}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="bp4-dialog-footer"
|
className="bp4-dialog-footer"
|
||||||
@ -801,6 +793,7 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (range pa
|
|||||||
<div
|
<div
|
||||||
className="content"
|
className="content"
|
||||||
>
|
>
|
||||||
|
<React.Fragment>
|
||||||
<AutoForm
|
<AutoForm
|
||||||
fields={
|
fields={
|
||||||
Array [
|
Array [
|
||||||
@ -1121,17 +1114,6 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (range pa
|
|||||||
"name": "tuningConfig.splitHintSpec.maxNumFiles",
|
"name": "tuningConfig.splitHintSpec.maxNumFiles",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
},
|
},
|
||||||
Object {
|
|
||||||
"adjustValue": [Function],
|
|
||||||
"defaultValue": undefined,
|
|
||||||
"info": <p>
|
|
||||||
Allows or forbids concurrent compactions.
|
|
||||||
</p>,
|
|
||||||
"label": "Allow concurrent compactions (experimental)",
|
|
||||||
"name": "taskContext.taskLockType",
|
|
||||||
"type": "boolean",
|
|
||||||
"valueAdjustment": [Function],
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
model={
|
model={
|
||||||
@ -1146,6 +1128,12 @@ exports[`CompactionConfigDialog matches snapshot with compactionConfig (range pa
|
|||||||
}
|
}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
|
<Blueprint4.Switch
|
||||||
|
checked={false}
|
||||||
|
label="Allow concurrent compactions (experimental)"
|
||||||
|
onChange={[Function]}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="bp4-dialog-footer"
|
className="bp4-dialog-footer"
|
||||||
@ -1194,6 +1182,7 @@ exports[`CompactionConfigDialog matches snapshot without compactionConfig 1`] =
|
|||||||
<div
|
<div
|
||||||
className="content"
|
className="content"
|
||||||
>
|
>
|
||||||
|
<React.Fragment>
|
||||||
<AutoForm
|
<AutoForm
|
||||||
fields={
|
fields={
|
||||||
Array [
|
Array [
|
||||||
@ -1514,17 +1503,6 @@ exports[`CompactionConfigDialog matches snapshot without compactionConfig 1`] =
|
|||||||
"name": "tuningConfig.splitHintSpec.maxNumFiles",
|
"name": "tuningConfig.splitHintSpec.maxNumFiles",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
},
|
},
|
||||||
Object {
|
|
||||||
"adjustValue": [Function],
|
|
||||||
"defaultValue": undefined,
|
|
||||||
"info": <p>
|
|
||||||
Allows or forbids concurrent compactions.
|
|
||||||
</p>,
|
|
||||||
"label": "Allow concurrent compactions (experimental)",
|
|
||||||
"name": "taskContext.taskLockType",
|
|
||||||
"type": "boolean",
|
|
||||||
"valueAdjustment": [Function],
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
model={
|
model={
|
||||||
@ -1539,6 +1517,12 @@ exports[`CompactionConfigDialog matches snapshot without compactionConfig 1`] =
|
|||||||
}
|
}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
|
<Blueprint4.Switch
|
||||||
|
checked={false}
|
||||||
|
label="Allow concurrent compactions (experimental)"
|
||||||
|
onChange={[Function]}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="bp4-dialog-footer"
|
className="bp4-dialog-footer"
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Button, Callout, Classes, Code, Dialog, Intent } from '@blueprintjs/core';
|
import { Button, Callout, Classes, Code, Dialog, Intent, Switch } from '@blueprintjs/core';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import type { FormJsonTabs } from '../../components';
|
import type { FormJsonTabs } from '../../components';
|
||||||
@ -26,7 +26,7 @@ import {
|
|||||||
COMPACTION_CONFIG_FIELDS,
|
COMPACTION_CONFIG_FIELDS,
|
||||||
compactionConfigHasLegacyInputSegmentSizeBytesSet,
|
compactionConfigHasLegacyInputSegmentSizeBytesSet,
|
||||||
} from '../../druid-models';
|
} from '../../druid-models';
|
||||||
import { deepDelete, formatBytesCompact } from '../../utils';
|
import { deepDelete, deepGet, deepSet, formatBytesCompact } from '../../utils';
|
||||||
import { CompactionHistoryDialog } from '../compaction-history-dialog/compaction-history-dialog';
|
import { CompactionHistoryDialog } from '../compaction-history-dialog/compaction-history-dialog';
|
||||||
|
|
||||||
import './compaction-config-dialog.scss';
|
import './compaction-config-dialog.scss';
|
||||||
@ -96,11 +96,24 @@ export const CompactionConfigDialog = React.memo(function CompactionConfigDialog
|
|||||||
/>
|
/>
|
||||||
<div className="content">
|
<div className="content">
|
||||||
{currentTab === 'form' ? (
|
{currentTab === 'form' ? (
|
||||||
|
<>
|
||||||
<AutoForm
|
<AutoForm
|
||||||
fields={COMPACTION_CONFIG_FIELDS}
|
fields={COMPACTION_CONFIG_FIELDS}
|
||||||
model={currentConfig}
|
model={currentConfig}
|
||||||
onChange={m => setCurrentConfig(m as CompactionConfig)}
|
onChange={m => setCurrentConfig(m as CompactionConfig)}
|
||||||
/>
|
/>
|
||||||
|
<Switch
|
||||||
|
label="Allow concurrent compactions (experimental)"
|
||||||
|
checked={typeof deepGet(currentConfig, 'taskContext.taskLockType') === 'string'}
|
||||||
|
onChange={() => {
|
||||||
|
setCurrentConfig(
|
||||||
|
(typeof deepGet(currentConfig, 'taskContext.taskLockType') === 'string'
|
||||||
|
? deepDelete(currentConfig, 'taskContext.taskLockType')
|
||||||
|
: deepSet(currentConfig, 'taskContext.taskLockType', 'REPLACE')) as any,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<JsonInput
|
<JsonInput
|
||||||
value={currentConfig}
|
value={currentConfig}
|
||||||
|
@ -354,13 +354,4 @@ export const COMPACTION_CONFIG_FIELDS: Field<CompactionConfig>[] = [
|
|||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'taskContext.taskLockType',
|
|
||||||
type: 'boolean',
|
|
||||||
label: 'Allow concurrent compactions (experimental)',
|
|
||||||
defaultValue: undefined,
|
|
||||||
valueAdjustment: v => (v ? 'REPLACE' : undefined),
|
|
||||||
adjustValue: v => v === 'REPLACE',
|
|
||||||
info: <p>Allows or forbids concurrent compactions.</p>,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
@ -347,7 +347,10 @@ export function normalizeSpec(spec: Partial<IngestionSpec>): IngestionSpec {
|
|||||||
spec = deepSetIfUnset(spec, 'spec.tuningConfig.type', specType);
|
spec = deepSetIfUnset(spec, 'spec.tuningConfig.type', specType);
|
||||||
|
|
||||||
if (spec.context?.taskLockType !== undefined) {
|
if (spec.context?.taskLockType !== undefined) {
|
||||||
spec.context.taskLockType = spec.spec?.ioConfig.appendToExisting ? 'APPEND' : 'REPLACE';
|
spec.context.taskLockType =
|
||||||
|
isStreamingSpec(spec) || deepGet(spec, 'spec.ioConfig.appendToExisting')
|
||||||
|
? 'APPEND'
|
||||||
|
: 'REPLACE';
|
||||||
}
|
}
|
||||||
|
|
||||||
return spec as IngestionSpec;
|
return spec as IngestionSpec;
|
||||||
|
@ -3134,8 +3134,6 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
|
|||||||
const { spec } = this.state;
|
const { spec } = this.state;
|
||||||
const parallel = deepGet(spec, 'spec.tuningConfig.maxNumConcurrentSubTasks') > 1;
|
const parallel = deepGet(spec, 'spec.tuningConfig.maxNumConcurrentSubTasks') > 1;
|
||||||
|
|
||||||
const appendToExisting = spec.spec?.ioConfig.appendToExisting;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="main">
|
<div className="main">
|
||||||
@ -3161,6 +3159,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
|
|||||||
name: 'spec.ioConfig.appendToExisting',
|
name: 'spec.ioConfig.appendToExisting',
|
||||||
label: 'Append to existing',
|
label: 'Append to existing',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
|
defined: s => !isStreamingSpec(s),
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
// appendToExisting can only be set on 'dynamic' portioning.
|
// appendToExisting can only be set on 'dynamic' portioning.
|
||||||
// We chose to show it always and instead have a specific message, separate from this form, to notify the user of the issue.
|
// We chose to show it always and instead have a specific message, separate from this form, to notify the user of the issue.
|
||||||
@ -3171,37 +3170,27 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
|
|||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'context.taskLockType',
|
|
||||||
type: 'boolean',
|
|
||||||
label: `Allow concurrent ${
|
|
||||||
appendToExisting ? 'append' : 'replace'
|
|
||||||
} tasks (experimental)`,
|
|
||||||
defaultValue: undefined,
|
|
||||||
valueAdjustment: v => {
|
|
||||||
if (!v) return undefined;
|
|
||||||
|
|
||||||
if (isStreamingSpec(spec)) {
|
|
||||||
return 'APPEND';
|
|
||||||
} else {
|
|
||||||
return appendToExisting ? 'APPEND' : 'REPLACE';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
adjustValue: v => {
|
|
||||||
if (v === undefined) return false;
|
|
||||||
|
|
||||||
if (isStreamingSpec(spec)) {
|
|
||||||
return v === 'APPEND';
|
|
||||||
}
|
|
||||||
|
|
||||||
return v === (appendToExisting ? 'APPEND' : 'REPLACE');
|
|
||||||
},
|
|
||||||
info: <p>Allows or forbids concurrent tasks.</p>,
|
|
||||||
},
|
|
||||||
]}
|
]}
|
||||||
model={spec}
|
model={spec}
|
||||||
onChange={this.updateSpec}
|
onChange={this.updateSpec}
|
||||||
/>
|
/>
|
||||||
|
<Switch
|
||||||
|
label="Allow concurrent tasks (experimental)"
|
||||||
|
checked={typeof deepGet(spec, 'context.taskLockType') === 'string'}
|
||||||
|
onChange={() => {
|
||||||
|
this.updateSpec(
|
||||||
|
typeof deepGet(spec, 'context.taskLockType') === 'string'
|
||||||
|
? deepDelete(spec, 'context.taskLockType')
|
||||||
|
: deepSet(
|
||||||
|
spec,
|
||||||
|
'context.taskLockType',
|
||||||
|
isStreamingSpec(spec) || deepGet(spec, 'spec.ioConfig.appendToExisting')
|
||||||
|
? 'APPEND'
|
||||||
|
: 'REPLACE',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="other">
|
<div className="other">
|
||||||
<H5>Parse error reporting</H5>
|
<H5>Parse error reporting</H5>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user