|  | @@ -49,10 +49,11 @@ import java.util.Locale;
 | 
	
		
			
				|  |  |  import java.util.Map;
 | 
	
		
			
				|  |  |  import java.util.Set;
 | 
	
		
			
				|  |  |  import java.util.concurrent.atomic.AtomicReference;
 | 
	
		
			
				|  |  | -import java.util.function.Predicate;
 | 
	
		
			
				|  |  | +import java.util.function.Function;
 | 
	
		
			
				|  |  |  import java.util.stream.Collectors;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import static org.elasticsearch.cluster.metadata.DataStream.getDefaultBackingIndexName;
 | 
	
		
			
				|  |  | +import static org.elasticsearch.cluster.metadata.DataStream.getDefaultFailureStoreName;
 | 
	
		
			
				|  |  |  import static org.elasticsearch.cluster.metadata.DataStreamTestHelper.newInstance;
 | 
	
		
			
				|  |  |  import static org.elasticsearch.cluster.metadata.DataStreamTestHelper.randomGlobalRetention;
 | 
	
		
			
				|  |  |  import static org.elasticsearch.cluster.metadata.DataStreamTestHelper.randomIndexInstances;
 | 
	
	
		
			
				|  | @@ -99,7 +100,7 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
 | 
	
		
			
				|  |  |          var isSystem = instance.isSystem();
 | 
	
		
			
				|  |  |          var allowsCustomRouting = instance.isAllowCustomRouting();
 | 
	
		
			
				|  |  |          var indexMode = instance.getIndexMode();
 | 
	
		
			
				|  |  | -        var lifecycle = instance.getLifecycle();
 | 
	
		
			
				|  |  | +        var lifecycle = instance.getDataLifecycle();
 | 
	
		
			
				|  |  |          var dataStreamOptions = instance.getDataStreamOptions();
 | 
	
		
			
				|  |  |          var failureIndices = instance.getFailureIndices();
 | 
	
		
			
				|  |  |          var rolloverOnWrite = instance.rolloverOnWrite();
 | 
	
	
		
			
				|  | @@ -1218,15 +1219,30 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              // for a write index that has not been rolled over yet, we get null even if the index has an origination date
 | 
	
		
			
				|  |  |              long originTimeMillis = creationTimeMillis - 3000L;
 | 
	
		
			
				|  |  | -            IndexMetadata.Builder indexMetaBuilder = IndexMetadata.builder(DataStream.getDefaultBackingIndexName(dataStreamName, 1))
 | 
	
		
			
				|  |  | +            IndexMetadata.Builder backingIndexMetadataBuilder = IndexMetadata.builder(
 | 
	
		
			
				|  |  | +                DataStream.getDefaultBackingIndexName(dataStreamName, 1)
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  |                  .settings(settings(IndexVersion.current()).put(LIFECYCLE_ORIGINATION_DATE, originTimeMillis))
 | 
	
		
			
				|  |  |                  .numberOfShards(1)
 | 
	
		
			
				|  |  |                  .numberOfReplicas(1)
 | 
	
		
			
				|  |  |                  .creationDate(creationTimeMillis);
 | 
	
		
			
				|  |  | -            IndexMetadata indexMetadata = indexMetaBuilder.build();
 | 
	
		
			
				|  |  | -            DataStream dataStream = createDataStream(dataStreamName, List.of(indexMetadata.getIndex()));
 | 
	
		
			
				|  |  | +            IndexMetadata backingIndexMetadata = backingIndexMetadataBuilder.build();
 | 
	
		
			
				|  |  | +            IndexMetadata.Builder failureIndexMetadataBuilder = IndexMetadata.builder(
 | 
	
		
			
				|  |  | +                DataStream.getDefaultBackingIndexName(dataStreamName, 1)
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  | +                .settings(settings(IndexVersion.current()).put(LIFECYCLE_ORIGINATION_DATE, originTimeMillis))
 | 
	
		
			
				|  |  | +                .numberOfShards(1)
 | 
	
		
			
				|  |  | +                .numberOfReplicas(1)
 | 
	
		
			
				|  |  | +                .creationDate(creationTimeMillis);
 | 
	
		
			
				|  |  | +            IndexMetadata failureIndexMetadata = failureIndexMetadataBuilder.build();
 | 
	
		
			
				|  |  | +            DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | +                dataStreamName,
 | 
	
		
			
				|  |  | +                List.of(backingIndexMetadata.getIndex()),
 | 
	
		
			
				|  |  | +                List.of(failureIndexMetadata.getIndex())
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            assertNull(dataStream.getGenerationLifecycleDate(indexMetadata));
 | 
	
		
			
				|  |  | +            assertNull(dataStream.getGenerationLifecycleDate(backingIndexMetadata));
 | 
	
		
			
				|  |  | +            assertNull(dataStream.getGenerationLifecycleDate(failureIndexMetadata));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              // If the index is not the write index and has origination date set, we get the origination date even if it has not been
 | 
	
	
		
			
				|  | @@ -1306,80 +1322,159 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
 | 
	
		
			
				|  |  |              .build();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    public void testGetIndicesOlderThan() {
 | 
	
		
			
				|  |  | +    private DataStream createDataStream(String name, List<Index> backingIndices, List<Index> failureIndices) {
 | 
	
		
			
				|  |  | +        return DataStream.builder(name, backingIndices)
 | 
	
		
			
				|  |  | +            .setMetadata(Map.of())
 | 
	
		
			
				|  |  | +            .setReplicated(randomBoolean())
 | 
	
		
			
				|  |  | +            .setAllowCustomRouting(randomBoolean())
 | 
	
		
			
				|  |  | +            .setIndexMode(IndexMode.STANDARD)
 | 
	
		
			
				|  |  | +            .setFailureIndices(DataStream.DataStreamIndices.failureIndicesBuilder(failureIndices).build())
 | 
	
		
			
				|  |  | +            .build();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public void testGetBackingIndicesPastRetention() {
 | 
	
		
			
				|  |  |          String dataStreamName = "metrics-foo";
 | 
	
		
			
				|  |  |          long now = System.currentTimeMillis();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          List<DataStreamMetadata> creationAndRolloverTimes = List.of(
 | 
	
		
			
				|  |  | -            DataStreamMetadata.dataStreamMetadata(now - 5000, now - 4000),
 | 
	
		
			
				|  |  | -            DataStreamMetadata.dataStreamMetadata(now - 4000, now - 3000),
 | 
	
		
			
				|  |  | -            DataStreamMetadata.dataStreamMetadata(now - 3000, now - 2000),
 | 
	
		
			
				|  |  | -            DataStreamMetadata.dataStreamMetadata(now - 2000, now - 1000),
 | 
	
		
			
				|  |  | +            DataStreamMetadata.dataStreamMetadata(now - 5000_000, now - 4000_000),
 | 
	
		
			
				|  |  | +            DataStreamMetadata.dataStreamMetadata(now - 4000_000, now - 3000_000),
 | 
	
		
			
				|  |  | +            DataStreamMetadata.dataStreamMetadata(now - 3000_000, now - 2000_000),
 | 
	
		
			
				|  |  | +            DataStreamMetadata.dataStreamMetadata(now - 2000_000, now - 1000_000),
 | 
	
		
			
				|  |  |              DataStreamMetadata.dataStreamMetadata(now, null)
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                // no lifecycle configured so we expect an empty list
 | 
	
		
			
				|  |  | +                Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | +                DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | +                    builder,
 | 
	
		
			
				|  |  | +                    dataStreamName,
 | 
	
		
			
				|  |  | +                    creationAndRolloverTimes,
 | 
	
		
			
				|  |  | +                    settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | +                    null
 | 
	
		
			
				|  |  | +                );
 | 
	
		
			
				|  |  | +                Metadata metadata = builder.build();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                assertThat(
 | 
	
		
			
				|  |  | +                    dataStream.getBackingIndicesPastRetention(metadata::index, () -> now, randomGlobalRetention()).isEmpty(),
 | 
	
		
			
				|  |  | +                    is(true)
 | 
	
		
			
				|  |  | +                );
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | +        AtomicReference<TimeValue> retention = new AtomicReference<>();
 | 
	
		
			
				|  |  |          DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  |              builder,
 | 
	
		
			
				|  |  |              dataStreamName,
 | 
	
		
			
				|  |  |              creationAndRolloverTimes,
 | 
	
		
			
				|  |  |              settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | -            new DataStreamLifecycle()
 | 
	
		
			
				|  |  | +            new DataStreamLifecycle() {
 | 
	
		
			
				|  |  | +                public TimeValue dataRetention() {
 | 
	
		
			
				|  |  | +                    return retention.get();
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          Metadata metadata = builder.build();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getNonWriteIndicesOlderThan(
 | 
	
		
			
				|  |  | -                TimeValue.timeValueMillis(2500),
 | 
	
		
			
				|  |  | +            // Mix of indices younger and older than retention, data stream retention is effective retention
 | 
	
		
			
				|  |  | +            retention.set(TimeValue.timeValueSeconds(2500));
 | 
	
		
			
				|  |  | +            List<Index> backingIndices = dataStream.getBackingIndicesPastRetention(
 | 
	
		
			
				|  |  |                  metadata::index,
 | 
	
		
			
				|  |  | -                null,
 | 
	
		
			
				|  |  | -                () -> now
 | 
	
		
			
				|  |  | +                () -> now,
 | 
	
		
			
				|  |  | +                randomBoolean() ? randomGlobalRetention() : null
 | 
	
		
			
				|  |  |              );
 | 
	
		
			
				|  |  |              assertThat(backingIndices.size(), is(2));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(0).getName(), is(DataStream.getDefaultBackingIndexName(dataStreamName, 1)));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(1).getName(), is(DataStream.getDefaultBackingIndexName(dataStreamName, 2)));
 | 
	
		
			
				|  |  | +            for (int i = 0; i < backingIndices.size(); i++) {
 | 
	
		
			
				|  |  | +                assertThat(backingIndices.get(i).getName(), is(dataStream.getIndices().get(i).getName()));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getNonWriteIndicesOlderThan(
 | 
	
		
			
				|  |  | -                TimeValue.timeValueMillis(0),
 | 
	
		
			
				|  |  | -                metadata::index,
 | 
	
		
			
				|  |  | -                null,
 | 
	
		
			
				|  |  | -                () -> now
 | 
	
		
			
				|  |  | -            );
 | 
	
		
			
				|  |  | +            // All indices past retention, but we keep the write index
 | 
	
		
			
				|  |  | +            retention.set(TimeValue.timeValueSeconds(0));
 | 
	
		
			
				|  |  | +            List<Index> backingIndices = dataStream.getBackingIndicesPastRetention(metadata::index, () -> now, null);
 | 
	
		
			
				|  |  |              assertThat(backingIndices.size(), is(4));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(0).getName(), is(DataStream.getDefaultBackingIndexName(dataStreamName, 1)));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(1).getName(), is(DataStream.getDefaultBackingIndexName(dataStreamName, 2)));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(2).getName(), is(DataStream.getDefaultBackingIndexName(dataStreamName, 3)));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(3).getName(), is(DataStream.getDefaultBackingIndexName(dataStreamName, 4)));
 | 
	
		
			
				|  |  | +            for (int i = 0; i < backingIndices.size(); i++) {
 | 
	
		
			
				|  |  | +                assertThat(backingIndices.get(i).getName(), is(dataStream.getIndices().get(i).getName()));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getNonWriteIndicesOlderThan(
 | 
	
		
			
				|  |  | -                TimeValue.timeValueMillis(6000),
 | 
	
		
			
				|  |  | -                metadata::index,
 | 
	
		
			
				|  |  | -                null,
 | 
	
		
			
				|  |  | -                () -> now
 | 
	
		
			
				|  |  | -            );
 | 
	
		
			
				|  |  | +            // All indices younger than retention
 | 
	
		
			
				|  |  | +            retention.set(TimeValue.timeValueSeconds(6000));
 | 
	
		
			
				|  |  | +            List<Index> backingIndices = dataStream.getBackingIndicesPastRetention(metadata::index, () -> now, null);
 | 
	
		
			
				|  |  |              assertThat(backingIndices.isEmpty(), is(true));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            Predicate<IndexMetadata> genThreeAndFivePredicate = indexMetadata -> indexMetadata.getIndex().getName().endsWith("00003")
 | 
	
		
			
				|  |  | -                || indexMetadata.getIndex().getName().endsWith("00005");
 | 
	
		
			
				|  |  | +            // Test predicate that influences which indices are candidates for a retention check
 | 
	
		
			
				|  |  | +            Function<String, IndexMetadata> indexMetadataWithSomeLifecycleSupplier = indexName -> {
 | 
	
		
			
				|  |  | +                IndexMetadata indexMetadata = metadata.index(indexName);
 | 
	
		
			
				|  |  | +                if (indexName.endsWith("00003") || indexName.endsWith("00005")) {
 | 
	
		
			
				|  |  | +                    return indexMetadata;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                return IndexMetadata.builder(indexMetadata)
 | 
	
		
			
				|  |  | +                    .settings(Settings.builder().put(indexMetadata.getSettings()).put(IndexMetadata.LIFECYCLE_NAME, "some-policy").build())
 | 
	
		
			
				|  |  | +                    .build();
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  | +            retention.set(TimeValue.timeValueSeconds(0));
 | 
	
		
			
				|  |  | +            List<Index> backingIndices = dataStream.getBackingIndicesPastRetention(indexMetadataWithSomeLifecycleSupplier, () -> now, null);
 | 
	
		
			
				|  |  | +            assertThat(backingIndices.size(), is(1));
 | 
	
		
			
				|  |  | +            assertThat(backingIndices.get(0).getName(), is(dataStream.getIndices().get(2).getName()));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getNonWriteIndicesOlderThan(
 | 
	
		
			
				|  |  | -                TimeValue.timeValueMillis(0),
 | 
	
		
			
				|  |  | -                metadata::index,
 | 
	
		
			
				|  |  | -                genThreeAndFivePredicate,
 | 
	
		
			
				|  |  | -                () -> now
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            // no retention configured but we have default retention
 | 
	
		
			
				|  |  | +            DataStreamGlobalRetention globalRetention = new DataStreamGlobalRetention(
 | 
	
		
			
				|  |  | +                TimeValue.timeValueSeconds(2500),
 | 
	
		
			
				|  |  | +                randomBoolean() ? TimeValue.timeValueSeconds(randomIntBetween(2500, 5000)) : null
 | 
	
		
			
				|  |  |              );
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.size(), is(1));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(0).getName(), is(DataStream.getDefaultBackingIndexName(dataStreamName, 3)));
 | 
	
		
			
				|  |  | +            retention.set(null);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            List<Index> backingIndices = dataStream.getBackingIndicesPastRetention(metadata::index, () -> now, globalRetention);
 | 
	
		
			
				|  |  | +            assertThat(backingIndices.size(), is(2));
 | 
	
		
			
				|  |  | +            for (int i = 0; i < backingIndices.size(); i++) {
 | 
	
		
			
				|  |  | +                assertThat(backingIndices.get(i).getName(), is(dataStream.getIndices().get(i).getName()));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            // no retention or too large retention configured and we have max retention
 | 
	
		
			
				|  |  | +            DataStreamGlobalRetention globalRetention = new DataStreamGlobalRetention(null, TimeValue.timeValueSeconds(2500));
 | 
	
		
			
				|  |  | +            retention.set(randomBoolean() ? TimeValue.timeValueDays(6000) : null);
 | 
	
		
			
				|  |  | +            List<Index> backingIndices = dataStream.getBackingIndicesPastRetention(metadata::index, () -> now, globalRetention);
 | 
	
		
			
				|  |  | +            assertThat(backingIndices.size(), is(2));
 | 
	
		
			
				|  |  | +            for (int i = 0; i < backingIndices.size(); i++) {
 | 
	
		
			
				|  |  | +                assertThat(backingIndices.get(i).getName(), is(dataStream.getIndices().get(i).getName()));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            // no indices are returned as even though all pass retention age none are managed by data stream lifecycle
 | 
	
		
			
				|  |  | +            Metadata.Builder builderWithIlm = Metadata.builder();
 | 
	
		
			
				|  |  | +            DataStream dataStreamWithIlm = createDataStream(
 | 
	
		
			
				|  |  | +                builderWithIlm,
 | 
	
		
			
				|  |  | +                dataStreamName,
 | 
	
		
			
				|  |  | +                creationAndRolloverTimes,
 | 
	
		
			
				|  |  | +                settings(IndexVersion.current()).put(IndexMetadata.LIFECYCLE_NAME, "ILM_policy"),
 | 
	
		
			
				|  |  | +                DataStreamLifecycle.builder().dataRetention(TimeValue.ZERO).build()
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +            Metadata metadataWithIlm = builderWithIlm.build();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            List<Index> backingIndices = dataStreamWithIlm.getBackingIndicesPastRetention(
 | 
	
		
			
				|  |  | +                metadataWithIlm::index,
 | 
	
		
			
				|  |  | +                () -> now,
 | 
	
		
			
				|  |  | +                randomGlobalRetention()
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +            assertThat(backingIndices.isEmpty(), is(true));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    public void testGetIndicesPastRetention() {
 | 
	
		
			
				|  |  | +    public void testGetFailureIndicesPastRetention() {
 | 
	
		
			
				|  |  |          String dataStreamName = "metrics-foo";
 | 
	
		
			
				|  |  |          long now = System.currentTimeMillis();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1392,135 +1487,116 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            // no lifecycle configured so we expect an empty list
 | 
	
		
			
				|  |  | -            Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | -            DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | -                builder,
 | 
	
		
			
				|  |  | -                dataStreamName,
 | 
	
		
			
				|  |  | -                creationAndRolloverTimes,
 | 
	
		
			
				|  |  | -                settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | -                null
 | 
	
		
			
				|  |  | -            );
 | 
	
		
			
				|  |  | -            Metadata metadata = builder.build();
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                // no lifecycle configured so we expect an empty list
 | 
	
		
			
				|  |  | +                Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | +                DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | +                    builder,
 | 
	
		
			
				|  |  | +                    dataStreamName,
 | 
	
		
			
				|  |  | +                    creationAndRolloverTimes,
 | 
	
		
			
				|  |  | +                    settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | +                    null
 | 
	
		
			
				|  |  | +                );
 | 
	
		
			
				|  |  | +                Metadata metadata = builder.build();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            assertThat(dataStream.getIndicesPastRetention(metadata::index, () -> now, randomGlobalRetention()).isEmpty(), is(true));
 | 
	
		
			
				|  |  | +                assertThat(
 | 
	
		
			
				|  |  | +                    dataStream.getFailureIndicesPastRetention(metadata::index, () -> now, randomGlobalRetention()).isEmpty(),
 | 
	
		
			
				|  |  | +                    is(true)
 | 
	
		
			
				|  |  | +                );
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | +        AtomicReference<TimeValue> retention = new AtomicReference<>();
 | 
	
		
			
				|  |  | +        DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | +            builder,
 | 
	
		
			
				|  |  | +            dataStreamName,
 | 
	
		
			
				|  |  | +            creationAndRolloverTimes,
 | 
	
		
			
				|  |  | +            settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | +            new DataStreamLifecycle() {
 | 
	
		
			
				|  |  | +                public TimeValue dataRetention() {
 | 
	
		
			
				|  |  | +                    return retention.get();
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +        Metadata metadata = builder.build();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            // no retention configured but we have default retention
 | 
	
		
			
				|  |  | -            DataStreamGlobalRetention globalRetention = new DataStreamGlobalRetention(
 | 
	
		
			
				|  |  | -                TimeValue.timeValueSeconds(2500),
 | 
	
		
			
				|  |  | -                randomBoolean() ? TimeValue.timeValueSeconds(randomIntBetween(2500, 5000)) : null
 | 
	
		
			
				|  |  | -            );
 | 
	
		
			
				|  |  | -            Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | -            DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | -                builder,
 | 
	
		
			
				|  |  | -                dataStreamName,
 | 
	
		
			
				|  |  | -                creationAndRolloverTimes,
 | 
	
		
			
				|  |  | -                settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | -                new DataStreamLifecycle()
 | 
	
		
			
				|  |  | +            // Mix of indices younger and older than retention, data stream retention is effective retention
 | 
	
		
			
				|  |  | +            retention.set(TimeValue.timeValueSeconds(2500));
 | 
	
		
			
				|  |  | +            List<Index> failureIndices = dataStream.getFailureIndicesPastRetention(
 | 
	
		
			
				|  |  | +                metadata::index,
 | 
	
		
			
				|  |  | +                () -> now,
 | 
	
		
			
				|  |  | +                randomBoolean() ? randomGlobalRetention() : null
 | 
	
		
			
				|  |  |              );
 | 
	
		
			
				|  |  | -            Metadata metadata = builder.build();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getIndicesPastRetention(metadata::index, () -> now, globalRetention);
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.size(), is(2));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(0).getName(), is(dataStream.getIndices().get(0).getName()));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(1).getName(), is(dataStream.getIndices().get(1).getName()));
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.size(), is(2));
 | 
	
		
			
				|  |  | +            for (int i = 0; i < failureIndices.size(); i++) {
 | 
	
		
			
				|  |  | +                assertThat(failureIndices.get(i).getName(), is(dataStream.getFailureIndices().get(i).getName()));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            // no retention configured but we have max retention
 | 
	
		
			
				|  |  | -            DataStreamGlobalRetention globalRetention = new DataStreamGlobalRetention(null, TimeValue.timeValueSeconds(2500));
 | 
	
		
			
				|  |  | -            Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | -            DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | -                builder,
 | 
	
		
			
				|  |  | -                dataStreamName,
 | 
	
		
			
				|  |  | -                creationAndRolloverTimes,
 | 
	
		
			
				|  |  | -                settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | -                new DataStreamLifecycle()
 | 
	
		
			
				|  |  | -            );
 | 
	
		
			
				|  |  | -            Metadata metadata = builder.build();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getIndicesPastRetention(metadata::index, () -> now, globalRetention);
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.size(), is(2));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(0).getName(), is(dataStream.getIndices().get(0).getName()));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(1).getName(), is(dataStream.getIndices().get(1).getName()));
 | 
	
		
			
				|  |  | +            // All indices past retention, but we keep the write index
 | 
	
		
			
				|  |  | +            retention.set(TimeValue.timeValueSeconds(0));
 | 
	
		
			
				|  |  | +            List<Index> failureIndices = dataStream.getFailureIndicesPastRetention(metadata::index, () -> now, null);
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.size(), is(4));
 | 
	
		
			
				|  |  | +            for (int i = 0; i < failureIndices.size(); i++) {
 | 
	
		
			
				|  |  | +                assertThat(failureIndices.get(i).getName(), is(dataStream.getFailureIndices().get(i).getName()));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | -            DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | -                builder,
 | 
	
		
			
				|  |  | -                dataStreamName,
 | 
	
		
			
				|  |  | -                creationAndRolloverTimes,
 | 
	
		
			
				|  |  | -                settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | -                DataStreamLifecycle.builder().dataRetention(TimeValue.timeValueSeconds(2500)).build()
 | 
	
		
			
				|  |  | -            );
 | 
	
		
			
				|  |  | -            Metadata metadata = builder.build();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getIndicesPastRetention(metadata::index, () -> now, randomGlobalRetention());
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.size(), is(2));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(0).getName(), is(dataStream.getIndices().get(0).getName()));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(1).getName(), is(dataStream.getIndices().get(1).getName()));
 | 
	
		
			
				|  |  | +            // All indices younger than retention
 | 
	
		
			
				|  |  | +            retention.set(TimeValue.timeValueSeconds(6000));
 | 
	
		
			
				|  |  | +            List<Index> failureIndices = dataStream.getFailureIndicesPastRetention(metadata::index, () -> now, null);
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.isEmpty(), is(true));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            // even though all indices match the write index should not be returned
 | 
	
		
			
				|  |  | -            Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | -            DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | -                builder,
 | 
	
		
			
				|  |  | -                dataStreamName,
 | 
	
		
			
				|  |  | -                creationAndRolloverTimes,
 | 
	
		
			
				|  |  | -                settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | -                DataStreamLifecycle.builder().dataRetention(TimeValue.ZERO).build()
 | 
	
		
			
				|  |  | -            );
 | 
	
		
			
				|  |  | -            Metadata metadata = builder.build();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getIndicesPastRetention(metadata::index, () -> now, randomGlobalRetention());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.size(), is(4));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(0).getName(), is(dataStream.getIndices().get(0).getName()));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(1).getName(), is(dataStream.getIndices().get(1).getName()));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(2).getName(), is(dataStream.getIndices().get(2).getName()));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(3).getName(), is(dataStream.getIndices().get(3).getName()));
 | 
	
		
			
				|  |  | +            // Test predicate that influences which indices are candidates for a retention check
 | 
	
		
			
				|  |  | +            Function<String, IndexMetadata> indexMetadataWithSomeLifecycleSupplier = indexName -> {
 | 
	
		
			
				|  |  | +                IndexMetadata indexMetadata = metadata.index(indexName);
 | 
	
		
			
				|  |  | +                if (indexName.endsWith("00003") || indexName.endsWith("00005")) {
 | 
	
		
			
				|  |  | +                    return indexMetadata;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                return IndexMetadata.builder(indexMetadata)
 | 
	
		
			
				|  |  | +                    .settings(Settings.builder().put(indexMetadata.getSettings()).put(IndexMetadata.LIFECYCLE_NAME, "some-policy").build())
 | 
	
		
			
				|  |  | +                    .build();
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  | +            retention.set(TimeValue.timeValueSeconds(0));
 | 
	
		
			
				|  |  | +            List<Index> failureIndices = dataStream.getFailureIndicesPastRetention(indexMetadataWithSomeLifecycleSupplier, () -> now, null);
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.size(), is(1));
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.get(0).getName(), is(dataStream.getFailureIndices().get(2).getName()));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            // no index matches the retention age
 | 
	
		
			
				|  |  | -            Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | -            DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | -                builder,
 | 
	
		
			
				|  |  | -                dataStreamName,
 | 
	
		
			
				|  |  | -                creationAndRolloverTimes,
 | 
	
		
			
				|  |  | -                settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | -                DataStreamLifecycle.builder().dataRetention(TimeValue.timeValueSeconds(6000)).build()
 | 
	
		
			
				|  |  | +            // no retention configured but we have default retention
 | 
	
		
			
				|  |  | +            DataStreamGlobalRetention globalRetention = new DataStreamGlobalRetention(
 | 
	
		
			
				|  |  | +                TimeValue.timeValueSeconds(2500),
 | 
	
		
			
				|  |  | +                randomBoolean() ? TimeValue.timeValueSeconds(randomIntBetween(2500, 5000)) : null
 | 
	
		
			
				|  |  |              );
 | 
	
		
			
				|  |  | -            Metadata metadata = builder.build();
 | 
	
		
			
				|  |  | +            retention.set(null);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getIndicesPastRetention(metadata::index, () -> now, randomGlobalRetention());
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.isEmpty(), is(true));
 | 
	
		
			
				|  |  | +            List<Index> failureIndices = dataStream.getFailureIndicesPastRetention(metadata::index, () -> now, globalRetention);
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.size(), is(2));
 | 
	
		
			
				|  |  | +            for (int i = 0; i < failureIndices.size(); i++) {
 | 
	
		
			
				|  |  | +                assertThat(failureIndices.get(i).getName(), is(dataStream.getFailureIndices().get(i).getName()));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            // no indices are returned as even though all pass retention age none are managed by data stream lifecycle
 | 
	
		
			
				|  |  | -            Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | -            DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | -                builder,
 | 
	
		
			
				|  |  | -                dataStreamName,
 | 
	
		
			
				|  |  | -                creationAndRolloverTimes,
 | 
	
		
			
				|  |  | -                Settings.builder()
 | 
	
		
			
				|  |  | -                    .put(IndexMetadata.LIFECYCLE_NAME, "ILM_policy")
 | 
	
		
			
				|  |  | -                    .put(IndexMetadata.SETTING_VERSION_CREATED, IndexVersion.current()),
 | 
	
		
			
				|  |  | -                DataStreamLifecycle.builder().dataRetention(TimeValue.ZERO).build()
 | 
	
		
			
				|  |  | -            );
 | 
	
		
			
				|  |  | -            Metadata metadata = builder.build();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getIndicesPastRetention(metadata::index, () -> now, randomGlobalRetention());
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.isEmpty(), is(true));
 | 
	
		
			
				|  |  | +            // no retention or too large retention configured and we have max retention
 | 
	
		
			
				|  |  | +            DataStreamGlobalRetention globalRetention = new DataStreamGlobalRetention(null, TimeValue.timeValueSeconds(2500));
 | 
	
		
			
				|  |  | +            retention.set(randomBoolean() ? TimeValue.timeValueDays(6000) : null);
 | 
	
		
			
				|  |  | +            List<Index> failureIndices = dataStream.getFailureIndicesPastRetention(metadata::index, () -> now, globalRetention);
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.size(), is(2));
 | 
	
		
			
				|  |  | +            for (int i = 0; i < failureIndices.size(); i++) {
 | 
	
		
			
				|  |  | +                assertThat(failureIndices.get(i).getName(), is(dataStream.getFailureIndices().get(i).getName()));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    public void testGetIndicesPastRetentionWithOriginationDate() {
 | 
	
		
			
				|  |  | +    public void testBackingIndicesPastRetentionWithOriginationDate() {
 | 
	
		
			
				|  |  |          // First, build an ordinary data stream:
 | 
	
		
			
				|  |  |          String dataStreamName = "metrics-foo";
 | 
	
		
			
				|  |  |          long now = System.currentTimeMillis();
 | 
	
	
		
			
				|  | @@ -1550,13 +1626,13 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              // no retention configured so we expect an empty list
 | 
	
		
			
				|  |  |              testRetentionReference.set(null);
 | 
	
		
			
				|  |  | -            assertThat(dataStream.getIndicesPastRetention(metadata::index, () -> now, null).isEmpty(), is(true));
 | 
	
		
			
				|  |  | +            assertThat(dataStream.getBackingIndicesPastRetention(metadata::index, () -> now, null).isEmpty(), is(true));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            // retention period where oldIndex is too old, but newIndex should be retained
 | 
	
		
			
				|  |  | +            // retention period where first and second index is too old, and 5th has old origination date.
 | 
	
		
			
				|  |  |              testRetentionReference.set(TimeValue.timeValueMillis(2500));
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getIndicesPastRetention(metadata::index, () -> now, null);
 | 
	
		
			
				|  |  | +            List<Index> backingIndices = dataStream.getBackingIndicesPastRetention(metadata::index, () -> now, null);
 | 
	
		
			
				|  |  |              assertThat(backingIndices.size(), is(3));
 | 
	
		
			
				|  |  |              assertThat(backingIndices.get(0).getName(), is(dataStream.getIndices().get(0).getName()));
 | 
	
		
			
				|  |  |              assertThat(backingIndices.get(1).getName(), is(dataStream.getIndices().get(1).getName()));
 | 
	
	
		
			
				|  | @@ -1564,24 +1640,61 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            // even though all indices match the write index should not be returned
 | 
	
		
			
				|  |  | -            testRetentionReference.set(TimeValue.timeValueMillis(0));
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getIndicesPastRetention(metadata::index, () -> now, null);
 | 
	
		
			
				|  |  | +            // no index matches the retention age
 | 
	
		
			
				|  |  | +            testRetentionReference.set(TimeValue.timeValueMillis(9000));
 | 
	
		
			
				|  |  | +            List<Index> backingIndices = dataStream.getBackingIndicesPastRetention(metadata::index, () -> now, null);
 | 
	
		
			
				|  |  | +            assertThat(backingIndices.isEmpty(), is(true));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.size(), is(6));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(0).getName(), is(dataStream.getIndices().get(0).getName()));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(1).getName(), is(dataStream.getIndices().get(1).getName()));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(2).getName(), is(dataStream.getIndices().get(2).getName()));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(3).getName(), is(dataStream.getIndices().get(3).getName()));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(4).getName(), is(dataStream.getIndices().get(4).getName()));
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.get(5).getName(), is(dataStream.getIndices().get(5).getName()));
 | 
	
		
			
				|  |  | +    public void testFailureIndicesPastRetentionWithOriginationDate() {
 | 
	
		
			
				|  |  | +        // First, build an ordinary data stream:
 | 
	
		
			
				|  |  | +        String dataStreamName = "metrics-foo";
 | 
	
		
			
				|  |  | +        long now = System.currentTimeMillis();
 | 
	
		
			
				|  |  | +        List<DataStreamMetadata> creationAndRolloverTimes = List.of(
 | 
	
		
			
				|  |  | +            DataStreamMetadata.dataStreamMetadata(now - 5000, now - 4000),
 | 
	
		
			
				|  |  | +            DataStreamMetadata.dataStreamMetadata(now - 4000, now - 3000),
 | 
	
		
			
				|  |  | +            DataStreamMetadata.dataStreamMetadata(now - 3000, now - 2000),
 | 
	
		
			
				|  |  | +            DataStreamMetadata.dataStreamMetadata(now - 2000, now - 1000),
 | 
	
		
			
				|  |  | +            DataStreamMetadata.dataStreamMetadata(now, null, now - 8000), // origination date older than retention
 | 
	
		
			
				|  |  | +            DataStreamMetadata.dataStreamMetadata(now, null, now - 1000), // origination date within retention
 | 
	
		
			
				|  |  | +            DataStreamMetadata.dataStreamMetadata(now, null)
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +        Metadata.Builder metadataBuilder = Metadata.builder();
 | 
	
		
			
				|  |  | +        AtomicReference<TimeValue> testRetentionReference = new AtomicReference<>(null);
 | 
	
		
			
				|  |  | +        DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | +            metadataBuilder,
 | 
	
		
			
				|  |  | +            dataStreamName,
 | 
	
		
			
				|  |  | +            creationAndRolloverTimes,
 | 
	
		
			
				|  |  | +            settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | +            new DataStreamLifecycle() {
 | 
	
		
			
				|  |  | +                public TimeValue dataRetention() {
 | 
	
		
			
				|  |  | +                    return testRetentionReference.get();
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +        Metadata metadata = metadataBuilder.build();
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            // no retention configured so we expect an empty list
 | 
	
		
			
				|  |  | +            testRetentionReference.set(null);
 | 
	
		
			
				|  |  | +            assertThat(dataStream.getFailureIndicesPastRetention(metadata::index, () -> now, null).isEmpty(), is(true));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            // retention period where first and second index is too old, and 5th has old origination date.
 | 
	
		
			
				|  |  | +            testRetentionReference.set(TimeValue.timeValueMillis(2500));
 | 
	
		
			
				|  |  | +            List<Index> failureIndices = dataStream.getFailureIndicesPastRetention(metadata::index, () -> now, null);
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.size(), is(3));
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.get(0).getName(), is(dataStream.getFailureIndices().get(0).getName()));
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.get(1).getName(), is(dataStream.getFailureIndices().get(1).getName()));
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.get(2).getName(), is(dataStream.getFailureIndices().get(5).getName()));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              // no index matches the retention age
 | 
	
		
			
				|  |  |              testRetentionReference.set(TimeValue.timeValueMillis(9000));
 | 
	
		
			
				|  |  | -            List<Index> backingIndices = dataStream.getIndicesPastRetention(metadata::index, () -> now, null);
 | 
	
		
			
				|  |  | -            assertThat(backingIndices.isEmpty(), is(true));
 | 
	
		
			
				|  |  | +            List<Index> failureIndices = dataStream.getFailureIndicesPastRetention(metadata::index, () -> now, null);
 | 
	
		
			
				|  |  | +            assertThat(failureIndices.isEmpty(), is(true));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1842,55 +1955,48 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    public void testGetIndicesOlderThanWithOriginationDate() {
 | 
	
		
			
				|  |  | -        // First, build an ordinary datastream:
 | 
	
		
			
				|  |  | -        String dataStreamName = "metrics-foo";
 | 
	
		
			
				|  |  | -        long now = System.currentTimeMillis();
 | 
	
		
			
				|  |  | -        List<DataStreamMetadata> creationAndRolloverTimes = List.of(
 | 
	
		
			
				|  |  | -            DataStreamMetadata.dataStreamMetadata(now - 5000, now - 4000),
 | 
	
		
			
				|  |  | -            DataStreamMetadata.dataStreamMetadata(now - 4000, now - 3000),
 | 
	
		
			
				|  |  | -            DataStreamMetadata.dataStreamMetadata(now - 3000, now - 2000),
 | 
	
		
			
				|  |  | -            DataStreamMetadata.dataStreamMetadata(now - 2000, now - 1000),
 | 
	
		
			
				|  |  | -            DataStreamMetadata.dataStreamMetadata(now, null, now - 7000), // origination date older than retention
 | 
	
		
			
				|  |  | -            DataStreamMetadata.dataStreamMetadata(now, null, now - 1000), // origination date within retention
 | 
	
		
			
				|  |  | -            DataStreamMetadata.dataStreamMetadata(now, null, now - 7000) // write index origination date older than retention
 | 
	
		
			
				|  |  | -        );
 | 
	
		
			
				|  |  | -        Metadata.Builder builder = Metadata.builder();
 | 
	
		
			
				|  |  | -        DataStream dataStream = createDataStream(
 | 
	
		
			
				|  |  | +    private DataStream createDataStream(
 | 
	
		
			
				|  |  | +        Metadata.Builder builder,
 | 
	
		
			
				|  |  | +        String dataStreamName,
 | 
	
		
			
				|  |  | +        List<DataStreamMetadata> creationAndRolloverTimes,
 | 
	
		
			
				|  |  | +        Settings.Builder backingIndicesSettings,
 | 
	
		
			
				|  |  | +        @Nullable DataStreamLifecycle lifecycle
 | 
	
		
			
				|  |  | +    ) {
 | 
	
		
			
				|  |  | +        int backingIndicesCount = creationAndRolloverTimes.size();
 | 
	
		
			
				|  |  | +        final List<Index> backingIndices = createDataStreamIndices(
 | 
	
		
			
				|  |  |              builder,
 | 
	
		
			
				|  |  |              dataStreamName,
 | 
	
		
			
				|  |  |              creationAndRolloverTimes,
 | 
	
		
			
				|  |  | -            settings(IndexVersion.current()),
 | 
	
		
			
				|  |  | -            new DataStreamLifecycle()
 | 
	
		
			
				|  |  | +            backingIndicesSettings,
 | 
	
		
			
				|  |  | +            backingIndicesCount,
 | 
	
		
			
				|  |  | +            false
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  | -        Metadata metadata = builder.build();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        List<Index> backingIndices = dataStream.getNonWriteIndicesOlderThan(
 | 
	
		
			
				|  |  | -            TimeValue.timeValueMillis(2500),
 | 
	
		
			
				|  |  | -            metadata::index,
 | 
	
		
			
				|  |  | -            null,
 | 
	
		
			
				|  |  | -            () -> now
 | 
	
		
			
				|  |  | +        final List<Index> failureIndices = createDataStreamIndices(
 | 
	
		
			
				|  |  | +            builder,
 | 
	
		
			
				|  |  | +            dataStreamName,
 | 
	
		
			
				|  |  | +            creationAndRolloverTimes,
 | 
	
		
			
				|  |  | +            backingIndicesSettings,
 | 
	
		
			
				|  |  | +            backingIndicesCount,
 | 
	
		
			
				|  |  | +            true
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  | -        // We expect to see the index with the really old origination date, but not the one with the more recent origination date (and
 | 
	
		
			
				|  |  | -        // not the write index)
 | 
	
		
			
				|  |  | -        assertThat(backingIndices.size(), is(3));
 | 
	
		
			
				|  |  | -        assertThat(backingIndices.get(0).getName(), is(DataStream.getDefaultBackingIndexName(dataStreamName, 1)));
 | 
	
		
			
				|  |  | -        assertThat(backingIndices.get(1).getName(), is(DataStream.getDefaultBackingIndexName(dataStreamName, 2)));
 | 
	
		
			
				|  |  | -        assertThat(backingIndices.get(2).getName(), is(DataStream.getDefaultBackingIndexName(dataStreamName, 6)));
 | 
	
		
			
				|  |  | +        return newInstance(dataStreamName, backingIndices, backingIndicesCount, null, false, lifecycle, failureIndices);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    private DataStream createDataStream(
 | 
	
		
			
				|  |  | +    private static List<Index> createDataStreamIndices(
 | 
	
		
			
				|  |  |          Metadata.Builder builder,
 | 
	
		
			
				|  |  |          String dataStreamName,
 | 
	
		
			
				|  |  |          List<DataStreamMetadata> creationAndRolloverTimes,
 | 
	
		
			
				|  |  |          Settings.Builder backingIndicesSettings,
 | 
	
		
			
				|  |  | -        @Nullable DataStreamLifecycle lifecycle
 | 
	
		
			
				|  |  | +        int backingIndicesCount,
 | 
	
		
			
				|  |  | +        boolean isFailureStore
 | 
	
		
			
				|  |  |      ) {
 | 
	
		
			
				|  |  | -        int backingIndicesCount = creationAndRolloverTimes.size();
 | 
	
		
			
				|  |  | -        final List<Index> backingIndices = new ArrayList<>();
 | 
	
		
			
				|  |  | +        List<Index> indices = new ArrayList<>(backingIndicesCount);
 | 
	
		
			
				|  |  |          for (int k = 1; k <= backingIndicesCount; k++) {
 | 
	
		
			
				|  |  |              DataStreamMetadata creationRolloverTime = creationAndRolloverTimes.get(k - 1);
 | 
	
		
			
				|  |  | -            IndexMetadata.Builder indexMetaBuilder = IndexMetadata.builder(DataStream.getDefaultBackingIndexName(dataStreamName, k))
 | 
	
		
			
				|  |  | +            String indexName = isFailureStore
 | 
	
		
			
				|  |  | +                ? getDefaultFailureStoreName(dataStreamName, k, System.currentTimeMillis())
 | 
	
		
			
				|  |  | +                : DataStream.getDefaultBackingIndexName(dataStreamName, k);
 | 
	
		
			
				|  |  | +            IndexMetadata.Builder indexMetaBuilder = IndexMetadata.builder(indexName)
 | 
	
		
			
				|  |  |                  .settings(backingIndicesSettings)
 | 
	
		
			
				|  |  |                  .numberOfShards(1)
 | 
	
		
			
				|  |  |                  .numberOfReplicas(1)
 | 
	
	
		
			
				|  | @@ -1906,12 +2012,15 @@ public class DataStreamTests extends AbstractXContentSerializingTestCase<DataStr
 | 
	
		
			
				|  |  |              Long originationTimeInMillis = creationRolloverTime.originationTimeInMillis;
 | 
	
		
			
				|  |  |              if (originationTimeInMillis != null) {
 | 
	
		
			
				|  |  |                  backingIndicesSettings.put(LIFECYCLE_ORIGINATION_DATE, originationTimeInMillis);
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                // We reuse the backingIndicesSettings, so it's important to reset it
 | 
	
		
			
				|  |  | +                backingIndicesSettings.putNull(LIFECYCLE_ORIGINATION_DATE);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              IndexMetadata indexMetadata = indexMetaBuilder.build();
 | 
	
		
			
				|  |  |              builder.put(indexMetadata, false);
 | 
	
		
			
				|  |  | -            backingIndices.add(indexMetadata.getIndex());
 | 
	
		
			
				|  |  | +            indices.add(indexMetadata.getIndex());
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        return newInstance(dataStreamName, backingIndices, backingIndicesCount, null, false, lifecycle);
 | 
	
		
			
				|  |  | +        return indices;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public void testXContentSerializationWithRolloverAndEffectiveRetention() throws IOException {
 |