diff --git a/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequestBuilder.java b/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequestBuilder.java index 5edd55796ac..e05dbc60697 100644 --- a/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequestBuilder.java +++ b/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequestBuilder.java @@ -233,7 +233,6 @@ public class RestoreSnapshotRequestBuilder extends MasterNodeOperationRequestBui /** * Sets index settings that should be added or replaced during restore - * @param settings index settings * @return this builder */ diff --git a/src/test/java/org/elasticsearch/index/IndexWithShadowReplicasTests.java b/src/test/java/org/elasticsearch/index/IndexWithShadowReplicasTests.java index c9bdc514396..db23b5aeec5 100644 --- a/src/test/java/org/elasticsearch/index/IndexWithShadowReplicasTests.java +++ b/src/test/java/org/elasticsearch/index/IndexWithShadowReplicasTests.java @@ -19,6 +19,8 @@ package org.elasticsearch.index; +import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse; +import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotResponse; import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexRequestBuilder; @@ -28,19 +30,26 @@ import org.elasticsearch.cluster.routing.RoutingNode; import org.elasticsearch.cluster.routing.RoutingNodes; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.shard.IndexShard; +import org.elasticsearch.index.shard.ShadowIndexShard; +import org.elasticsearch.indices.IndicesService; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.sort.SortOrder; +import org.elasticsearch.snapshots.SnapshotState; import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.elasticsearch.test.InternalTestCluster; import org.junit.Test; import java.nio.file.Path; import java.util.List; +import java.util.concurrent.ExecutionException; import static com.google.common.collect.Lists.newArrayList; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.*; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.greaterThanOrEqualTo; /** @@ -49,7 +58,69 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo; @ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.TEST, numDataNodes = 0) public class IndexWithShadowReplicasTests extends ElasticsearchIntegrationTest { - @Test + /** + * Tests the case where we create an index without shadow replicas, snapshot it and then restore into + * an index with shadow replicas enabled. + */ + public void testRestoreToShadow() throws ExecutionException, InterruptedException { + Settings nodeSettings = ImmutableSettings.builder() + .put("node.add_id_to_custom_path", false) + .put("node.enable_custom_paths", true) + .build(); + + internalCluster().startNodesAsync(3, nodeSettings).get(); + final Path dataPath = newTempDirPath(); + Settings idxSettings = ImmutableSettings.builder() + .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1) + .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0).build(); + assertAcked(prepareCreate("foo").setSettings(idxSettings)); + ensureGreen(); + final int numDocs = randomIntBetween(10, 100); + for (int i = 0; i < numDocs; i++) { + client().prepareIndex("foo", "doc", ""+i).setSource("foo", "bar").get(); + } + assertNoFailures(client().admin().indices().prepareFlush().setForce(true).setWaitIfOngoing(true).execute().actionGet()); + + assertAcked(client().admin().cluster().preparePutRepository("test-repo") + .setType("fs").setSettings(ImmutableSettings.settingsBuilder() + .put("location", newTempDirPath()))); + CreateSnapshotResponse createSnapshotResponse = client().admin().cluster().prepareCreateSnapshot("test-repo", "test-snap").setWaitForCompletion(true).setIndices("foo").get(); + assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0)); + assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), equalTo(createSnapshotResponse.getSnapshotInfo().totalShards())); + assertThat(client().admin().cluster().prepareGetSnapshots("test-repo").setSnapshots("test-snap").get().getSnapshots().get(0).state(), equalTo(SnapshotState.SUCCESS)); + + Settings shadowSettings = ImmutableSettings.builder() + .put(IndexMetaData.SETTING_DATA_PATH, dataPath.toAbsolutePath().toString()) + .put(IndexMetaData.SETTING_SHADOW_REPLICAS, true) + .put(IndexMetaData.SETTING_SHARED_FILESYSTEM, true) + .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 2).build(); + + logger.info("--> restore the index into shadow replica index"); + RestoreSnapshotResponse restoreSnapshotResponse = client().admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap") + .setIndexSettings(shadowSettings).setWaitForCompletion(true) + .setRenamePattern("(.+)").setRenameReplacement("$1-copy") + .execute().actionGet(); + assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0)); + ensureGreen(); + refresh(); + + for (IndicesService service : internalCluster().getDataNodeInstances(IndicesService.class)) { + if (service.hasIndex("foo-copy")) { + IndexShard shard = service.indexServiceSafe("foo-copy").shard(0); + if (shard.routingEntry().primary()) { + assertFalse(shard instanceof ShadowIndexShard); + } else { + assertTrue(shard instanceof ShadowIndexShard); + } + } + } + logger.info("--> performing query"); + SearchResponse resp = client().prepareSearch("foo-copy").setQuery(matchAllQuery()).get(); + assertHitCount(resp, numDocs); + + } + + @Test public void testIndexWithFewDocuments() throws Exception { Settings nodeSettings = ImmutableSettings.builder() .put("node.add_id_to_custom_path", false)