-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Allow opting out of force-merging on a cloned index in ILM's searchable snapshot action #137375
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
63a3c65
Allow opting out of force-merging on a cloned index in ILM's searchab…
nielsbauman 91f74ae
Update docs/changelog/137375.yaml
nielsbauman 9157717
[CI] Auto commit changes from spotless
1c9386d
Add `applies_to` tag to docs
nielsbauman ab5a0f5
Apply copilot suggestion
nielsbauman 0c1188d
[CI] Update transport version definitions
66f7f6b
PR feedback
nielsbauman 6f5081c
Merge branch 'main' into allow-opt-out-ilm
nielsbauman 605795f
[CI] Update transport version definitions
811dabe
Merge branch 'main' into allow-opt-out-ilm
nielsbauman 3521a16
`./gradlew generateTransportVersion`
nielsbauman 77a79ae
Fix transport versions
nielsbauman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| pr: 137375 | ||
| summary: Allow opting out of force-merging on a cloned index in ILM's searchable snapshot | ||
| action | ||
| area: ILM+SLM | ||
| type: enhancement | ||
| issues: [] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
.../main/resources/transport/definitions/referable/ilm_searchable_snapshot_opt_out_clone.csv
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 9206000 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| text_similarity_rank_docs_explain_chunks,9205000 | ||
| ilm_searchable_snapshot_opt_out_clone,9206000 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |
|
|
||
| import org.apache.logging.log4j.LogManager; | ||
| import org.apache.logging.log4j.Logger; | ||
| import org.elasticsearch.TransportVersion; | ||
| import org.elasticsearch.TransportVersions; | ||
| import org.elasticsearch.action.admin.indices.shrink.ResizeType; | ||
| import org.elasticsearch.client.internal.Client; | ||
|
|
@@ -58,6 +59,12 @@ public class SearchableSnapshotAction implements LifecycleAction { | |
| public static final ParseField FORCE_MERGE_INDEX = new ParseField("force_merge_index"); | ||
| public static final ParseField TOTAL_SHARDS_PER_NODE = new ParseField("total_shards_per_node"); | ||
| public static final ParseField REPLICATE_FOR = new ParseField("replicate_for"); | ||
| public static final ParseField FORCE_MERGE_ON_CLONE = new ParseField("force_merge_on_clone"); | ||
|
|
||
| private static final TransportVersion FORCE_MERGE_ON_CLONE_TRANSPORT_VERSION = TransportVersion.fromName( | ||
| "ilm_searchable_snapshot_opt_out_clone" | ||
| ); | ||
|
|
||
| public static final String CONDITIONAL_SKIP_ACTION_STEP = BranchingStep.NAME + "-check-prerequisites"; | ||
| public static final String CONDITIONAL_SKIP_GENERATE_AND_CLEAN = BranchingStep.NAME + "-check-existing-snapshot"; | ||
| public static final String CONDITIONAL_SKIP_CLONE_STEP = BranchingStep.NAME + "-skip-clone-check"; | ||
|
|
@@ -87,7 +94,7 @@ public class SearchableSnapshotAction implements LifecycleAction { | |
|
|
||
| private static final ConstructingObjectParser<SearchableSnapshotAction, Void> PARSER = new ConstructingObjectParser<>( | ||
| NAME, | ||
| a -> new SearchableSnapshotAction((String) a[0], a[1] == null || (boolean) a[1], (Integer) a[2], (TimeValue) a[3]) | ||
| a -> new SearchableSnapshotAction((String) a[0], a[1] == null || (boolean) a[1], (Integer) a[2], (TimeValue) a[3], (Boolean) a[4]) | ||
| ); | ||
|
|
||
| static { | ||
|
|
@@ -100,6 +107,7 @@ public class SearchableSnapshotAction implements LifecycleAction { | |
| REPLICATE_FOR, | ||
| ObjectParser.ValueType.STRING | ||
| ); | ||
| PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), FORCE_MERGE_ON_CLONE); | ||
| } | ||
|
|
||
| public static SearchableSnapshotAction parse(XContentParser parser) { | ||
|
|
@@ -112,12 +120,16 @@ public static SearchableSnapshotAction parse(XContentParser parser) { | |
| private final Integer totalShardsPerNode; | ||
| @Nullable | ||
| private final TimeValue replicateFor; | ||
| /** Opt-out field for forcing the force-merge step to run on the source index instead of a cloned version with 0 replicas. */ | ||
| @Nullable | ||
| private final Boolean forceMergeOnClone; | ||
|
|
||
| public SearchableSnapshotAction( | ||
| String snapshotRepository, | ||
| boolean forceMergeIndex, | ||
| @Nullable Integer totalShardsPerNode, | ||
| @Nullable TimeValue replicateFor | ||
| @Nullable TimeValue replicateFor, | ||
| @Nullable Boolean forceMergeOnClone | ||
| ) { | ||
| if (Strings.hasText(snapshotRepository) == false) { | ||
| throw new IllegalArgumentException("the snapshot repository must be specified"); | ||
|
|
@@ -136,21 +148,31 @@ public SearchableSnapshotAction( | |
| ); | ||
| } | ||
| this.replicateFor = replicateFor; | ||
|
|
||
| if (forceMergeIndex == false && forceMergeOnClone != null) { | ||
| throw new IllegalArgumentException( | ||
| "[" + FORCE_MERGE_ON_CLONE.getPreferredName() + "] is not allowed when [" + FORCE_MERGE_INDEX + "] is [false]" | ||
nielsbauman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ); | ||
| } | ||
| this.forceMergeOnClone = forceMergeOnClone; | ||
| } | ||
|
|
||
| public SearchableSnapshotAction(String snapshotRepository, boolean forceMergeIndex) { | ||
| this(snapshotRepository, forceMergeIndex, null, null); | ||
| this(snapshotRepository, forceMergeIndex, null, null, null); | ||
| } | ||
|
|
||
| public SearchableSnapshotAction(String snapshotRepository) { | ||
| this(snapshotRepository, true, null, null); | ||
| this(snapshotRepository, true, null, null, null); | ||
| } | ||
|
|
||
| public SearchableSnapshotAction(StreamInput in) throws IOException { | ||
| this.snapshotRepository = in.readString(); | ||
| this.forceMergeIndex = in.readBoolean(); | ||
| this.totalShardsPerNode = in.getTransportVersion().onOrAfter(TransportVersions.V_8_16_0) ? in.readOptionalInt() : null; | ||
| this.replicateFor = in.getTransportVersion().supports(TransportVersions.V_8_18_0) ? in.readOptionalTimeValue() : null; | ||
| this.forceMergeOnClone = in.getTransportVersion().supports(FORCE_MERGE_ON_CLONE_TRANSPORT_VERSION) | ||
| ? in.readOptionalBoolean() | ||
| : null; | ||
| } | ||
|
|
||
| public boolean isForceMergeIndex() { | ||
|
|
@@ -171,6 +193,11 @@ public TimeValue getReplicateFor() { | |
| return replicateFor; | ||
| } | ||
|
|
||
| @Nullable | ||
| public Boolean isForceMergeOnClone() { | ||
| return forceMergeOnClone; | ||
| } | ||
|
|
||
| @Override | ||
| public List<Step> toSteps(Client client, String phase, StepKey nextStepKey) { | ||
| assert false; | ||
|
|
@@ -299,9 +326,12 @@ public List<Step> toSteps(Client client, String phase, StepKey nextStepKey, XPac | |
| Instant::now | ||
| ); | ||
|
|
||
| // We force-merge on the clone by default, but allow the user to opt-out of this behavior if there is any reason why they don't want | ||
| // to clone the index (e.g. if something is preventing the cloned index shards from being assigned). | ||
| StepKey keyForForceMerge = shouldForceMergeOnClone() ? conditionalSkipCloneKey : forceMergeStepKey; | ||
| // When generating a snapshot, we either jump to the force merge section, or we skip the | ||
| // forcemerge and go straight to steps for creating the snapshot | ||
| StepKey keyForSnapshotGeneration = forceMergeIndex ? conditionalSkipCloneKey : generateSnapshotNameKey; | ||
| StepKey keyForSnapshotGeneration = forceMergeIndex ? keyForForceMerge : generateSnapshotNameKey; | ||
| // Branch, deciding whether there is an existing searchable snapshot that can be used for mounting the index | ||
| // (in which case, skip generating a new name and the snapshot cleanup), or if we need to generate a new snapshot | ||
| BranchingStep skipGeneratingSnapshotStep = new BranchingStep( | ||
|
|
@@ -529,12 +559,14 @@ public List<Step> toSteps(Client client, String phase, StepKey nextStepKey, XPac | |
| steps.add(waitUntilTimeSeriesEndTimeStep); | ||
| steps.add(skipGeneratingSnapshotStep); | ||
| if (forceMergeIndex) { | ||
| steps.add(conditionalSkipCloneStep); | ||
| steps.add(readOnlyStep); | ||
| steps.add(cleanupClonedIndexStep); | ||
| steps.add(generateCloneIndexNameStep); | ||
| steps.add(cloneIndexStep); | ||
| steps.add(waitForClonedIndexGreenStep); | ||
| if (shouldForceMergeOnClone()) { | ||
| steps.add(conditionalSkipCloneStep); | ||
| steps.add(readOnlyStep); | ||
| steps.add(cleanupClonedIndexStep); | ||
| steps.add(generateCloneIndexNameStep); | ||
| steps.add(cloneIndexStep); | ||
| steps.add(waitForClonedIndexGreenStep); | ||
| } | ||
| steps.add(forceMergeStep); | ||
| steps.add(segmentCountStep); | ||
| } | ||
|
|
@@ -581,6 +613,15 @@ static MountSearchableSnapshotRequest.Storage getConcreteStorageType(StepKey cur | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns whether we should first clone the index and perform the force-merge on that cloned index (true) or force-merge on the | ||
| * original index (false). Defaults to true when {@link #forceMergeOnClone} is null/unspecified. Note that this value is ignored when | ||
| * {@link #forceMergeIndex} is false. | ||
| */ | ||
| private boolean shouldForceMergeOnClone() { | ||
| return forceMergeOnClone == null || forceMergeOnClone; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isSafeAction() { | ||
| return true; | ||
|
|
@@ -601,6 +642,9 @@ public void writeTo(StreamOutput out) throws IOException { | |
| if (out.getTransportVersion().supports(TransportVersions.V_8_18_0)) { | ||
| out.writeOptionalTimeValue(replicateFor); | ||
| } | ||
| if (out.getTransportVersion().supports(FORCE_MERGE_ON_CLONE_TRANSPORT_VERSION)) { | ||
| out.writeOptionalBoolean(forceMergeOnClone); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -614,6 +658,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws | |
| if (replicateFor != null) { | ||
| builder.field(REPLICATE_FOR.getPreferredName(), replicateFor); | ||
| } | ||
| if (forceMergeOnClone != null) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this answers my question from above -- we don't want it in the xcontent if it has not been set explicitly. |
||
| builder.field(FORCE_MERGE_ON_CLONE.getPreferredName(), forceMergeOnClone); | ||
| } | ||
| builder.endObject(); | ||
| return builder; | ||
| } | ||
|
|
@@ -630,12 +677,13 @@ public boolean equals(Object o) { | |
| return Objects.equals(snapshotRepository, that.snapshotRepository) | ||
| && Objects.equals(forceMergeIndex, that.forceMergeIndex) | ||
| && Objects.equals(totalShardsPerNode, that.totalShardsPerNode) | ||
| && Objects.equals(replicateFor, that.replicateFor); | ||
| && Objects.equals(replicateFor, that.replicateFor) | ||
| && Objects.equals(forceMergeOnClone, that.forceMergeOnClone); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(snapshotRepository, forceMergeIndex, totalShardsPerNode, replicateFor); | ||
| return Objects.hash(snapshotRepository, forceMergeIndex, totalShardsPerNode, replicateFor, forceMergeOnClone); | ||
| } | ||
|
|
||
| @Nullable | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't ready through the whole PR yet so I might be missing something, but what if
forceMergeOnCloneis false? We don't want to throw an exception here do we? Is there any reason for forceMergeOnClone to be a Boolean rather than a boolean? Is there any real value in it being able to have 3 states instead of 2?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I was a bit on the fence here. My reason for going with a Boolean was that it better represents what the user actually does (null, false, true). However, we don't currently make a lot of use of that null state, so I don't have super strong feelings on this. If you strongly prefer having a boolean, I'm ok with changing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense with the toXcontent not returning it when null. But is this a bug here that you can't say
force_merge_on_clone: falseandforce_merge_index: false?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah sorry, I forgot to comment on that. I intentionally went with that behavior, as I thought it was cleaner and less confusing if
force_merge_on_cloneis simply not supported whenforce_merge_index: false. It wouldn't have any effect if you were able to specify it, but I think it's confusing to allow configuring fields that are ignored. This way, it's clear that theforce_merge_on_clonefield is not relevant/supported. What are your thoughts?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems a bit odd to me, but it sort of makes sense.