Skip to content

Commit 699f4cf

Browse files
authored
Refactor ShrinkStep to ResizeStep (#133591)
By making the step more generic, we can reuse it in other actions (such as the upcoming improved force merge action).
1 parent eb75ba3 commit 699f4cf

File tree

10 files changed

+266
-196
lines changed

10 files changed

+266
-196
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/OperationMode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public boolean isValidChange(OperationMode nextMode) {
2222
},
2323

2424
/**
25-
* this represents a state where only sensitive actions (like {@link ShrinkStep}) will be executed
25+
* this represents a state where only sensitive actions (like {@link ResizeIndexStep}) will be executed
2626
* until they finish, at which point the operation mode will move to <code>STOPPED</code>.
2727
*/
2828
STOPPING {
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
package org.elasticsearch.xpack.core.ilm;
8+
9+
import org.apache.logging.log4j.LogManager;
10+
import org.apache.logging.log4j.Logger;
11+
import org.elasticsearch.action.ActionListener;
12+
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
13+
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
14+
import org.elasticsearch.client.internal.Client;
15+
import org.elasticsearch.cluster.ClusterStateObserver;
16+
import org.elasticsearch.cluster.ProjectState;
17+
import org.elasticsearch.cluster.metadata.IndexMetadata;
18+
import org.elasticsearch.cluster.metadata.LifecycleExecutionState;
19+
import org.elasticsearch.common.settings.Settings;
20+
import org.elasticsearch.common.unit.ByteSizeValue;
21+
import org.elasticsearch.core.Nullable;
22+
import org.elasticsearch.core.TimeValue;
23+
24+
import java.util.Objects;
25+
import java.util.function.BiFunction;
26+
import java.util.function.Function;
27+
28+
/**
29+
* Resizes an index with the specified settings, using the name that was generated in a previous {@link GenerateUniqueIndexNameStep} step.
30+
*/
31+
public class ResizeIndexStep extends AsyncActionStep {
32+
33+
public static final String SHRINK = "shrink";
34+
public static final String CLONE = "clone";
35+
private static final Logger logger = LogManager.getLogger(ResizeIndexStep.class);
36+
37+
private final ResizeType resizeType;
38+
private final BiFunction<String, LifecycleExecutionState, String> targetIndexNameSupplier;
39+
/** A supplier that takes the index metadata of the <i>original</i> index and returns settings for the target index . */
40+
private final Function<IndexMetadata, Settings> targetIndexSettingsSupplier;
41+
@Nullable
42+
private final ByteSizeValue maxPrimaryShardSize;
43+
44+
public ResizeIndexStep(
45+
StepKey key,
46+
StepKey nextStepKey,
47+
Client client,
48+
ResizeType resizeType,
49+
BiFunction<String, LifecycleExecutionState, String> targetIndexNameSupplier,
50+
Function<IndexMetadata, Settings> targetIndexSettingsSupplier,
51+
@Nullable ByteSizeValue maxPrimaryShardSize
52+
) {
53+
super(key, nextStepKey, client);
54+
this.resizeType = resizeType;
55+
this.targetIndexNameSupplier = targetIndexNameSupplier;
56+
this.targetIndexSettingsSupplier = targetIndexSettingsSupplier;
57+
this.maxPrimaryShardSize = maxPrimaryShardSize;
58+
assert resizeType == ResizeType.SHRINK || maxPrimaryShardSize == null : "maxPrimaryShardSize can only be set for shrink operations";
59+
}
60+
61+
@Override
62+
public boolean isRetryable() {
63+
return true;
64+
}
65+
66+
@Override
67+
public void performAction(
68+
IndexMetadata indexMetadata,
69+
ProjectState currentState,
70+
ClusterStateObserver observer,
71+
ActionListener<Void> listener
72+
) {
73+
LifecycleExecutionState lifecycleState = indexMetadata.getLifecycleExecutionState();
74+
if (lifecycleState.lifecycleDate() == null) {
75+
throw new IllegalStateException("source index [" + indexMetadata.getIndex().getName() + "] is missing lifecycle date");
76+
}
77+
78+
final String targetIndexName = targetIndexNameSupplier.apply(indexMetadata.getIndex().getName(), lifecycleState);
79+
if (currentState.metadata().index(targetIndexName) != null) {
80+
logger.warn(
81+
"skipping [{}] step for index [{}] as part of policy [{}] as the target index [{}] already exists",
82+
getKey().name(),
83+
indexMetadata.getIndex().getName(),
84+
indexMetadata.getLifecyclePolicyName(),
85+
targetIndexName
86+
);
87+
listener.onResponse(null);
88+
return;
89+
}
90+
91+
Settings relevantTargetSettings = Settings.builder()
92+
.put(targetIndexSettingsSupplier.apply(indexMetadata))
93+
// We add the skip setting to prevent ILM from processing the shrunken index before the execution state has been copied - which
94+
// could happen if the shards of the shrunken index take a long time to allocate.
95+
.put(LifecycleSettings.LIFECYCLE_SKIP, true)
96+
.build();
97+
98+
ResizeRequest resizeRequest = new ResizeRequest(targetIndexName, indexMetadata.getIndex().getName()).masterNodeTimeout(
99+
TimeValue.MAX_VALUE
100+
);
101+
resizeRequest.setResizeType(resizeType);
102+
resizeRequest.getTargetIndexRequest().settings(relevantTargetSettings);
103+
if (resizeType == ResizeType.SHRINK) {
104+
resizeRequest.setMaxPrimaryShardSize(maxPrimaryShardSize);
105+
}
106+
107+
// This request does not wait for (successful) completion of the resize operation - it fires-and-forgets.
108+
// It's up to a subsequent step to check for the existence of the target index and wait for it to be green.
109+
getClient(currentState.projectId()).admin()
110+
.indices()
111+
.resizeIndex(resizeRequest, listener.delegateFailureAndWrap((l, response) -> l.onResponse(null)));
112+
113+
}
114+
115+
public ResizeType getResizeType() {
116+
return resizeType;
117+
}
118+
119+
public BiFunction<String, LifecycleExecutionState, String> getTargetIndexNameSupplier() {
120+
return targetIndexNameSupplier;
121+
}
122+
123+
public Function<IndexMetadata, Settings> getTargetIndexSettingsSupplier() {
124+
return targetIndexSettingsSupplier;
125+
}
126+
127+
public ByteSizeValue getMaxPrimaryShardSize() {
128+
return maxPrimaryShardSize;
129+
}
130+
131+
@Override
132+
public int hashCode() {
133+
return Objects.hash(super.hashCode(), resizeType, maxPrimaryShardSize);
134+
}
135+
136+
@Override
137+
public boolean equals(Object obj) {
138+
if (obj == null) {
139+
return false;
140+
}
141+
if (getClass() != obj.getClass()) {
142+
return false;
143+
}
144+
ResizeIndexStep other = (ResizeIndexStep) obj;
145+
return super.equals(obj)
146+
&& Objects.equals(resizeType, other.resizeType)
147+
&& Objects.equals(maxPrimaryShardSize, other.maxPrimaryShardSize);
148+
}
149+
150+
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkAction.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.apache.logging.log4j.Logger;
1111
import org.elasticsearch.TransportVersions;
1212
import org.elasticsearch.action.admin.indices.shrink.ResizeNumberOfShardsCalculator;
13+
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
1314
import org.elasticsearch.action.admin.indices.stats.IndexShardStats;
1415
import org.elasticsearch.client.internal.Client;
1516
import org.elasticsearch.cluster.metadata.IndexAbstraction;
@@ -173,7 +174,7 @@ public List<Step> toSteps(Client client, String phase, Step.StepKey nextStepKey)
173174
StepKey generateShrinkIndexNameKey = new StepKey(phase, NAME, GenerateUniqueIndexNameStep.NAME);
174175
StepKey setSingleNodeKey = new StepKey(phase, NAME, SetSingleNodeAllocateStep.NAME);
175176
StepKey allocationRoutedKey = new StepKey(phase, NAME, CheckShrinkReadyStep.NAME);
176-
StepKey shrinkKey = new StepKey(phase, NAME, ShrinkStep.NAME);
177+
StepKey shrinkKey = new StepKey(phase, NAME, ResizeIndexStep.SHRINK);
177178
StepKey enoughShardsKey = new StepKey(phase, NAME, ShrunkShardsAllocatedStep.NAME);
178179
StepKey copyMetadataKey = new StepKey(phase, NAME, CopyExecutionStateStep.NAME);
179180
StepKey dataStreamCheckBranchingKey = new StepKey(phase, NAME, CONDITIONAL_DATASTREAM_CHECK_KEY);
@@ -267,7 +268,24 @@ public List<Step> toSteps(Client client, String phase, Step.StepKey nextStepKey)
267268
new CheckShrinkReadyStep(allocationRoutedKey, shrinkKey),
268269
setSingleNodeKey
269270
);
270-
ShrinkStep shrink = new ShrinkStep(shrinkKey, enoughShardsKey, client, numberOfShards, maxPrimaryShardSize);
271+
ResizeIndexStep shrink = new ResizeIndexStep(
272+
shrinkKey,
273+
enoughShardsKey,
274+
client,
275+
ResizeType.SHRINK,
276+
ShrinkIndexNameSupplier::getShrinkIndexName,
277+
indexMetadata -> {
278+
Settings.Builder settingsBuilder = Settings.builder()
279+
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, indexMetadata.getNumberOfReplicas())
280+
// We need to remove the single node allocation so replicas can be allocated.
281+
.put(IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + "_id", (String) null);
282+
if (numberOfShards != null) {
283+
settingsBuilder.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, numberOfShards);
284+
}
285+
return settingsBuilder.build();
286+
},
287+
maxPrimaryShardSize
288+
);
271289
// wait until the shrunk index is recovered. we again wait until the configured threshold is breached and if the shrunk index has
272290
// not successfully recovered until then, we rewind to the "cleanup-shrink-index" step to delete this unsuccessful shrunk index
273291
// and retry the operation by generating a new shrink index name and attempting to shrink again

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkStep.java

Lines changed: 0 additions & 129 deletions
This file was deleted.

0 commit comments

Comments
 (0)