Skip to content

Commit 14daacf

Browse files
Implement repair functionality for aliases colliding with indices bug (#91887) (#91988)
Follow up to #91456 implementing an automated fix for indices corrupted in 8.5.
1 parent e75a665 commit 14daacf

File tree

2 files changed

+58
-15
lines changed

2 files changed

+58
-15
lines changed

server/src/main/java/org/elasticsearch/cluster/metadata/IndexMetadata.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
package org.elasticsearch.cluster.metadata;
1010

11+
import org.apache.logging.log4j.LogManager;
12+
import org.apache.logging.log4j.Logger;
1113
import org.elasticsearch.Version;
1214
import org.elasticsearch.action.admin.indices.rollover.RolloverInfo;
1315
import org.elasticsearch.action.support.ActiveShardCount;
@@ -83,6 +85,8 @@
8385

8486
public class IndexMetadata implements Diffable<IndexMetadata>, ToXContentFragment {
8587

88+
private static final Logger logger = LogManager.getLogger(IndexMetadata.class);
89+
8690
public static final ClusterBlock INDEX_READ_ONLY_BLOCK = new ClusterBlock(
8791
5,
8892
"index read-only (api)",
@@ -1589,7 +1593,7 @@ public IndexMetadata apply(IndexMetadata part) {
15891593
builder.stats(stats);
15901594
builder.indexWriteLoadForecast(indexWriteLoadForecast);
15911595
builder.shardSizeInBytesForecast(shardSizeInBytesForecast);
1592-
return builder.build();
1596+
return builder.build(true);
15931597
}
15941598
}
15951599

@@ -1656,7 +1660,7 @@ public static IndexMetadata readFrom(StreamInput in, @Nullable Function<String,
16561660
builder.indexWriteLoadForecast(in.readOptionalDouble());
16571661
builder.shardSizeInBytesForecast(in.readOptionalLong());
16581662
}
1659-
return builder.build();
1663+
return builder.build(true);
16601664
}
16611665

16621666
/**
@@ -2012,6 +2016,11 @@ public Builder shardSizeInBytesForecast(Long shardSizeInBytesForecast) {
20122016
}
20132017

20142018
public IndexMetadata build() {
2019+
return build(false);
2020+
}
2021+
2022+
// package private for testing
2023+
IndexMetadata build(boolean repair) {
20152024
/*
20162025
* We expect that the metadata has been properly built to set the number of shards and the number of replicas, and do not rely
20172026
* on the default values here. Those must have been set upstream.
@@ -2140,7 +2149,16 @@ public IndexMetadata build() {
21402149
var aliasesMap = aliases.build();
21412150
for (AliasMetadata alias : aliasesMap.values()) {
21422151
if (alias.alias().equals(index)) {
2143-
throw new IllegalArgumentException("alias name [" + index + "] self-conflicts with index name");
2152+
if (repair && indexCreatedVersion.equals(Version.V_8_5_0)) {
2153+
var updatedBuilder = ImmutableOpenMap.builder(aliasesMap);
2154+
final var brokenAlias = updatedBuilder.remove(index);
2155+
final var fixedAlias = AliasMetadata.newAliasMetadata(brokenAlias, index + "-alias-corrupted-by-8-5");
2156+
aliasesMap = updatedBuilder.fPut(fixedAlias.getAlias(), fixedAlias).build();
2157+
logger.warn("Repaired corrupted alias with the same name as its index for [{}]", index);
2158+
break;
2159+
} else {
2160+
throw new IllegalArgumentException("alias name [" + index + "] self-conflicts with index name");
2161+
}
21442162
}
21452163
}
21462164

@@ -2463,7 +2481,7 @@ public static IndexMetadata fromXContent(XContentParser parser, Map<String, Mapp
24632481
assert settingsVersion : "settings version should be present for indices created on or after 6.5.0";
24642482
assert indexCreatedVersion(builder.settings).before(Version.V_7_2_0) || aliasesVersion
24652483
: "aliases version should be present for indices created on or after 7.2.0";
2466-
return builder.build();
2484+
return builder.build(true);
24672485
}
24682486

24692487
/**
@@ -2574,7 +2592,7 @@ public static IndexMetadata legacyFromXContent(XContentParser parser) throws IOE
25742592
builder.putMapping(MappingMetadata.EMPTY_MAPPINGS); // just make sure it's not empty so that _source can be read
25752593
}
25762594

2577-
IndexMetadata indexMetadata = builder.build();
2595+
IndexMetadata indexMetadata = builder.build(true);
25782596
assert indexMetadata.getCreationVersion().isLegacyIndexVersion();
25792597
assert indexMetadata.getCompatibilityVersion().isLegacyIndexVersion();
25802598
return indexMetadata;

server/src/test/java/org/elasticsearch/cluster/metadata/IndexMetadataTests.java

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import static org.elasticsearch.cluster.metadata.IndexMetadata.parseIndexNameCounter;
4848
import static org.hamcrest.Matchers.containsString;
4949
import static org.hamcrest.Matchers.equalTo;
50+
import static org.hamcrest.Matchers.hasKey;
5051
import static org.hamcrest.Matchers.is;
5152

5253
public class IndexMetadataTests extends ESTestCase {
@@ -497,16 +498,40 @@ public void testLifeCyclePolicyName() {
497498
}
498499

499500
public void testIndexAndAliasWithSameName() {
500-
final IllegalArgumentException iae = expectThrows(
501-
IllegalArgumentException.class,
502-
() -> IndexMetadata.builder("index")
503-
.settings(Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT))
504-
.numberOfShards(1)
505-
.numberOfReplicas(0)
506-
.putAlias(AliasMetadata.builder("index").build())
507-
.build()
508-
);
509-
assertEquals("alias name [index] self-conflicts with index name", iae.getMessage());
501+
{
502+
final IllegalArgumentException iae = expectThrows(
503+
IllegalArgumentException.class,
504+
() -> IndexMetadata.builder("index")
505+
.settings(Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT))
506+
.numberOfShards(1)
507+
.numberOfReplicas(0)
508+
.putAlias(AliasMetadata.builder("index").build())
509+
.build(randomBoolean())
510+
);
511+
assertEquals("alias name [index] self-conflicts with index name", iae.getMessage());
512+
}
513+
{
514+
final IllegalArgumentException iae = expectThrows(
515+
IllegalArgumentException.class,
516+
() -> IndexMetadata.builder("index")
517+
.settings(Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.V_8_5_0))
518+
.numberOfShards(1)
519+
.numberOfReplicas(0)
520+
.putAlias(AliasMetadata.builder("index").build())
521+
.build(false)
522+
);
523+
assertEquals("alias name [index] self-conflicts with index name", iae.getMessage());
524+
}
525+
}
526+
527+
public void testRepairIndexAndAliasWithSameName() {
528+
final IndexMetadata indexMetadata = IndexMetadata.builder("index")
529+
.settings(Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.V_8_5_0))
530+
.numberOfShards(1)
531+
.numberOfReplicas(0)
532+
.putAlias(AliasMetadata.builder("index").build())
533+
.build(true);
534+
assertThat(indexMetadata.getAliases(), hasKey("index-alias-corrupted-by-8-5"));
510535
}
511536

512537
private static Settings indexSettingsWithDataTier(String dataTier) {

0 commit comments

Comments
 (0)