Skip to content

Commit 92d4287

Browse files
authored
RestoreService should update primary terms when restoring shards of existing indices (#38177)
When restoring shards of existing indices, the RestoreService also restores the values of primary terms stored in the snapshot index metadata. The primary terms are not updated and could potentially conflict with current index primary terms if the restored primary terms are lower than the existing ones. This situation is likely to happen with replicated closed indices (because primary terms are increased when the index is transitioning from open to closed state, and the snapshotted primary terms are the one at the time the index was opened) (see #38024) and maybe also with CCR. This commit changes the RestoreService so that it updates the primary terms using the maximum value between the snapshotted values and the existing values. Backport da6269b Related to #33888
1 parent 9ee0747 commit 92d4287

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

server/src/main/java/org/elasticsearch/snapshots/RestoreService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,12 @@ public ClusterState execute(ClusterState currentState) {
315315
currentIndexMetaData.getMappingVersion() + 1));
316316
indexMdBuilder.settingsVersion(Math.max(snapshotIndexMetaData.getSettingsVersion(),
317317
currentIndexMetaData.getSettingsVersion() + 1));
318+
319+
for (int shard = 0; shard < snapshotIndexMetaData.getNumberOfShards(); shard++) {
320+
indexMdBuilder.primaryTerm(shard,
321+
Math.max(snapshotIndexMetaData.primaryTerm(shard), currentIndexMetaData.primaryTerm(shard)));
322+
}
323+
318324
if (!request.includeAliases()) {
319325
// Remove all snapshot aliases
320326
if (!snapshotIndexMetaData.getAliases().isEmpty()) {

server/src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
import java.util.function.Consumer;
117117
import java.util.function.Predicate;
118118
import java.util.stream.Collectors;
119+
import java.util.stream.IntStream;
119120
import java.util.stream.Stream;
120121

121122
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
@@ -3704,6 +3705,48 @@ public void testAbortedSnapshotDuringInitDoesNotStart() throws Exception {
37043705
}
37053706
}
37063707

3708+
public void testRestoreIncreasesPrimaryTerms() {
3709+
final String indexName = randomAlphaOfLengthBetween(5, 10).toLowerCase(Locale.ROOT);
3710+
createIndex(indexName, Settings.builder()
3711+
.put(SETTING_NUMBER_OF_SHARDS, 2)
3712+
.put(SETTING_NUMBER_OF_REPLICAS, 0)
3713+
.build());
3714+
ensureGreen(indexName);
3715+
3716+
if (randomBoolean()) {
3717+
// open and close the index to increase the primary terms
3718+
for (int i = 0; i < randomInt(3); i++) {
3719+
assertAcked(client().admin().indices().prepareClose(indexName));
3720+
assertAcked(client().admin().indices().prepareOpen(indexName));
3721+
}
3722+
}
3723+
3724+
final IndexMetaData indexMetaData = client().admin().cluster().prepareState().clear().setIndices(indexName)
3725+
.setMetaData(true).get().getState().metaData().index(indexName);
3726+
final int numPrimaries = getNumShards(indexName).numPrimaries;
3727+
final Map<Integer, Long> primaryTerms = IntStream.range(0, numPrimaries)
3728+
.boxed().collect(Collectors.toMap(shardId -> shardId, indexMetaData::primaryTerm));
3729+
3730+
assertAcked(client().admin().cluster().preparePutRepository("test-repo").setType("fs").setSettings(randomRepoSettings()));
3731+
final CreateSnapshotResponse createSnapshotResponse = client().admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
3732+
.setWaitForCompletion(true).setIndices(indexName).get();
3733+
assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), equalTo(numPrimaries));
3734+
assertThat(createSnapshotResponse.getSnapshotInfo().failedShards(), equalTo(0));
3735+
3736+
assertAcked(client().admin().indices().prepareClose(indexName));
3737+
3738+
final RestoreSnapshotResponse restoreSnapshotResponse = client().admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
3739+
.setWaitForCompletion(true).get();
3740+
assertThat(restoreSnapshotResponse.getRestoreInfo().successfulShards(), equalTo(numPrimaries));
3741+
assertThat(restoreSnapshotResponse.getRestoreInfo().failedShards(), equalTo(0));
3742+
3743+
final IndexMetaData restoredIndexMetaData = client().admin().cluster().prepareState().clear().setIndices(indexName)
3744+
.setMetaData(true).get().getState().metaData().index(indexName);
3745+
for (int shardId = 0; shardId < numPrimaries; shardId++) {
3746+
assertThat(restoredIndexMetaData.primaryTerm(shardId), equalTo(primaryTerms.get(shardId) + 1));
3747+
}
3748+
}
3749+
37073750
private RepositoryData getRepositoryData(Repository repository) throws InterruptedException {
37083751
ThreadPool threadPool = internalCluster().getInstance(ThreadPool.class, internalCluster().getMasterName());
37093752
final SetOnce<RepositoryData> repositoryData = new SetOnce<>();

0 commit comments

Comments
 (0)