From bd209df95234e6ffd14f5d72597cc5c8926a62b6 Mon Sep 17 00:00:00 2001 From: Niels Bauman Date: Thu, 21 Aug 2025 15:44:07 +0200 Subject: [PATCH 1/4] Refactor `CleanupShrinkIndexStep` to `CleanupGeneratedIndexStep` By making the step more generic, we can reuse it in other actions (such as the upcoming improved force merge action). We ensure that indices that are in this cleanup step while the cluster upgrades to this version, are still able to progress seamlessly by registering the old step name as a `NoopStep` and forwarding them to the new cleanup step name. --- ...ep.java => CleanupGeneratedIndexStep.java} | 53 ++++-- .../xpack/core/ilm/ShrinkAction.java | 11 +- ...va => CleanupGeneratedIndexStepTests.java} | 30 ++- .../xpack/core/ilm/ShrinkActionTests.java | 175 +++++++++--------- 4 files changed, 152 insertions(+), 117 deletions(-) rename x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/{CleanupShrinkIndexStep.java => CleanupGeneratedIndexStep.java} (61%) rename x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/{CleanupShrinkIndexStepTests.java => CleanupGeneratedIndexStepTests.java} (84%) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupShrinkIndexStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java similarity index 61% rename from x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupShrinkIndexStep.java rename to x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java index c93dab7cdc2fa..bc90d18c9ec68 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupShrinkIndexStep.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java @@ -19,15 +19,28 @@ import org.elasticsearch.core.TimeValue; import org.elasticsearch.index.IndexNotFoundException; +import java.util.function.BiFunction; + /** - * Deletes the index identified by the shrink index name stored in the lifecycle state of the managed index (if any was generated) + * Deletes the index identified by the index name supplier. */ -public class CleanupShrinkIndexStep extends AsyncRetryDuringSnapshotActionStep { - public static final String NAME = "cleanup-shrink-index"; - private static final Logger logger = LogManager.getLogger(CleanupShrinkIndexStep.class); +public class CleanupGeneratedIndexStep extends AsyncRetryDuringSnapshotActionStep { + + public static final String OLD_NAME = "cleanup-shrink-index"; + public static final String NAME = "cleanup-prefixed-index"; + + private static final Logger logger = LogManager.getLogger(CleanupGeneratedIndexStep.class); - public CleanupShrinkIndexStep(StepKey key, StepKey nextStepKey, Client client) { + private final BiFunction targetIndexNameSupplier; + + public CleanupGeneratedIndexStep( + StepKey key, + StepKey nextStepKey, + Client client, + BiFunction targetIndexNameSupplier + ) { super(key, nextStepKey, client); + this.targetIndexNameSupplier = targetIndexNameSupplier; } @Override @@ -37,19 +50,18 @@ public boolean isRetryable() { @Override void performDuringNoSnapshot(IndexMetadata indexMetadata, ProjectMetadata currentProject, ActionListener listener) { - final String shrunkenIndexSource = IndexMetadata.INDEX_RESIZE_SOURCE_NAME.get(indexMetadata.getSettings()); - if (Strings.isNullOrEmpty(shrunkenIndexSource) == false) { - // the current managed index is a shrunk index - if (currentProject.index(shrunkenIndexSource) == null) { - // if the source index does not exist, we'll skip deleting the - // (managed) shrunk index as that will cause data loss + // If the index was generated by a resize operation, and the source inex does not exist anymore, we skip the deletion to avoid + // data loss. + final String generatedIndexSource = IndexMetadata.INDEX_RESIZE_SOURCE_NAME.get(indexMetadata.getSettings()); + if (Strings.isNullOrEmpty(generatedIndexSource) == false) { + if (currentProject.index(generatedIndexSource) == null) { String policyName = indexMetadata.getLifecyclePolicyName(); logger.warn( "managed index [{}] as part of policy [{}] is a shrunk index and the source index [{}] does not exist " + "anymore. will skip the [{}] step", indexMetadata.getIndex().getName(), policyName, - shrunkenIndexSource, + generatedIndexSource, NAME ); listener.onResponse(null); @@ -57,20 +69,22 @@ void performDuringNoSnapshot(IndexMetadata indexMetadata, ProjectMetadata curren } } - LifecycleExecutionState lifecycleState = indexMetadata.getLifecycleExecutionState(); - final String shrinkIndexName = lifecycleState.shrinkIndexName(); - // if the shrink index was not generated there is nothing to delete so we move on - if (Strings.hasText(shrinkIndexName) == false) { + final String targetIndexName = targetIndexNameSupplier.apply( + indexMetadata.getIndex().getName(), + indexMetadata.getLifecycleExecutionState() + ); + // If no index name was generated, there is nothing for us to delete, so we can move on + if (Strings.hasText(targetIndexName) == false) { listener.onResponse(null); return; } getClient(currentProject.id()).admin() .indices() - .delete(new DeleteIndexRequest(shrinkIndexName).masterNodeTimeout(TimeValue.MAX_VALUE), new ActionListener<>() { + .delete(new DeleteIndexRequest(targetIndexName).masterNodeTimeout(TimeValue.MAX_VALUE), new ActionListener<>() { @Override public void onResponse(AcknowledgedResponse acknowledgedResponse) { // even if not all nodes acked the delete request yet we can consider this operation as successful as - // we'll generate a new index name and attempt to shrink into the newly generated name + // we'll generate a new index name and attempt to create a new index with the newly generated name listener.onResponse(null); } @@ -86,4 +100,7 @@ public void onFailure(Exception e) { }); } + public BiFunction getTargetIndexNameSupplier() { + return targetIndexNameSupplier; + } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkAction.java index e991d46570766..8760c5f081700 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkAction.java @@ -168,7 +168,8 @@ public List toSteps(Client client, String phase, Step.StepKey nextStepKey) StepKey waitTimeSeriesEndTimePassesKey = new StepKey(phase, NAME, WaitUntilTimeSeriesEndTimePassesStep.NAME); StepKey readOnlyKey = new StepKey(phase, NAME, ReadOnlyAction.NAME); StepKey checkTargetShardsCountKey = new StepKey(phase, NAME, CheckTargetShardsCountStep.NAME); - StepKey cleanupShrinkIndexKey = new StepKey(phase, NAME, CleanupShrinkIndexStep.NAME); + StepKey oldCleanupShrinkIndexKey = new StepKey(phase, NAME, CleanupGeneratedIndexStep.OLD_NAME); + StepKey cleanupShrinkIndexKey = new StepKey(phase, NAME, CleanupGeneratedIndexStep.NAME); StepKey generateShrinkIndexNameKey = new StepKey(phase, NAME, GenerateUniqueIndexNameStep.NAME); StepKey setSingleNodeKey = new StepKey(phase, NAME, SetSingleNodeAllocateStep.NAME); StepKey allocationRoutedKey = new StepKey(phase, NAME, CheckShrinkReadyStep.NAME); @@ -240,13 +241,16 @@ public List toSteps(Client client, String phase, Step.StepKey nextStepKey) cleanupShrinkIndexKey, numberOfShards ); + // The cleanup step was renamed, so we need to forward indices in the old step to the new one, i.e. during an upgrade + NoopStep oldCleanupShrinkIndexStep = new NoopStep(oldCleanupShrinkIndexKey, cleanupShrinkIndexKey); // We generate a unique shrink index name but we also retry if the allocation of the shrunk index is not possible, so we want to // delete the "previously generated" shrink index (this is a no-op if it's the first run of the action and we haven't generated a // shrink index name) - CleanupShrinkIndexStep cleanupShrinkIndexStep = new CleanupShrinkIndexStep( + CleanupGeneratedIndexStep cleanupShrinkIndexStep = new CleanupGeneratedIndexStep( cleanupShrinkIndexKey, generateShrinkIndexNameKey, - client + client, + ShrinkIndexNameSupplier::getShrinkIndexName ); // generate a unique shrink index name and store it in the ILM execution state GenerateUniqueIndexNameStep generateUniqueIndexNameStep = new GenerateUniqueIndexNameStep( @@ -313,6 +317,7 @@ public List toSteps(Client client, String phase, Step.StepKey nextStepKey) waitUntilTimeSeriesEndTimeStep, readOnlyStep, checkTargetShardsCountStep, + oldCleanupShrinkIndexStep, cleanupShrinkIndexStep, generateUniqueIndexNameStep, setSingleNodeStep, diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/CleanupShrinkIndexStepTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStepTests.java similarity index 84% rename from x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/CleanupShrinkIndexStepTests.java rename to x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStepTests.java index fa175baaf30b1..dfbb5b767f3a8 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/CleanupShrinkIndexStepTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStepTests.java @@ -28,22 +28,27 @@ import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.is; -public class CleanupShrinkIndexStepTests extends AbstractStepTestCase { +public class CleanupGeneratedIndexStepTests extends AbstractStepTestCase { @Override - public CleanupShrinkIndexStep createRandomInstance() { + public CleanupGeneratedIndexStep createRandomInstance() { StepKey stepKey = randomStepKey(); StepKey nextStepKey = randomStepKey(); - return new CleanupShrinkIndexStep(stepKey, nextStepKey, client); + return new CleanupGeneratedIndexStep(stepKey, nextStepKey, client, (index, state) -> randomAlphaOfLength(5) + index); } @Override - protected CleanupShrinkIndexStep copyInstance(CleanupShrinkIndexStep instance) { - return new CleanupShrinkIndexStep(instance.getKey(), instance.getNextStepKey(), instance.getClientWithoutProject()); + protected CleanupGeneratedIndexStep copyInstance(CleanupGeneratedIndexStep instance) { + return new CleanupGeneratedIndexStep( + instance.getKey(), + instance.getNextStepKey(), + instance.getClientWithoutProject(), + instance.getTargetIndexNameSupplier() + ); } @Override - public CleanupShrinkIndexStep mutateInstance(CleanupShrinkIndexStep instance) { + public CleanupGeneratedIndexStep mutateInstance(CleanupGeneratedIndexStep instance) { StepKey key = instance.getKey(); StepKey nextKey = instance.getNextStepKey(); switch (between(0, 1)) { @@ -51,7 +56,7 @@ public CleanupShrinkIndexStep mutateInstance(CleanupShrinkIndexStep instance) { case 1 -> nextKey = new StepKey(nextKey.phase(), nextKey.action(), nextKey.name() + randomAlphaOfLength(5)); default -> throw new AssertionError("Illegal randomisation branch"); } - return new CleanupShrinkIndexStep(key, nextKey, instance.getClientWithoutProject()); + return new CleanupGeneratedIndexStep(key, nextKey, instance.getClientWithoutProject(), instance.getTargetIndexNameSupplier()); } public void testPerformActionDoesntFailIfShrinkingIndexNameIsMissing() { @@ -67,7 +72,7 @@ public void testPerformActionDoesntFailIfShrinkingIndexNameIsMissing() { ProjectState state = projectStateFromProject(ProjectMetadata.builder(randomProjectIdOrDefault()).put(indexMetadata, true)); - CleanupShrinkIndexStep cleanupShrinkIndexStep = createRandomInstance(); + CleanupGeneratedIndexStep cleanupShrinkIndexStep = createRandomInstance(); cleanupShrinkIndexStep.performAction(indexMetadata, state, null, new ActionListener<>() { @Override public void onResponse(Void unused) {} @@ -100,7 +105,12 @@ public void testPerformAction() { try (var threadPool = createThreadPool()) { final var client = getDeleteIndexRequestAssertingClient(threadPool, shrinkIndexName); - CleanupShrinkIndexStep step = new CleanupShrinkIndexStep(randomStepKey(), randomStepKey(), client); + CleanupGeneratedIndexStep step = new CleanupGeneratedIndexStep( + randomStepKey(), + randomStepKey(), + client, + ShrinkIndexNameSupplier::getShrinkIndexName + ); step.performAction(indexMetadata, state, null, ActionListener.noop()); } } @@ -125,7 +135,7 @@ public void testDeleteSkippedIfManagedIndexIsShrunkAndSourceDoesntExist() { try (var threadPool = createThreadPool()) { final var client = getFailingIfCalledClient(threadPool); - CleanupShrinkIndexStep step = new CleanupShrinkIndexStep(randomStepKey(), randomStepKey(), client); + CleanupGeneratedIndexStep step = new CleanupGeneratedIndexStep(randomStepKey(), randomStepKey(), client, (index, s) -> index); step.performAction(shrunkIndexMetadata, state, null, ActionListener.noop()); } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/ShrinkActionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/ShrinkActionTests.java index e0b84ef28a79f..4a558ef620812 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/ShrinkActionTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/ShrinkActionTests.java @@ -279,119 +279,122 @@ public void testToSteps() { randomAlphaOfLengthBetween(1, 10) ); List steps = action.toSteps(client, phase, nextStepKey); - assertThat(steps.size(), equalTo(action.getAllowWriteAfterShrink() ? 19 : 18)); - StepKey expectedFirstKey = new StepKey(phase, ShrinkAction.NAME, ShrinkAction.CONDITIONAL_SKIP_SHRINK_STEP); - StepKey expectedSecondKey = new StepKey(phase, ShrinkAction.NAME, CheckNotDataStreamWriteIndexStep.NAME); - StepKey expectedThirdKey = new StepKey(phase, ShrinkAction.NAME, WaitForNoFollowersStep.NAME); - StepKey expectedFourthKey = new StepKey(phase, ShrinkAction.NAME, WaitUntilTimeSeriesEndTimePassesStep.NAME); - StepKey expectedFifthKey = new StepKey(phase, ShrinkAction.NAME, ReadOnlyAction.NAME); - StepKey expectedSixthKey = new StepKey(phase, ShrinkAction.NAME, CheckTargetShardsCountStep.NAME); - StepKey expectedSeventhKey = new StepKey(phase, ShrinkAction.NAME, CleanupShrinkIndexStep.NAME); - StepKey expectedEighthKey = new StepKey(phase, ShrinkAction.NAME, GenerateUniqueIndexNameStep.NAME); - StepKey expectedNinthKey = new StepKey(phase, ShrinkAction.NAME, SetSingleNodeAllocateStep.NAME); - StepKey expectedTenthKey = new StepKey(phase, ShrinkAction.NAME, CheckShrinkReadyStep.NAME); - StepKey expectedEleventhKey = new StepKey(phase, ShrinkAction.NAME, ShrinkStep.NAME); - StepKey expectedTwelveKey = new StepKey(phase, ShrinkAction.NAME, ShrunkShardsAllocatedStep.NAME); - StepKey expectedThirteenKey = new StepKey(phase, ShrinkAction.NAME, CopyExecutionStateStep.NAME); - StepKey expectedFourteenKey = new StepKey(phase, ShrinkAction.NAME, ShrinkAction.CONDITIONAL_DATASTREAM_CHECK_KEY); - StepKey expectedFifteenKey = new StepKey(phase, ShrinkAction.NAME, ShrinkSetAliasStep.NAME); - StepKey expectedSixteenKey = new StepKey(phase, ShrinkAction.NAME, ShrunkenIndexCheckStep.NAME); - StepKey expectedSeventeenKey = new StepKey(phase, ShrinkAction.NAME, ReplaceDataStreamBackingIndexStep.NAME); - StepKey expectedEighteenKey = new StepKey(phase, ShrinkAction.NAME, DeleteStep.NAME); - StepKey expectedNineteenthKey = new StepKey(phase, ShrinkAction.NAME, UpdateSettingsStep.NAME); + assertThat(steps.size(), equalTo(action.getAllowWriteAfterShrink() ? 20 : 19)); + StepKey preShrinkBranchingKey = new StepKey(phase, ShrinkAction.NAME, ShrinkAction.CONDITIONAL_SKIP_SHRINK_STEP); + StepKey checkNotWriteIndex = new StepKey(phase, ShrinkAction.NAME, CheckNotDataStreamWriteIndexStep.NAME); + StepKey waitForNoFollowerStepKey = new StepKey(phase, ShrinkAction.NAME, WaitForNoFollowersStep.NAME); + StepKey waitTimeSeriesEndTimePassesKey = new StepKey(phase, ShrinkAction.NAME, WaitUntilTimeSeriesEndTimePassesStep.NAME); + StepKey readOnlyKey = new StepKey(phase, ShrinkAction.NAME, ReadOnlyAction.NAME); + StepKey checkTargetShardsCountKey = new StepKey(phase, ShrinkAction.NAME, CheckTargetShardsCountStep.NAME); + StepKey oldCleanupShrinkIndexKey = new StepKey(phase, ShrinkAction.NAME, CleanupGeneratedIndexStep.OLD_NAME); + StepKey cleanupShrinkIndexKey = new StepKey(phase, ShrinkAction.NAME, CleanupGeneratedIndexStep.NAME); + StepKey generateShrinkIndexNameKey = new StepKey(phase, ShrinkAction.NAME, GenerateUniqueIndexNameStep.NAME); + StepKey setSingleNodeKey = new StepKey(phase, ShrinkAction.NAME, SetSingleNodeAllocateStep.NAME); + StepKey allocationRoutedKey = new StepKey(phase, ShrinkAction.NAME, CheckShrinkReadyStep.NAME); + StepKey shrinkKey = new StepKey(phase, ShrinkAction.NAME, ShrinkStep.NAME); + StepKey enoughShardsKey = new StepKey(phase, ShrinkAction.NAME, ShrunkShardsAllocatedStep.NAME); + StepKey copyMetadataKey = new StepKey(phase, ShrinkAction.NAME, CopyExecutionStateStep.NAME); + StepKey dataStreamCheckBranchingKey = new StepKey(phase, ShrinkAction.NAME, ShrinkAction.CONDITIONAL_DATASTREAM_CHECK_KEY); + StepKey aliasKey = new StepKey(phase, ShrinkAction.NAME, ShrinkSetAliasStep.NAME); + StepKey isShrunkIndexKey = new StepKey(phase, ShrinkAction.NAME, ShrunkenIndexCheckStep.NAME); + StepKey replaceDataStreamIndexKey = new StepKey(phase, ShrinkAction.NAME, ReplaceDataStreamBackingIndexStep.NAME); + StepKey deleteIndexKey = new StepKey(phase, ShrinkAction.NAME, DeleteStep.NAME); + StepKey allowWriteKey = new StepKey(phase, ShrinkAction.NAME, UpdateSettingsStep.NAME); assertTrue(steps.get(0) instanceof AsyncBranchingStep); - assertThat(steps.get(0).getKey(), equalTo(expectedFirstKey)); + assertThat(steps.get(0).getKey(), equalTo(preShrinkBranchingKey)); expectThrows(IllegalStateException.class, () -> steps.get(0).getNextStepKey()); - assertThat(((AsyncBranchingStep) steps.get(0)).getNextStepKeyOnFalse(), equalTo(expectedSecondKey)); + assertThat(((AsyncBranchingStep) steps.get(0)).getNextStepKeyOnFalse(), equalTo(checkNotWriteIndex)); assertThat( ((AsyncBranchingStep) steps.get(0)).getNextStepKeyOnTrue(), - equalTo(action.getAllowWriteAfterShrink() ? expectedNineteenthKey : nextStepKey) + equalTo(action.getAllowWriteAfterShrink() ? allowWriteKey : nextStepKey) ); assertTrue(steps.get(1) instanceof CheckNotDataStreamWriteIndexStep); - assertThat(steps.get(1).getKey(), equalTo(expectedSecondKey)); - assertThat(steps.get(1).getNextStepKey(), equalTo(expectedThirdKey)); + assertThat(steps.get(1).getKey(), equalTo(checkNotWriteIndex)); + assertThat(steps.get(1).getNextStepKey(), equalTo(waitForNoFollowerStepKey)); assertTrue(steps.get(2) instanceof WaitForNoFollowersStep); - assertThat(steps.get(2).getKey(), equalTo(expectedThirdKey)); - assertThat(steps.get(2).getNextStepKey(), equalTo(expectedFourthKey)); + assertThat(steps.get(2).getKey(), equalTo(waitForNoFollowerStepKey)); + assertThat(steps.get(2).getNextStepKey(), equalTo(waitTimeSeriesEndTimePassesKey)); assertTrue(steps.get(3) instanceof WaitUntilTimeSeriesEndTimePassesStep); - assertThat(steps.get(3).getKey(), equalTo(expectedFourthKey)); - assertThat(steps.get(3).getNextStepKey(), equalTo(expectedFifthKey)); + assertThat(steps.get(3).getKey(), equalTo(waitTimeSeriesEndTimePassesKey)); + assertThat(steps.get(3).getNextStepKey(), equalTo(readOnlyKey)); assertTrue(steps.get(4) instanceof ReadOnlyStep); - assertThat(steps.get(4).getKey(), equalTo(expectedFifthKey)); - assertThat(steps.get(4).getNextStepKey(), equalTo(expectedSixthKey)); + assertThat(steps.get(4).getKey(), equalTo(readOnlyKey)); + assertThat(steps.get(4).getNextStepKey(), equalTo(checkTargetShardsCountKey)); assertTrue(steps.get(5) instanceof CheckTargetShardsCountStep); - assertThat(steps.get(5).getKey(), equalTo(expectedSixthKey)); - assertThat(steps.get(5).getNextStepKey(), equalTo(expectedSeventhKey)); - - assertTrue(steps.get(6) instanceof CleanupShrinkIndexStep); - assertThat(steps.get(6).getKey(), equalTo(expectedSeventhKey)); - assertThat(steps.get(6).getNextStepKey(), equalTo(expectedEighthKey)); - - assertTrue(steps.get(7) instanceof GenerateUniqueIndexNameStep); - assertThat(steps.get(7).getKey(), equalTo(expectedEighthKey)); - assertThat(steps.get(7).getNextStepKey(), equalTo(expectedNinthKey)); - - assertTrue(steps.get(8) instanceof SetSingleNodeAllocateStep); - assertThat(steps.get(8).getKey(), equalTo(expectedNinthKey)); - assertThat(steps.get(8).getNextStepKey(), equalTo(expectedTenthKey)); - - assertTrue(steps.get(9) instanceof ClusterStateWaitUntilThresholdStep); - assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(9)).getStepToExecute(), is(instanceOf(CheckShrinkReadyStep.class))); - // assert in case the threshold is breached we go back to the "cleanup shrunk index" step - assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(9)).getNextKeyOnThreshold(), is(expectedNinthKey)); - assertThat(steps.get(9).getKey(), equalTo(expectedTenthKey)); - assertThat(steps.get(9).getNextStepKey(), equalTo(expectedEleventhKey)); - - assertTrue(steps.get(10) instanceof ShrinkStep); - assertThat(steps.get(10).getKey(), equalTo(expectedEleventhKey)); - assertThat(steps.get(10).getNextStepKey(), equalTo(expectedTwelveKey)); - - assertTrue(steps.get(11) instanceof ClusterStateWaitUntilThresholdStep); - assertThat(steps.get(11).getKey(), equalTo(expectedTwelveKey)); - assertThat(steps.get(11).getNextStepKey(), equalTo(expectedThirteenKey)); + assertThat(steps.get(5).getKey(), equalTo(checkTargetShardsCountKey)); + assertThat(steps.get(5).getNextStepKey(), equalTo(cleanupShrinkIndexKey)); + + assertTrue(steps.get(6) instanceof NoopStep); + assertThat(steps.get(6).getKey(), equalTo(oldCleanupShrinkIndexKey)); + assertThat(steps.get(6).getNextStepKey(), equalTo(cleanupShrinkIndexKey)); + + assertTrue(steps.get(7) instanceof CleanupGeneratedIndexStep); + assertThat(steps.get(7).getKey(), equalTo(cleanupShrinkIndexKey)); + assertThat(steps.get(7).getNextStepKey(), equalTo(generateShrinkIndexNameKey)); + + assertTrue(steps.get(8) instanceof GenerateUniqueIndexNameStep); + assertThat(steps.get(8).getKey(), equalTo(generateShrinkIndexNameKey)); + assertThat(steps.get(8).getNextStepKey(), equalTo(setSingleNodeKey)); + + assertTrue(steps.get(9) instanceof SetSingleNodeAllocateStep); + assertThat(steps.get(9).getKey(), equalTo(setSingleNodeKey)); + assertThat(steps.get(9).getNextStepKey(), equalTo(allocationRoutedKey)); + + assertTrue(steps.get(10) instanceof ClusterStateWaitUntilThresholdStep); + assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(10)).getStepToExecute(), is(instanceOf(CheckShrinkReadyStep.class))); + assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(10)).getNextKeyOnThreshold(), is(setSingleNodeKey)); + assertThat(steps.get(10).getKey(), equalTo(allocationRoutedKey)); + assertThat(steps.get(10).getNextStepKey(), equalTo(shrinkKey)); + + assertTrue(steps.get(11) instanceof ShrinkStep); + assertThat(steps.get(11).getKey(), equalTo(shrinkKey)); + assertThat(steps.get(11).getNextStepKey(), equalTo(enoughShardsKey)); + + assertTrue(steps.get(12) instanceof ClusterStateWaitUntilThresholdStep); + assertThat(steps.get(12).getKey(), equalTo(enoughShardsKey)); + assertThat(steps.get(12).getNextStepKey(), equalTo(copyMetadataKey)); assertThat( - ((ClusterStateWaitUntilThresholdStep) steps.get(11)).getStepToExecute(), + ((ClusterStateWaitUntilThresholdStep) steps.get(12)).getStepToExecute(), is(instanceOf(ShrunkShardsAllocatedStep.class)) ); - // assert in case the threshold is breached we go back to the "cleanup shrunk index" step - assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(11)).getNextKeyOnThreshold(), is(expectedSeventhKey)); + assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(12)).getNextKeyOnThreshold(), is(cleanupShrinkIndexKey)); - assertTrue(steps.get(12) instanceof CopyExecutionStateStep); - assertThat(steps.get(12).getKey(), equalTo(expectedThirteenKey)); - assertThat(steps.get(12).getNextStepKey(), equalTo(expectedFourteenKey)); + assertTrue(steps.get(13) instanceof CopyExecutionStateStep); + assertThat(steps.get(13).getKey(), equalTo(copyMetadataKey)); + assertThat(steps.get(13).getNextStepKey(), equalTo(dataStreamCheckBranchingKey)); - assertTrue(steps.get(13) instanceof BranchingStep); - assertThat(steps.get(13).getKey(), equalTo(expectedFourteenKey)); - expectThrows(IllegalStateException.class, () -> steps.get(13).getNextStepKey()); - assertThat(((BranchingStep) steps.get(13)).getNextStepKeyOnFalse(), equalTo(expectedFifteenKey)); - assertThat(((BranchingStep) steps.get(13)).getNextStepKeyOnTrue(), equalTo(expectedSeventeenKey)); + assertTrue(steps.get(14) instanceof BranchingStep); + assertThat(steps.get(14).getKey(), equalTo(dataStreamCheckBranchingKey)); + expectThrows(IllegalStateException.class, () -> steps.get(14).getNextStepKey()); + assertThat(((BranchingStep) steps.get(14)).getNextStepKeyOnFalse(), equalTo(aliasKey)); + assertThat(((BranchingStep) steps.get(14)).getNextStepKeyOnTrue(), equalTo(replaceDataStreamIndexKey)); - assertTrue(steps.get(14) instanceof ShrinkSetAliasStep); - assertThat(steps.get(14).getKey(), equalTo(expectedFifteenKey)); - assertThat(steps.get(14).getNextStepKey(), equalTo(expectedSixteenKey)); + assertTrue(steps.get(15) instanceof ShrinkSetAliasStep); + assertThat(steps.get(15).getKey(), equalTo(aliasKey)); + assertThat(steps.get(15).getNextStepKey(), equalTo(isShrunkIndexKey)); - assertTrue(steps.get(15) instanceof ShrunkenIndexCheckStep); - assertThat(steps.get(15).getKey(), equalTo(expectedSixteenKey)); - assertThat(steps.get(15).getNextStepKey(), equalTo(action.getAllowWriteAfterShrink() ? expectedNineteenthKey : nextStepKey)); + assertTrue(steps.get(16) instanceof ShrunkenIndexCheckStep); + assertThat(steps.get(16).getKey(), equalTo(isShrunkIndexKey)); + assertThat(steps.get(16).getNextStepKey(), equalTo(action.getAllowWriteAfterShrink() ? allowWriteKey : nextStepKey)); - assertTrue(steps.get(16) instanceof ReplaceDataStreamBackingIndexStep); - assertThat(steps.get(16).getKey(), equalTo(expectedSeventeenKey)); - assertThat(steps.get(16).getNextStepKey(), equalTo(expectedEighteenKey)); + assertTrue(steps.get(17) instanceof ReplaceDataStreamBackingIndexStep); + assertThat(steps.get(17).getKey(), equalTo(replaceDataStreamIndexKey)); + assertThat(steps.get(17).getNextStepKey(), equalTo(deleteIndexKey)); - assertTrue(steps.get(17) instanceof DeleteStep); - assertThat(steps.get(17).getKey(), equalTo(expectedEighteenKey)); - assertThat(steps.get(17).getNextStepKey(), equalTo(expectedSixteenKey)); + assertTrue(steps.get(18) instanceof DeleteStep); + assertThat(steps.get(18).getKey(), equalTo(deleteIndexKey)); + assertThat(steps.get(18).getNextStepKey(), equalTo(isShrunkIndexKey)); if (action.getAllowWriteAfterShrink()) { - assertTrue(steps.get(18) instanceof UpdateSettingsStep); - assertThat(steps.get(18).getKey(), equalTo(expectedNineteenthKey)); - assertThat(steps.get(18).getNextStepKey(), equalTo(nextStepKey)); + assertTrue(steps.get(19) instanceof UpdateSettingsStep); + assertThat(steps.get(19).getKey(), equalTo(allowWriteKey)); + assertThat(steps.get(19).getNextStepKey(), equalTo(nextStepKey)); } } From df469f54e96d22aadfe0e259535bd4fed86524ce Mon Sep 17 00:00:00 2001 From: Niels Bauman <33722607+nielsbauman@users.noreply.github.com> Date: Thu, 21 Aug 2025 21:13:44 +0200 Subject: [PATCH 2/4] Fix comment typo Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java index bc90d18c9ec68..5464e3eed6ed4 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java @@ -50,7 +50,7 @@ public boolean isRetryable() { @Override void performDuringNoSnapshot(IndexMetadata indexMetadata, ProjectMetadata currentProject, ActionListener listener) { - // If the index was generated by a resize operation, and the source inex does not exist anymore, we skip the deletion to avoid + // If the index was generated by a resize operation, and the source index does not exist anymore, we skip the deletion to avoid // data loss. final String generatedIndexSource = IndexMetadata.INDEX_RESIZE_SOURCE_NAME.get(indexMetadata.getSettings()); if (Strings.isNullOrEmpty(generatedIndexSource) == false) { From 2caa2d5f2280999d717ff9cec06edcb45ac83cb0 Mon Sep 17 00:00:00 2001 From: Niels Bauman Date: Tue, 26 Aug 2025 20:42:59 +0200 Subject: [PATCH 3/4] PR suggestions --- .../xpack/core/ilm/CleanupGeneratedIndexStep.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java index 5464e3eed6ed4..faa667528892c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java @@ -27,7 +27,7 @@ public class CleanupGeneratedIndexStep extends AsyncRetryDuringSnapshotActionStep { public static final String OLD_NAME = "cleanup-shrink-index"; - public static final String NAME = "cleanup-prefixed-index"; + public static final String NAME = "cleanup-generated-index"; private static final Logger logger = LogManager.getLogger(CleanupGeneratedIndexStep.class); @@ -53,7 +53,7 @@ void performDuringNoSnapshot(IndexMetadata indexMetadata, ProjectMetadata curren // If the index was generated by a resize operation, and the source index does not exist anymore, we skip the deletion to avoid // data loss. final String generatedIndexSource = IndexMetadata.INDEX_RESIZE_SOURCE_NAME.get(indexMetadata.getSettings()); - if (Strings.isNullOrEmpty(generatedIndexSource) == false) { + if (Strings.hasText(generatedIndexSource)) { if (currentProject.index(generatedIndexSource) == null) { String policyName = indexMetadata.getLifecyclePolicyName(); logger.warn( From 7d9060427d4c45a51327f76624d3ad4282381f18 Mon Sep 17 00:00:00 2001 From: Niels Bauman Date: Tue, 26 Aug 2025 20:48:23 +0200 Subject: [PATCH 4/4] Remove `NoopStep` --- .../core/ilm/CleanupGeneratedIndexStep.java | 1 - .../xpack/core/ilm/ShrinkAction.java | 7 +- .../xpack/core/ilm/ShrinkActionTests.java | 99 +++++++++---------- 3 files changed, 49 insertions(+), 58 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java index faa667528892c..d931ee2e96bb6 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/CleanupGeneratedIndexStep.java @@ -26,7 +26,6 @@ */ public class CleanupGeneratedIndexStep extends AsyncRetryDuringSnapshotActionStep { - public static final String OLD_NAME = "cleanup-shrink-index"; public static final String NAME = "cleanup-generated-index"; private static final Logger logger = LogManager.getLogger(CleanupGeneratedIndexStep.class); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkAction.java index 8760c5f081700..7ec2cdeb06aa5 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkAction.java @@ -46,6 +46,7 @@ public class ShrinkAction implements LifecycleAction { public static final ParseField MAX_PRIMARY_SHARD_SIZE = new ParseField("max_primary_shard_size"); public static final ParseField ALLOW_WRITE_AFTER_SHRINK = new ParseField("allow_write_after_shrink"); public static final String CONDITIONAL_SKIP_SHRINK_STEP = BranchingStep.NAME + "-check-prerequisites"; + public static final String CLEANUP_SHRINK_INDEX_STEP = "cleanup-shrink-index"; public static final String CONDITIONAL_DATASTREAM_CHECK_KEY = BranchingStep.NAME + "-on-datastream-check"; private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( @@ -168,8 +169,7 @@ public List toSteps(Client client, String phase, Step.StepKey nextStepKey) StepKey waitTimeSeriesEndTimePassesKey = new StepKey(phase, NAME, WaitUntilTimeSeriesEndTimePassesStep.NAME); StepKey readOnlyKey = new StepKey(phase, NAME, ReadOnlyAction.NAME); StepKey checkTargetShardsCountKey = new StepKey(phase, NAME, CheckTargetShardsCountStep.NAME); - StepKey oldCleanupShrinkIndexKey = new StepKey(phase, NAME, CleanupGeneratedIndexStep.OLD_NAME); - StepKey cleanupShrinkIndexKey = new StepKey(phase, NAME, CleanupGeneratedIndexStep.NAME); + StepKey cleanupShrinkIndexKey = new StepKey(phase, NAME, CLEANUP_SHRINK_INDEX_STEP); StepKey generateShrinkIndexNameKey = new StepKey(phase, NAME, GenerateUniqueIndexNameStep.NAME); StepKey setSingleNodeKey = new StepKey(phase, NAME, SetSingleNodeAllocateStep.NAME); StepKey allocationRoutedKey = new StepKey(phase, NAME, CheckShrinkReadyStep.NAME); @@ -241,8 +241,6 @@ public List toSteps(Client client, String phase, Step.StepKey nextStepKey) cleanupShrinkIndexKey, numberOfShards ); - // The cleanup step was renamed, so we need to forward indices in the old step to the new one, i.e. during an upgrade - NoopStep oldCleanupShrinkIndexStep = new NoopStep(oldCleanupShrinkIndexKey, cleanupShrinkIndexKey); // We generate a unique shrink index name but we also retry if the allocation of the shrunk index is not possible, so we want to // delete the "previously generated" shrink index (this is a no-op if it's the first run of the action and we haven't generated a // shrink index name) @@ -317,7 +315,6 @@ public List toSteps(Client client, String phase, Step.StepKey nextStepKey) waitUntilTimeSeriesEndTimeStep, readOnlyStep, checkTargetShardsCountStep, - oldCleanupShrinkIndexStep, cleanupShrinkIndexStep, generateUniqueIndexNameStep, setSingleNodeStep, diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/ShrinkActionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/ShrinkActionTests.java index 4a558ef620812..e7bc6e200a6db 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/ShrinkActionTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/ShrinkActionTests.java @@ -279,15 +279,14 @@ public void testToSteps() { randomAlphaOfLengthBetween(1, 10) ); List steps = action.toSteps(client, phase, nextStepKey); - assertThat(steps.size(), equalTo(action.getAllowWriteAfterShrink() ? 20 : 19)); + assertThat(steps.size(), equalTo(action.getAllowWriteAfterShrink() ? 19 : 18)); StepKey preShrinkBranchingKey = new StepKey(phase, ShrinkAction.NAME, ShrinkAction.CONDITIONAL_SKIP_SHRINK_STEP); StepKey checkNotWriteIndex = new StepKey(phase, ShrinkAction.NAME, CheckNotDataStreamWriteIndexStep.NAME); StepKey waitForNoFollowerStepKey = new StepKey(phase, ShrinkAction.NAME, WaitForNoFollowersStep.NAME); StepKey waitTimeSeriesEndTimePassesKey = new StepKey(phase, ShrinkAction.NAME, WaitUntilTimeSeriesEndTimePassesStep.NAME); StepKey readOnlyKey = new StepKey(phase, ShrinkAction.NAME, ReadOnlyAction.NAME); StepKey checkTargetShardsCountKey = new StepKey(phase, ShrinkAction.NAME, CheckTargetShardsCountStep.NAME); - StepKey oldCleanupShrinkIndexKey = new StepKey(phase, ShrinkAction.NAME, CleanupGeneratedIndexStep.OLD_NAME); - StepKey cleanupShrinkIndexKey = new StepKey(phase, ShrinkAction.NAME, CleanupGeneratedIndexStep.NAME); + StepKey cleanupShrinkIndexKey = new StepKey(phase, ShrinkAction.NAME, ShrinkAction.CLEANUP_SHRINK_INDEX_STEP); StepKey generateShrinkIndexNameKey = new StepKey(phase, ShrinkAction.NAME, GenerateUniqueIndexNameStep.NAME); StepKey setSingleNodeKey = new StepKey(phase, ShrinkAction.NAME, SetSingleNodeAllocateStep.NAME); StepKey allocationRoutedKey = new StepKey(phase, ShrinkAction.NAME, CheckShrinkReadyStep.NAME); @@ -330,71 +329,67 @@ public void testToSteps() { assertThat(steps.get(5).getKey(), equalTo(checkTargetShardsCountKey)); assertThat(steps.get(5).getNextStepKey(), equalTo(cleanupShrinkIndexKey)); - assertTrue(steps.get(6) instanceof NoopStep); - assertThat(steps.get(6).getKey(), equalTo(oldCleanupShrinkIndexKey)); - assertThat(steps.get(6).getNextStepKey(), equalTo(cleanupShrinkIndexKey)); + assertTrue(steps.get(6) instanceof CleanupGeneratedIndexStep); + assertThat(steps.get(6).getKey(), equalTo(cleanupShrinkIndexKey)); + assertThat(steps.get(6).getNextStepKey(), equalTo(generateShrinkIndexNameKey)); - assertTrue(steps.get(7) instanceof CleanupGeneratedIndexStep); - assertThat(steps.get(7).getKey(), equalTo(cleanupShrinkIndexKey)); - assertThat(steps.get(7).getNextStepKey(), equalTo(generateShrinkIndexNameKey)); + assertTrue(steps.get(7) instanceof GenerateUniqueIndexNameStep); + assertThat(steps.get(7).getKey(), equalTo(generateShrinkIndexNameKey)); + assertThat(steps.get(7).getNextStepKey(), equalTo(setSingleNodeKey)); - assertTrue(steps.get(8) instanceof GenerateUniqueIndexNameStep); - assertThat(steps.get(8).getKey(), equalTo(generateShrinkIndexNameKey)); - assertThat(steps.get(8).getNextStepKey(), equalTo(setSingleNodeKey)); + assertTrue(steps.get(8) instanceof SetSingleNodeAllocateStep); + assertThat(steps.get(8).getKey(), equalTo(setSingleNodeKey)); + assertThat(steps.get(8).getNextStepKey(), equalTo(allocationRoutedKey)); - assertTrue(steps.get(9) instanceof SetSingleNodeAllocateStep); - assertThat(steps.get(9).getKey(), equalTo(setSingleNodeKey)); - assertThat(steps.get(9).getNextStepKey(), equalTo(allocationRoutedKey)); + assertTrue(steps.get(9) instanceof ClusterStateWaitUntilThresholdStep); + assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(9)).getStepToExecute(), is(instanceOf(CheckShrinkReadyStep.class))); + assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(9)).getNextKeyOnThreshold(), is(setSingleNodeKey)); + assertThat(steps.get(9).getKey(), equalTo(allocationRoutedKey)); + assertThat(steps.get(9).getNextStepKey(), equalTo(shrinkKey)); - assertTrue(steps.get(10) instanceof ClusterStateWaitUntilThresholdStep); - assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(10)).getStepToExecute(), is(instanceOf(CheckShrinkReadyStep.class))); - assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(10)).getNextKeyOnThreshold(), is(setSingleNodeKey)); - assertThat(steps.get(10).getKey(), equalTo(allocationRoutedKey)); - assertThat(steps.get(10).getNextStepKey(), equalTo(shrinkKey)); + assertTrue(steps.get(10) instanceof ShrinkStep); + assertThat(steps.get(10).getKey(), equalTo(shrinkKey)); + assertThat(steps.get(10).getNextStepKey(), equalTo(enoughShardsKey)); - assertTrue(steps.get(11) instanceof ShrinkStep); - assertThat(steps.get(11).getKey(), equalTo(shrinkKey)); - assertThat(steps.get(11).getNextStepKey(), equalTo(enoughShardsKey)); - - assertTrue(steps.get(12) instanceof ClusterStateWaitUntilThresholdStep); - assertThat(steps.get(12).getKey(), equalTo(enoughShardsKey)); - assertThat(steps.get(12).getNextStepKey(), equalTo(copyMetadataKey)); + assertTrue(steps.get(11) instanceof ClusterStateWaitUntilThresholdStep); + assertThat(steps.get(11).getKey(), equalTo(enoughShardsKey)); + assertThat(steps.get(11).getNextStepKey(), equalTo(copyMetadataKey)); assertThat( - ((ClusterStateWaitUntilThresholdStep) steps.get(12)).getStepToExecute(), + ((ClusterStateWaitUntilThresholdStep) steps.get(11)).getStepToExecute(), is(instanceOf(ShrunkShardsAllocatedStep.class)) ); - assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(12)).getNextKeyOnThreshold(), is(cleanupShrinkIndexKey)); + assertThat(((ClusterStateWaitUntilThresholdStep) steps.get(11)).getNextKeyOnThreshold(), is(cleanupShrinkIndexKey)); - assertTrue(steps.get(13) instanceof CopyExecutionStateStep); - assertThat(steps.get(13).getKey(), equalTo(copyMetadataKey)); - assertThat(steps.get(13).getNextStepKey(), equalTo(dataStreamCheckBranchingKey)); + assertTrue(steps.get(12) instanceof CopyExecutionStateStep); + assertThat(steps.get(12).getKey(), equalTo(copyMetadataKey)); + assertThat(steps.get(12).getNextStepKey(), equalTo(dataStreamCheckBranchingKey)); - assertTrue(steps.get(14) instanceof BranchingStep); - assertThat(steps.get(14).getKey(), equalTo(dataStreamCheckBranchingKey)); - expectThrows(IllegalStateException.class, () -> steps.get(14).getNextStepKey()); - assertThat(((BranchingStep) steps.get(14)).getNextStepKeyOnFalse(), equalTo(aliasKey)); - assertThat(((BranchingStep) steps.get(14)).getNextStepKeyOnTrue(), equalTo(replaceDataStreamIndexKey)); + assertTrue(steps.get(13) instanceof BranchingStep); + assertThat(steps.get(13).getKey(), equalTo(dataStreamCheckBranchingKey)); + expectThrows(IllegalStateException.class, () -> steps.get(13).getNextStepKey()); + assertThat(((BranchingStep) steps.get(13)).getNextStepKeyOnFalse(), equalTo(aliasKey)); + assertThat(((BranchingStep) steps.get(13)).getNextStepKeyOnTrue(), equalTo(replaceDataStreamIndexKey)); - assertTrue(steps.get(15) instanceof ShrinkSetAliasStep); - assertThat(steps.get(15).getKey(), equalTo(aliasKey)); - assertThat(steps.get(15).getNextStepKey(), equalTo(isShrunkIndexKey)); + assertTrue(steps.get(14) instanceof ShrinkSetAliasStep); + assertThat(steps.get(14).getKey(), equalTo(aliasKey)); + assertThat(steps.get(14).getNextStepKey(), equalTo(isShrunkIndexKey)); - assertTrue(steps.get(16) instanceof ShrunkenIndexCheckStep); - assertThat(steps.get(16).getKey(), equalTo(isShrunkIndexKey)); - assertThat(steps.get(16).getNextStepKey(), equalTo(action.getAllowWriteAfterShrink() ? allowWriteKey : nextStepKey)); + assertTrue(steps.get(15) instanceof ShrunkenIndexCheckStep); + assertThat(steps.get(15).getKey(), equalTo(isShrunkIndexKey)); + assertThat(steps.get(15).getNextStepKey(), equalTo(action.getAllowWriteAfterShrink() ? allowWriteKey : nextStepKey)); - assertTrue(steps.get(17) instanceof ReplaceDataStreamBackingIndexStep); - assertThat(steps.get(17).getKey(), equalTo(replaceDataStreamIndexKey)); - assertThat(steps.get(17).getNextStepKey(), equalTo(deleteIndexKey)); + assertTrue(steps.get(16) instanceof ReplaceDataStreamBackingIndexStep); + assertThat(steps.get(16).getKey(), equalTo(replaceDataStreamIndexKey)); + assertThat(steps.get(16).getNextStepKey(), equalTo(deleteIndexKey)); - assertTrue(steps.get(18) instanceof DeleteStep); - assertThat(steps.get(18).getKey(), equalTo(deleteIndexKey)); - assertThat(steps.get(18).getNextStepKey(), equalTo(isShrunkIndexKey)); + assertTrue(steps.get(17) instanceof DeleteStep); + assertThat(steps.get(17).getKey(), equalTo(deleteIndexKey)); + assertThat(steps.get(17).getNextStepKey(), equalTo(isShrunkIndexKey)); if (action.getAllowWriteAfterShrink()) { - assertTrue(steps.get(19) instanceof UpdateSettingsStep); - assertThat(steps.get(19).getKey(), equalTo(allowWriteKey)); - assertThat(steps.get(19).getNextStepKey(), equalTo(nextStepKey)); + assertTrue(steps.get(18) instanceof UpdateSettingsStep); + assertThat(steps.get(18).getKey(), equalTo(allowWriteKey)); + assertThat(steps.get(18).getNextStepKey(), equalTo(nextStepKey)); } }