Skip Shrink when numberOfShards not changed (#37953)

Previously, ShrinkAction would fail if
it was executed on an index that had
the same number of shards as the target
shrunken number.

This PR introduced a new BranchingStep that
is used inside of ShrinkAction to branch which
step to move to next, depending on the
shard values. So no shrink will occur if the
shard count is unchanged.
This commit is contained in:
Tal Levy 2019-01-30 15:09:17 -08:00 committed by GitHub
parent b88bdfe958
commit 7c738fd241
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 345 additions and 37 deletions

View File

@ -591,7 +591,7 @@ public class ILMDocumentationIT extends ESRestHighLevelClientTestCase {
{
Map<String, Phase> phases = new HashMap<>();
Map<String, LifecycleAction> warmActions = new HashMap<>();
warmActions.put(ShrinkAction.NAME, new ShrinkAction(1));
warmActions.put(ShrinkAction.NAME, new ShrinkAction(3));
phases.put("warm", new Phase("warm", TimeValue.ZERO, warmActions));
LifecyclePolicy policy = new LifecyclePolicy("my_policy",
@ -602,7 +602,7 @@ public class ILMDocumentationIT extends ESRestHighLevelClientTestCase {
CreateIndexRequest createIndexRequest = new CreateIndexRequest("my_index")
.settings(Settings.builder()
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 2)
.put("index.lifecycle.name", "my_policy")
.build());
client.indices().create(createIndexRequest, RequestOptions.DEFAULT);

View File

@ -0,0 +1,114 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.indexlifecycle;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.util.SetOnce;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.index.Index;
import java.util.Objects;
import java.util.function.BiPredicate;
/**
* This step changes its {@link #getNextStepKey()} depending on the
* outcome of a defined predicate. It performs no changes to the
* cluster state.
*/
public class BranchingStep extends ClusterStateActionStep {
public static final String NAME = "branch";
private static final Logger logger = LogManager.getLogger(BranchingStep.class);
private StepKey nextStepKeyOnFalse;
private StepKey nextStepKeyOnTrue;
private BiPredicate<Index, ClusterState> predicate;
private SetOnce<Boolean> predicateValue;
/**
* {@link BranchingStep} is a step whose next step is based on
* the return value of a specific predicate.
*
* @param key the step's key
* @param nextStepKeyOnFalse the key of the step to run if predicate returns false
* @param nextStepKeyOnTrue the key of the step to run if predicate returns true
* @param predicate the condition to check when deciding which step to run next
*/
public BranchingStep(StepKey key, StepKey nextStepKeyOnFalse, StepKey nextStepKeyOnTrue, BiPredicate<Index, ClusterState> predicate) {
// super.nextStepKey is set to null since it is not used by this step
super(key, null);
this.nextStepKeyOnFalse = nextStepKeyOnFalse;
this.nextStepKeyOnTrue = nextStepKeyOnTrue;
this.predicate = predicate;
this.predicateValue = new SetOnce<>();
}
@Override
public ClusterState performAction(Index index, ClusterState clusterState) {
IndexMetaData indexMetaData = clusterState.metaData().index(index);
if (indexMetaData == null) {
// Index must have been since deleted, ignore it
logger.debug("[{}] lifecycle action for index [{}] executed but index no longer exists", getKey().getAction(), index.getName());
return clusterState;
}
predicateValue.set(predicate.test(index, clusterState));
return clusterState;
}
/**
* This method returns the next step to execute based on the predicate. If
* the predicate returned true, then nextStepKeyOnTrue is the key of the
* next step to run, otherwise nextStepKeyOnFalse is.
*
* throws {@link UnsupportedOperationException} if performAction was not called yet
*
* @return next step to execute
*/
@Override
public final StepKey getNextStepKey() {
if (predicateValue.get() == null) {
throw new IllegalStateException("Cannot call getNextStepKey before performAction");
}
return predicateValue.get() ? nextStepKeyOnTrue : nextStepKeyOnFalse;
}
/**
* @return the next step if {@code predicate} is false
*/
final StepKey getNextStepKeyOnFalse() {
return nextStepKeyOnFalse;
}
/**
* @return the next step if {@code predicate} is true
*/
final StepKey getNextStepKeyOnTrue() {
return nextStepKeyOnTrue;
}
public final BiPredicate<Index, ClusterState> getPredicate() {
return predicate;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BranchingStep that = (BranchingStep) o;
return super.equals(o)
&& Objects.equals(nextStepKeyOnFalse, that.nextStepKeyOnFalse)
&& Objects.equals(nextStepKeyOnTrue, that.nextStepKeyOnTrue);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), nextStepKeyOnFalse, nextStepKeyOnTrue);
}
}

View File

@ -85,6 +85,7 @@ public class ShrinkAction implements LifecycleAction {
public List<Step> toSteps(Client client, String phase, Step.StepKey nextStepKey) {
Settings readOnlySettings = Settings.builder().put(IndexMetaData.SETTING_BLOCKS_WRITE, true).build();
StepKey branchingKey = new StepKey(phase, NAME, BranchingStep.NAME);
StepKey readOnlyKey = new StepKey(phase, NAME, ReadOnlyAction.NAME);
StepKey setSingleNodeKey = new StepKey(phase, NAME, SetSingleNodeAllocateStep.NAME);
StepKey allocationRoutedKey = new StepKey(phase, NAME, CheckShrinkReadyStep.NAME);
@ -94,6 +95,8 @@ public class ShrinkAction implements LifecycleAction {
StepKey aliasKey = new StepKey(phase, NAME, ShrinkSetAliasStep.NAME);
StepKey isShrunkIndexKey = new StepKey(phase, NAME, ShrunkenIndexCheckStep.NAME);
BranchingStep conditionalSkipShrinkStep = new BranchingStep(branchingKey, readOnlyKey, nextStepKey,
(index, clusterState) -> clusterState.getMetaData().index(index).getNumberOfShards() == numberOfShards);
UpdateSettingsStep readOnlyStep = new UpdateSettingsStep(readOnlyKey, setSingleNodeKey, client, readOnlySettings);
SetSingleNodeAllocateStep setSingleNodeStep = new SetSingleNodeAllocateStep(setSingleNodeKey, allocationRoutedKey, client);
CheckShrinkReadyStep checkShrinkReadyStep = new CheckShrinkReadyStep(allocationRoutedKey, shrinkKey);
@ -102,12 +105,13 @@ public class ShrinkAction implements LifecycleAction {
CopyExecutionStateStep copyMetadata = new CopyExecutionStateStep(copyMetadataKey, aliasKey, SHRUNKEN_INDEX_PREFIX);
ShrinkSetAliasStep aliasSwapAndDelete = new ShrinkSetAliasStep(aliasKey, isShrunkIndexKey, client, SHRUNKEN_INDEX_PREFIX);
ShrunkenIndexCheckStep waitOnShrinkTakeover = new ShrunkenIndexCheckStep(isShrunkIndexKey, nextStepKey, SHRUNKEN_INDEX_PREFIX);
return Arrays.asList(readOnlyStep, setSingleNodeStep, checkShrinkReadyStep, shrink, allocated, copyMetadata,
aliasSwapAndDelete, waitOnShrinkTakeover);
return Arrays.asList(conditionalSkipShrinkStep, readOnlyStep, setSingleNodeStep, checkShrinkReadyStep, shrink, allocated,
copyMetadata, aliasSwapAndDelete, waitOnShrinkTakeover);
}
@Override
public List<StepKey> toStepKeys(String phase) {
StepKey conditionalSkipKey = new StepKey(phase, NAME, BranchingStep.NAME);
StepKey readOnlyKey = new StepKey(phase, NAME, ReadOnlyAction.NAME);
StepKey setSingleNodeKey = new StepKey(phase, NAME, SetSingleNodeAllocateStep.NAME);
StepKey checkShrinkReadyKey = new StepKey(phase, NAME, CheckShrinkReadyStep.NAME);
@ -116,7 +120,7 @@ public class ShrinkAction implements LifecycleAction {
StepKey copyMetadataKey = new StepKey(phase, NAME, CopyExecutionStateStep.NAME);
StepKey aliasKey = new StepKey(phase, NAME, ShrinkSetAliasStep.NAME);
StepKey isShrunkIndexKey = new StepKey(phase, NAME, ShrunkenIndexCheckStep.NAME);
return Arrays.asList(readOnlyKey, setSingleNodeKey, checkShrinkReadyKey, shrinkKey, enoughShardsKey,
return Arrays.asList(conditionalSkipKey, readOnlyKey, setSingleNodeKey, checkShrinkReadyKey, shrinkKey, enoughShardsKey,
copyMetadataKey, aliasKey, isShrunkIndexKey);
}

View File

@ -34,7 +34,7 @@ public abstract class Step {
return key;
}
public final StepKey getNextStepKey() {
public StepKey getNextStepKey() {
return nextStepKey;
}

View File

@ -0,0 +1,85 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.indexlifecycle;
import org.apache.lucene.util.SetOnce;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.index.Index;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
import java.util.function.BiPredicate;
import static org.hamcrest.Matchers.equalTo;
public class BranchingStepTests extends AbstractStepTestCase<BranchingStep> {
public void testPredicateNextStepChange() {
String indexName = randomAlphaOfLength(5);
ClusterState state = ClusterState.builder(ClusterName.DEFAULT).metaData(MetaData.builder()
.put(IndexMetaData.builder(indexName).settings(settings(Version.CURRENT))
.numberOfShards(1).numberOfReplicas(0))).build();
StepKey stepKey = new StepKey(randomAlphaOfLength(5), randomAlphaOfLength(5), BranchingStep.NAME);
StepKey nextStepKey = new StepKey(randomAlphaOfLength(6), randomAlphaOfLength(6), BranchingStep.NAME);
StepKey nextSkipKey = new StepKey(randomAlphaOfLength(7), randomAlphaOfLength(7), BranchingStep.NAME);
{
BranchingStep step = new BranchingStep(stepKey, nextStepKey, nextSkipKey, (i, c) -> true);
expectThrows(IllegalStateException.class, step::getNextStepKey);
step.performAction(state.metaData().index(indexName).getIndex(), state);
assertThat(step.getNextStepKey(), equalTo(step.getNextStepKeyOnTrue()));
expectThrows(SetOnce.AlreadySetException.class, () -> step.performAction(state.metaData().index(indexName).getIndex(), state));
}
{
BranchingStep step = new BranchingStep(stepKey, nextStepKey, nextSkipKey, (i, c) -> false);
expectThrows(IllegalStateException.class, step::getNextStepKey);
step.performAction(state.metaData().index(indexName).getIndex(), state);
assertThat(step.getNextStepKey(), equalTo(step.getNextStepKeyOnFalse()));
expectThrows(SetOnce.AlreadySetException.class, () -> step.performAction(state.metaData().index(indexName).getIndex(), state));
}
}
@Override
public BranchingStep createRandomInstance() {
StepKey stepKey = new StepKey(randomAlphaOfLength(5), randomAlphaOfLength(5), BranchingStep.NAME);
StepKey nextStepKey = new StepKey(randomAlphaOfLength(6), randomAlphaOfLength(6), BranchingStep.NAME);
StepKey nextSkipKey = new StepKey(randomAlphaOfLength(7), randomAlphaOfLength(7), BranchingStep.NAME);
return new BranchingStep(stepKey, nextStepKey, nextSkipKey, (i, c) -> randomBoolean());
}
@Override
public BranchingStep mutateInstance(BranchingStep instance) {
StepKey key = instance.getKey();
StepKey nextStepKey = instance.getNextStepKeyOnFalse();
StepKey nextSkipStepKey = instance.getNextStepKeyOnTrue();
BiPredicate<Index, ClusterState> predicate = instance.getPredicate();
switch (between(0, 2)) {
case 0:
key = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
break;
case 1:
nextStepKey = new StepKey(nextStepKey.getPhase(), nextStepKey.getAction(), nextStepKey.getName() + randomAlphaOfLength(5));
break;
case 2:
nextSkipStepKey = new StepKey(nextSkipStepKey.getPhase(), nextSkipStepKey.getAction(),
nextSkipStepKey.getName() + randomAlphaOfLength(5));
break;
default:
throw new AssertionError("Illegal randomisation branch");
}
return new BranchingStep(key, nextStepKey, nextSkipStepKey, predicate);
}
@Override
public BranchingStep copyInstance(BranchingStep instance) {
return new BranchingStep(instance.getKey(), instance.getNextStepKeyOnFalse(), instance.getNextStepKeyOnTrue(),
instance.getPredicate());
}
}

View File

@ -5,12 +5,18 @@
*/
package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import static org.hamcrest.Matchers.equalTo;
@ -46,59 +52,134 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
assertThat(e.getMessage(), equalTo("[number_of_shards] must be greater than 0"));
}
public void testPerformActionWithSkip() {
String lifecycleName = randomAlphaOfLengthBetween(4, 10);
int numberOfShards = randomIntBetween(1, 10);
ShrinkAction action = new ShrinkAction(numberOfShards);
String phase = randomAlphaOfLengthBetween(1, 10);
StepKey nextStepKey = new StepKey(randomAlphaOfLengthBetween(1, 10), randomAlphaOfLengthBetween(1, 10),
randomAlphaOfLengthBetween(1, 10));
List<Step> steps = action.toSteps(null, phase, nextStepKey);
BranchingStep step = ((BranchingStep) steps.get(0));
LifecyclePolicy policy = new LifecyclePolicy(lifecycleName, Collections.singletonMap("warm",
new Phase("warm", TimeValue.ZERO, Collections.singletonMap(action.getWriteableName(), action))));
LifecyclePolicyMetadata policyMetadata = new LifecyclePolicyMetadata(policy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong());
String indexName = randomAlphaOfLength(5);
ClusterState state = ClusterState.builder(ClusterName.DEFAULT).metaData(MetaData.builder()
.putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(
Collections.singletonMap(policyMetadata.getName(), policyMetadata), OperationMode.RUNNING))
.put(IndexMetaData.builder(indexName).settings(settings(Version.CURRENT).put(LifecycleSettings.LIFECYCLE_NAME, lifecycleName))
.putCustom(LifecycleExecutionState.ILM_CUSTOM_METADATA_KEY,
LifecycleExecutionState.builder()
.setPhase(step.getKey().getPhase())
.setPhaseTime(0L)
.setAction(step.getKey().getAction())
.setActionTime(0L)
.setStep(step.getKey().getName())
.setStepTime(0L)
.build().asMap())
.numberOfShards(numberOfShards).numberOfReplicas(0))).build();
step.performAction(state.metaData().index(indexName).getIndex(), state);
assertThat(step.getNextStepKey(), equalTo(nextStepKey));
}
public void testPerformActionWithoutSkip() {
int numShards = 6;
int divisor = randomFrom(2, 3, 6);
int expectedFinalShards = numShards / divisor;
String lifecycleName = randomAlphaOfLengthBetween(4, 10);
ShrinkAction action = new ShrinkAction(expectedFinalShards);
String phase = randomAlphaOfLengthBetween(1, 10);
StepKey nextStepKey = new StepKey(randomAlphaOfLengthBetween(1, 10), randomAlphaOfLengthBetween(1, 10),
randomAlphaOfLengthBetween(1, 10));
List<Step> steps = action.toSteps(null, phase, nextStepKey);
BranchingStep step = ((BranchingStep) steps.get(0));
LifecyclePolicy policy = new LifecyclePolicy(lifecycleName, Collections.singletonMap("warm",
new Phase("warm", TimeValue.ZERO, Collections.singletonMap(action.getWriteableName(), action))));
LifecyclePolicyMetadata policyMetadata = new LifecyclePolicyMetadata(policy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong());
String indexName = randomAlphaOfLength(5);
ClusterState state = ClusterState.builder(ClusterName.DEFAULT).metaData(MetaData.builder()
.putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(
Collections.singletonMap(policyMetadata.getName(), policyMetadata), OperationMode.RUNNING))
.put(IndexMetaData.builder(indexName).settings(settings(Version.CURRENT).put(LifecycleSettings.LIFECYCLE_NAME, lifecycleName))
.putCustom(LifecycleExecutionState.ILM_CUSTOM_METADATA_KEY,
LifecycleExecutionState.builder()
.setPhase(step.getKey().getPhase())
.setPhaseTime(0L)
.setAction(step.getKey().getAction())
.setActionTime(0L)
.setStep(step.getKey().getName())
.setStepTime(0L)
.build().asMap())
.numberOfShards(numShards).numberOfReplicas(0))).build();
ClusterState newState = step.performAction(state.metaData().index(indexName).getIndex(), state);
assertThat(step.getNextStepKey(), equalTo(steps.get(1).getKey()));
}
public void testToSteps() {
ShrinkAction action = createTestInstance();
String phase = randomAlphaOfLengthBetween(1, 10);
StepKey nextStepKey = new StepKey(randomAlphaOfLengthBetween(1, 10), randomAlphaOfLengthBetween(1, 10),
randomAlphaOfLengthBetween(1, 10));
List<Step> steps = action.toSteps(null, phase, nextStepKey);
assertThat(steps.size(), equalTo(8));
StepKey expectedFirstKey = new StepKey(phase, ShrinkAction.NAME, ReadOnlyAction.NAME);
StepKey expectedSecondKey = new StepKey(phase, ShrinkAction.NAME, SetSingleNodeAllocateStep.NAME);
StepKey expectedThirdKey = new StepKey(phase, ShrinkAction.NAME, CheckShrinkReadyStep.NAME);
StepKey expectedFourthKey = new StepKey(phase, ShrinkAction.NAME, ShrinkStep.NAME);
StepKey expectedFifthKey = new StepKey(phase, ShrinkAction.NAME, ShrunkShardsAllocatedStep.NAME);
StepKey expectedSixthKey = new StepKey(phase, ShrinkAction.NAME, CopyExecutionStateStep.NAME);
StepKey expectedSeventhKey = new StepKey(phase, ShrinkAction.NAME, ShrinkSetAliasStep.NAME);
StepKey expectedEighthKey = new StepKey(phase, ShrinkAction.NAME, ShrunkenIndexCheckStep.NAME);
assertThat(steps.size(), equalTo(9));
StepKey expectedFirstKey = new StepKey(phase, ShrinkAction.NAME, BranchingStep.NAME);
StepKey expectedSecondKey = new StepKey(phase, ShrinkAction.NAME, ReadOnlyAction.NAME);
StepKey expectedThirdKey = new StepKey(phase, ShrinkAction.NAME, SetSingleNodeAllocateStep.NAME);
StepKey expectedFourthKey = new StepKey(phase, ShrinkAction.NAME, CheckShrinkReadyStep.NAME);
StepKey expectedFifthKey = new StepKey(phase, ShrinkAction.NAME, ShrinkStep.NAME);
StepKey expectedSixthKey = new StepKey(phase, ShrinkAction.NAME, ShrunkShardsAllocatedStep.NAME);
StepKey expectedSeventhKey = new StepKey(phase, ShrinkAction.NAME, CopyExecutionStateStep.NAME);
StepKey expectedEighthKey = new StepKey(phase, ShrinkAction.NAME, ShrinkSetAliasStep.NAME);
StepKey expectedNinthKey = new StepKey(phase, ShrinkAction.NAME, ShrunkenIndexCheckStep.NAME);
assertTrue(steps.get(0) instanceof UpdateSettingsStep);
assertTrue(steps.get(0) instanceof BranchingStep);
assertThat(steps.get(0).getKey(), equalTo(expectedFirstKey));
assertThat(steps.get(0).getNextStepKey(), equalTo(expectedSecondKey));
assertTrue(IndexMetaData.INDEX_BLOCKS_WRITE_SETTING.get(((UpdateSettingsStep)steps.get(0)).getSettings()));
expectThrows(IllegalStateException.class, () -> steps.get(0).getNextStepKey());
assertThat(((BranchingStep) steps.get(0)).getNextStepKeyOnFalse(), equalTo(expectedSecondKey));
assertThat(((BranchingStep) steps.get(0)).getNextStepKeyOnTrue(), equalTo(nextStepKey));
assertTrue(steps.get(1) instanceof SetSingleNodeAllocateStep);
assertTrue(steps.get(1) instanceof UpdateSettingsStep);
assertThat(steps.get(1).getKey(), equalTo(expectedSecondKey));
assertThat(steps.get(1).getNextStepKey(), equalTo(expectedThirdKey));
assertTrue(IndexMetaData.INDEX_BLOCKS_WRITE_SETTING.get(((UpdateSettingsStep)steps.get(1)).getSettings()));
assertTrue(steps.get(2) instanceof CheckShrinkReadyStep);
assertTrue(steps.get(2) instanceof SetSingleNodeAllocateStep);
assertThat(steps.get(2).getKey(), equalTo(expectedThirdKey));
assertThat(steps.get(2).getNextStepKey(), equalTo(expectedFourthKey));
assertTrue(steps.get(3) instanceof ShrinkStep);
assertTrue(steps.get(3) instanceof CheckShrinkReadyStep);
assertThat(steps.get(3).getKey(), equalTo(expectedFourthKey));
assertThat(steps.get(3).getNextStepKey(), equalTo(expectedFifthKey));
assertThat(((ShrinkStep) steps.get(3)).getShrunkIndexPrefix(), equalTo(ShrinkAction.SHRUNKEN_INDEX_PREFIX));
assertTrue(steps.get(4) instanceof ShrunkShardsAllocatedStep);
assertTrue(steps.get(4) instanceof ShrinkStep);
assertThat(steps.get(4).getKey(), equalTo(expectedFifthKey));
assertThat(steps.get(4).getNextStepKey(), equalTo(expectedSixthKey));
assertThat(((ShrunkShardsAllocatedStep) steps.get(4)).getShrunkIndexPrefix(), equalTo(ShrinkAction.SHRUNKEN_INDEX_PREFIX));
assertThat(((ShrinkStep) steps.get(4)).getShrunkIndexPrefix(), equalTo(ShrinkAction.SHRUNKEN_INDEX_PREFIX));
assertTrue(steps.get(5) instanceof CopyExecutionStateStep);
assertTrue(steps.get(5) instanceof ShrunkShardsAllocatedStep);
assertThat(steps.get(5).getKey(), equalTo(expectedSixthKey));
assertThat(steps.get(5).getNextStepKey(), equalTo(expectedSeventhKey));
assertThat(((CopyExecutionStateStep) steps.get(5)).getShrunkIndexPrefix(), equalTo(ShrinkAction.SHRUNKEN_INDEX_PREFIX));
assertThat(((ShrunkShardsAllocatedStep) steps.get(5)).getShrunkIndexPrefix(), equalTo(ShrinkAction.SHRUNKEN_INDEX_PREFIX));
assertTrue(steps.get(6) instanceof ShrinkSetAliasStep);
assertTrue(steps.get(6) instanceof CopyExecutionStateStep);
assertThat(steps.get(6).getKey(), equalTo(expectedSeventhKey));
assertThat(steps.get(6).getNextStepKey(), equalTo(expectedEighthKey));
assertThat(((ShrinkSetAliasStep) steps.get(6)).getShrunkIndexPrefix(), equalTo(ShrinkAction.SHRUNKEN_INDEX_PREFIX));
assertThat(((CopyExecutionStateStep) steps.get(6)).getShrunkIndexPrefix(), equalTo(ShrinkAction.SHRUNKEN_INDEX_PREFIX));
assertTrue(steps.get(7) instanceof ShrunkenIndexCheckStep);
assertTrue(steps.get(7) instanceof ShrinkSetAliasStep);
assertThat(steps.get(7).getKey(), equalTo(expectedEighthKey));
assertThat(steps.get(7).getNextStepKey(), equalTo(nextStepKey));
assertThat(((ShrunkenIndexCheckStep) steps.get(7)).getShrunkIndexPrefix(), equalTo(ShrinkAction.SHRUNKEN_INDEX_PREFIX));
assertThat(steps.get(7).getNextStepKey(), equalTo(expectedNinthKey));
assertThat(((ShrinkSetAliasStep) steps.get(7)).getShrunkIndexPrefix(), equalTo(ShrinkAction.SHRUNKEN_INDEX_PREFIX));
assertTrue(steps.get(8) instanceof ShrunkenIndexCheckStep);
assertThat(steps.get(8).getKey(), equalTo(expectedNinthKey));
assertThat(steps.get(8).getNextStepKey(), equalTo(nextStepKey));
assertThat(((ShrunkenIndexCheckStep) steps.get(8)).getShrunkIndexPrefix(), equalTo(ShrinkAction.SHRUNKEN_INDEX_PREFIX));
}
@Override

View File

@ -466,6 +466,24 @@ public class TimeSeriesLifecycleActionsIT extends ESRestTestCase {
expectThrows(ResponseException.class, this::indexDocument);
}
public void testShrinkSameShards() throws Exception {
int numberOfShards = randomFrom(1, 2);
String shrunkenIndex = ShrinkAction.SHRUNKEN_INDEX_PREFIX + index;
createIndexWithSettings(index, Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, numberOfShards)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0));
createNewSingletonPolicy("warm", new ShrinkAction(numberOfShards));
updatePolicy(index, policy);
assertBusy(() -> {
assertTrue(indexExists(index));
assertFalse(indexExists(shrunkenIndex));
assertFalse(aliasExists(shrunkenIndex, index));
Map<String, Object> settings = getOnlyIndexSettings(index);
assertThat(getStepKeyForIndex(index), equalTo(TerminalPolicyStep.KEY));
assertThat(settings.get(IndexMetaData.SETTING_NUMBER_OF_SHARDS), equalTo(String.valueOf(numberOfShards)));
assertNull(settings.get(IndexMetaData.INDEX_BLOCKS_WRITE_SETTING.getKey()));
});
}
public void testShrinkDuringSnapshot() throws Exception {
String shrunkenIndex = ShrinkAction.SHRUNKEN_INDEX_PREFIX + index;
// Create the repository before taking the snapshot.

View File

@ -86,24 +86,30 @@ public class ExecuteStepsUpdateTask extends ClusterStateUpdateTask {
// either get to a step that isn't a cluster state step or a
// cluster state wait step returns not completed
while (currentStep instanceof ClusterStateActionStep || currentStep instanceof ClusterStateWaitStep) {
nextStepKey = currentStep.getNextStepKey();
if (currentStep instanceof ClusterStateActionStep) {
// cluster state action step so do the action and
// move the cluster state to the next step
logger.trace("[{}] performing cluster state action ({}) [{}], next: [{}]",
index.getName(), currentStep.getClass().getSimpleName(), currentStep.getKey(), currentStep.getNextStepKey());
logger.trace("[{}] performing cluster state action ({}) [{}]",
index.getName(), currentStep.getClass().getSimpleName(), currentStep.getKey());
try {
state = ((ClusterStateActionStep) currentStep).performAction(index, state);
} catch (Exception exception) {
return moveToErrorStep(state, currentStep.getKey(), exception);
}
if (currentStep.getNextStepKey() == null) {
// set here to make sure that the clusterProcessed knows to execute the
// correct step if it an async action
nextStepKey = currentStep.getNextStepKey();
if (nextStepKey == null) {
return state;
} else {
logger.trace("[{}] moving cluster state to next step [{}]", index.getName(), nextStepKey);
state = IndexLifecycleRunner.moveClusterStateToNextStep(index, state, currentStep.getKey(),
currentStep.getNextStepKey(), nowSupplier, false);
nextStepKey, nowSupplier, false);
}
} else {
// set here to make sure that the clusterProcessed knows to execute the
// correct step if it an async action
nextStepKey = currentStep.getNextStepKey();
// cluster state wait step so evaluate the
// condition, if the condition is met move to the
// next step, if its not met return the current

View File

@ -268,7 +268,7 @@ public class ExecuteStepsUpdateTaskTests extends ESTestCase {
assertThat(currentStepKey, equalTo(new StepKey(firstStepKey.getPhase(), firstStepKey.getAction(), ErrorStep.NAME)));
assertThat(firstStep.getExecuteCount(), equalTo(1L));
assertThat(secondStep.getExecuteCount(), equalTo(0L));
assertThat(task.getNextStepKey(), equalTo(secondStep.getKey()));
assertNull(task.getNextStepKey());
assertThat(lifecycleState.getPhaseTime(), nullValue());
assertThat(lifecycleState.getActionTime(), nullValue());
assertThat(lifecycleState.getStepInfo(),