Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ export interface SerializedHotPhase extends SerializedPhase {
max_age?: string;
max_docs?: number;
};
forcemerge?: {
max_num_segments: number;
};
forcemerge?: ForcemergeAction;
set_priority?: {
priority: number | null;
};
Expand All @@ -57,9 +55,7 @@ export interface SerializedWarmPhase extends SerializedPhase {
shrink?: {
number_of_shards: number;
};
forcemerge?: {
max_num_segments: number;
};
forcemerge?: ForcemergeAction;
set_priority?: {
priority: number | null;
};
Expand Down Expand Up @@ -105,6 +101,12 @@ export interface AllocateAction {
};
}

export interface ForcemergeAction {
max_num_segments: number;
// only accepted value for index_codec
index_codec?: 'best_compression';
}

export interface Policy {
name: string;
phases: {
Expand Down Expand Up @@ -150,6 +152,7 @@ export interface PhaseWithIndexPriority {
export interface PhaseWithForcemergeAction {
forceMergeEnabled: boolean;
selectedForceMergeSegments: string;
bestCompressionEnabled: boolean;
}

export interface HotPhase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const defaultNewHotPhase: HotPhase = {
selectedMaxSizeStoredUnits: 'gb',
forceMergeEnabled: false,
selectedForceMergeSegments: '',
bestCompressionEnabled: false,
phaseIndexPriority: '100',
selectedMaxDocuments: '',
};
Expand All @@ -29,6 +30,7 @@ export const defaultNewWarmPhase: WarmPhase = {
phaseEnabled: false,
forceMergeEnabled: false,
selectedForceMergeSegments: '',
bestCompressionEnabled: false,
selectedMinimumAge: '0',
selectedMinimumAgeUnits: 'd',
selectedNodeAttrs: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiDescribedFormGroup,
EuiFieldNumber,
EuiFormRow,
EuiSpacer,
EuiSwitch,
EuiTextColor,
Expand All @@ -19,17 +20,25 @@ import { ErrableFormRow } from './form_errors';
import { Phases, PhaseWithForcemergeAction } from '../../../../../common/types';
import { PhaseValidationErrors } from '../../../services/policies/policy_validation';

const forcemergeLabel = i18n.translate('xpack.indexLifecycleMgmt.warmPhase.forceMergeDataLabel', {
const forcemergeLabel = i18n.translate('xpack.indexLifecycleMgmt.forcemerge.enableLabel', {
defaultMessage: 'Force merge data',
});

const bestCompressionLabel = i18n.translate(
'xpack.indexLifecycleMgmt.forcemerge.bestCompressionLabel',
{
defaultMessage: 'Enable higher compression ratio codec',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some alternate suggestions in order of preference:

  • Compress stored fields
  • Use higher compression

}
);

interface Props {
errors?: PhaseValidationErrors<PhaseWithForcemergeAction>;
phase: keyof Phases & string;
phaseData: PhaseWithForcemergeAction;
setPhaseData: (dataKey: keyof PhaseWithForcemergeAction, value: boolean | string) => void;
isShowingErrors: boolean;
}

export const Forcemerge: React.FunctionComponent<Props> = ({
errors,
phaseData,
Expand All @@ -42,15 +51,15 @@ export const Forcemerge: React.FunctionComponent<Props> = ({
title={
<h3>
<FormattedMessage
id="xpack.indexLifecycleMgmt.editPolicy.warmPhase.forceMergeDataText"
id="xpack.indexLifecycleMgmt.editPolicy.forceMerge.enableText"
defaultMessage="Force merge"
/>
</h3>
}
description={
<EuiTextColor color="subdued">
<FormattedMessage
id="xpack.indexLifecycleMgmt.editPolicy.warmPhase.forceMergeDataExplanationText"
id="xpack.indexLifecycleMgmt.editPolicy.forceMerge.enableExplanationText"
defaultMessage="Reduce the number of segments in your shard by merging smaller files and clearing deleted ones."
/>{' '}
<LearnMoreLink docPath="indices-forcemerge.html" />
Expand All @@ -73,23 +82,44 @@ export const Forcemerge: React.FunctionComponent<Props> = ({
<EuiSpacer />
<div id="forcemergeContent" aria-live="polite" role="region">
{phaseData.forceMergeEnabled ? (
<ErrableFormRow
id={`${phase}-selectedForceMergeSegments`}
label={i18n.translate('xpack.indexLifecycleMgmt.warmPhase.numberOfSegmentsLabel', {
defaultMessage: 'Number of segments',
})}
isShowingErrors={isShowingErrors}
errors={errors?.selectedForceMergeSegments}
>
<EuiFieldNumber
data-test-subj={`${phase}-selectedForceMergeSegments`}
value={phaseData.selectedForceMergeSegments}
onChange={(e) => {
setPhaseData('selectedForceMergeSegments', e.target.value);
}}
min={1}
/>
</ErrableFormRow>
<>
<ErrableFormRow
id={`${phase}-selectedForceMergeSegments`}
label={i18n.translate('xpack.indexLifecycleMgmt.forceMerge.numberOfSegmentsLabel', {
defaultMessage: 'Number of segments',
})}
isShowingErrors={isShowingErrors}
errors={errors?.selectedForceMergeSegments}
>
<EuiFieldNumber
data-test-subj={`${phase}-selectedForceMergeSegments`}
value={phaseData.selectedForceMergeSegments}
onChange={(e) => {
setPhaseData('selectedForceMergeSegments', e.target.value);
}}
min={1}
/>
</ErrableFormRow>
<EuiFormRow
hasEmptyLabelSpace
helpText={
<FormattedMessage
id="xpack.indexLifecycleMgmt.editPolicy.forceMerge.bestCompressionText"
defaultMessage="Uses DEFLATE for a higher compression ratio but slower stored fields performance
than the default LZ4 codec."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some alternate suggestions in order of preference:

  • Better compress stored fields at the cost of slower performance.
  • Use higher compression for stored fields at the cost of slower performance.
  • Use the DEFLATE codec for higher compression but slower stored fields performance. If disabled, the default LZ4 codec is used.

/>
}
>
<EuiSwitch
data-test-subj={`${phase}-bestCompression`}
label={bestCompressionLabel}
checked={phaseData.bestCompressionEnabled}
onChange={(e) => {
setPhaseData('bestCompressionEnabled', e.target.checked);
}}
/>
</EuiFormRow>
</>
) : null}
</div>
</EuiDescribedFormGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import { determineDataTierAllocationType } from '../../lib';
import { serializePhaseWithAllocation } from './shared';

const coldPhaseInitialization: ColdPhase = {
export const coldPhaseInitialization: ColdPhase = {
phaseEnabled: false,
selectedMinimumAge: '0',
selectedMinimumAgeUnits: 'd',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const hotPhaseInitialization: HotPhase = {
selectedMaxSizeStoredUnits: 'gb',
forceMergeEnabled: false,
selectedForceMergeSegments: '',
bestCompressionEnabled: false,
phaseIndexPriority: '',
selectedMaxDocuments: '',
};
Expand Down Expand Up @@ -64,6 +65,8 @@ export const hotPhaseFromES = (phaseSerialized?: SerializedHotPhase): HotPhase =
const forcemerge = actions.forcemerge;
phase.forceMergeEnabled = true;
phase.selectedForceMergeSegments = forcemerge.max_num_segments.toString();
// only accepted value for index_codec
phase.bestCompressionEnabled = forcemerge.index_codec === 'best_compression';
}

if (actions.set_priority) {
Expand Down Expand Up @@ -105,6 +108,10 @@ export const hotPhaseToES = (
esPhase.actions.forcemerge = {
max_num_segments: parseInt(phase.selectedForceMergeSegments, 10),
};
if (phase.bestCompressionEnabled) {
// only accepted value for index_codec
esPhase.actions.forcemerge.index_codec = 'best_compression';
}
} else {
delete esPhase.actions.forcemerge;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/
import cloneDeep from 'lodash/cloneDeep';
import { serializePolicy } from './policy_serialization';
import { deserializePolicy, serializePolicy } from './policy_serialization';
import {
defaultNewColdPhase,
defaultNewDeletePhase,
defaultNewHotPhase,
defaultNewWarmPhase,
} from '../../constants';
import { DataTierAllocationType } from '../../../../common/types';
import { coldPhaseInitialization } from './cold_phase';

describe('Policy serialization', () => {
test('serialize a policy using "default" data allocation', () => {
Expand Down Expand Up @@ -367,4 +368,135 @@ describe('Policy serialization', () => {
serializePolicy(deserializedPolicy, originalPolicy);
expect(originalPolicy).toEqual(originalClone);
});

test('serialize a policy using "best_compression" codec for forcemerge', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is worth adding a test that asserts our serialisation will remove the "best_compression" setting from a policy that originally has it specified. This will ensure that we do not have a dangling "best_compression" setting.

expect(
serializePolicy(
{
name: 'test',
phases: {
hot: {
...defaultNewHotPhase,
forceMergeEnabled: true,
selectedForceMergeSegments: '1',
bestCompressionEnabled: true,
},
warm: {
...defaultNewWarmPhase,
phaseEnabled: true,
forceMergeEnabled: true,
selectedForceMergeSegments: '1',
bestCompressionEnabled: true,
},
cold: {
...defaultNewColdPhase,
},
delete: { ...defaultNewDeletePhase },
},
},
{
name: 'test',
phases: {
hot: { actions: {} },
warm: {
actions: { allocate: { include: {}, exclude: {}, require: { something: 'here' } } },
},
},
}
)
).toEqual({
name: 'test',
phases: {
hot: {
actions: {
rollover: {
max_age: '30d',
max_size: '50gb',
},
forcemerge: {
max_num_segments: 1,
index_codec: 'best_compression',
},
set_priority: {
priority: 100,
},
},
},
warm: {
actions: {
forcemerge: {
max_num_segments: 1,
index_codec: 'best_compression',
},
set_priority: {
priority: 50,
},
},
},
},
});
});

test('de-serialize a policy using "best_compression" codec for forcemerge', () => {
expect(
deserializePolicy({
modified_date: Date.now().toString(),
name: 'test',
version: 1,
policy: {
name: 'test',
phases: {
hot: {
actions: {
rollover: {
max_age: '30d',
max_size: '50gb',
},
forcemerge: {
max_num_segments: 1,
index_codec: 'best_compression',
},
set_priority: {
priority: 100,
},
},
},
warm: {
actions: {
forcemerge: {
max_num_segments: 1,
index_codec: 'best_compression',
},
set_priority: {
priority: 50,
},
},
},
},
},
})
).toEqual({
name: 'test',
phases: {
hot: {
...defaultNewHotPhase,
forceMergeEnabled: true,
selectedForceMergeSegments: '1',
bestCompressionEnabled: true,
},
warm: {
...defaultNewWarmPhase,
warmPhaseOnRollover: false,
phaseEnabled: true,
forceMergeEnabled: true,
selectedForceMergeSegments: '1',
bestCompressionEnabled: true,
},
cold: {
...coldPhaseInitialization,
},
delete: { ...defaultNewDeletePhase },
},
});
});
});
Loading