|
@@ -23,10 +23,14 @@ import org.elasticsearch.action.ActionFuture;
|
|
|
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
|
|
|
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest;
|
|
|
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsResponse;
|
|
|
+import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotIndexShardStage;
|
|
|
+import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotIndexShardStatus;
|
|
|
+import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStats;
|
|
|
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStatus;
|
|
|
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
|
|
|
import org.elasticsearch.client.Client;
|
|
|
import org.elasticsearch.cluster.SnapshotsInProgress;
|
|
|
+import org.elasticsearch.cluster.metadata.IndexMetadata;
|
|
|
import org.elasticsearch.common.settings.Settings;
|
|
|
import org.elasticsearch.common.unit.TimeValue;
|
|
|
import org.elasticsearch.core.internal.io.IOUtils;
|
|
@@ -189,4 +193,111 @@ public class SnapshotStatusApisIT extends AbstractSnapshotIntegTestCase {
|
|
|
assertThat(found.snapshotId(), is(snapshotInfo.snapshotId()));
|
|
|
assertThat(found.state(), is(SnapshotState.SUCCESS));
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Tests the following sequence of steps:
|
|
|
+ * 1. Start snapshot of two shards (both located on separate data nodes).
|
|
|
+ * 2. Have one of the shards snapshot completely and the other block
|
|
|
+ * 3. Restart the data node that completed its shard snapshot
|
|
|
+ * 4. Make sure that snapshot status APIs show correct file-counts and -sizes
|
|
|
+ *
|
|
|
+ * @throws Exception on failure
|
|
|
+ */
|
|
|
+ public void testCorrectCountsForDoneShards() throws Exception {
|
|
|
+ final String indexOne = "index-1";
|
|
|
+ final String indexTwo = "index-2";
|
|
|
+ final List<String> dataNodes = internalCluster().startDataOnlyNodes(2);
|
|
|
+ final String dataNodeOne = dataNodes.get(0);
|
|
|
+ final String dataNodeTwo = dataNodes.get(1);
|
|
|
+
|
|
|
+ createIndex(indexOne, singleShardOneNode(dataNodeOne));
|
|
|
+ indexDoc(indexOne, "some_doc_id", "foo", "bar");
|
|
|
+ createIndex(indexTwo, singleShardOneNode(dataNodeTwo));
|
|
|
+ indexDoc(indexTwo, "some_doc_id", "foo", "bar");
|
|
|
+
|
|
|
+ final String repoName = "test-repo";
|
|
|
+ createRepository(repoName, "mock", randomRepoPath());
|
|
|
+
|
|
|
+ blockDataNode(repoName, dataNodeOne);
|
|
|
+
|
|
|
+ final String snapshotOne = "snap-1";
|
|
|
+ // restarting a data node below so using a master client here
|
|
|
+ final ActionFuture<CreateSnapshotResponse> responseSnapshotOne = internalCluster().masterClient().admin()
|
|
|
+ .cluster().prepareCreateSnapshot(repoName, snapshotOne).setWaitForCompletion(true).execute();
|
|
|
+
|
|
|
+ assertBusy(() -> {
|
|
|
+ final SnapshotStatus snapshotStatusOne = getSnapshotStatus(repoName, snapshotOne);
|
|
|
+ final SnapshotIndexShardStatus snapshotShardState = stateFirstShard(snapshotStatusOne, indexTwo);
|
|
|
+ assertThat(snapshotShardState.getStage(), is(SnapshotIndexShardStage.DONE));
|
|
|
+ assertThat(snapshotShardState.getStats().getTotalFileCount(), greaterThan(0));
|
|
|
+ assertThat(snapshotShardState.getStats().getTotalSize(), greaterThan(0L));
|
|
|
+ }, 30L, TimeUnit.SECONDS);
|
|
|
+
|
|
|
+ final SnapshotStats snapshotShardStats =
|
|
|
+ stateFirstShard(getSnapshotStatus(repoName, snapshotOne), indexTwo).getStats();
|
|
|
+ final int totalFiles = snapshotShardStats.getTotalFileCount();
|
|
|
+ final long totalFileSize = snapshotShardStats.getTotalSize();
|
|
|
+
|
|
|
+ internalCluster().restartNode(dataNodeTwo);
|
|
|
+
|
|
|
+ final SnapshotIndexShardStatus snapshotShardStateAfterNodeRestart =
|
|
|
+ stateFirstShard(getSnapshotStatus(repoName, snapshotOne), indexTwo);
|
|
|
+ assertThat(snapshotShardStateAfterNodeRestart.getStage(), is(SnapshotIndexShardStage.DONE));
|
|
|
+ assertThat(snapshotShardStateAfterNodeRestart.getStats().getTotalFileCount(), equalTo(totalFiles));
|
|
|
+ assertThat(snapshotShardStateAfterNodeRestart.getStats().getTotalSize(), equalTo(totalFileSize));
|
|
|
+
|
|
|
+ unblockAllDataNodes(repoName);
|
|
|
+ assertThat(responseSnapshotOne.get().getSnapshotInfo().state(), is(SnapshotState.SUCCESS));
|
|
|
+
|
|
|
+ // indexing another document to the second index so it will do writes during the snapshot and we can block on those writes
|
|
|
+ indexDoc(indexTwo, "some_other_doc_id", "foo", "other_bar");
|
|
|
+
|
|
|
+ blockDataNode(repoName, dataNodeTwo);
|
|
|
+
|
|
|
+ final String snapshotTwo = "snap-2";
|
|
|
+ final ActionFuture<CreateSnapshotResponse> responseSnapshotTwo =
|
|
|
+ client().admin().cluster().prepareCreateSnapshot(repoName, snapshotTwo).setWaitForCompletion(true).execute();
|
|
|
+
|
|
|
+ waitForBlock(dataNodeTwo, repoName, TimeValue.timeValueSeconds(30L));
|
|
|
+
|
|
|
+ assertBusy(() -> {
|
|
|
+ final SnapshotStatus snapshotStatusOne = getSnapshotStatus(repoName, snapshotOne);
|
|
|
+ final SnapshotStatus snapshotStatusTwo = getSnapshotStatus(repoName, snapshotTwo);
|
|
|
+ final SnapshotIndexShardStatus snapshotShardStateOne = stateFirstShard(snapshotStatusOne, indexOne);
|
|
|
+ final SnapshotIndexShardStatus snapshotShardStateTwo = stateFirstShard(snapshotStatusTwo, indexOne);
|
|
|
+ assertThat(snapshotShardStateOne.getStage(), is(SnapshotIndexShardStage.DONE));
|
|
|
+ assertThat(snapshotShardStateTwo.getStage(), is(SnapshotIndexShardStage.DONE));
|
|
|
+ final int totalFilesShardOne = snapshotShardStateOne.getStats().getTotalFileCount();
|
|
|
+ final long totalSizeShardOne = snapshotShardStateOne.getStats().getTotalSize();
|
|
|
+ assertThat(totalFilesShardOne, greaterThan(0));
|
|
|
+ assertThat(totalSizeShardOne, greaterThan(0L));
|
|
|
+ assertThat(totalFilesShardOne, equalTo(snapshotShardStateTwo.getStats().getTotalFileCount()));
|
|
|
+ assertThat(totalSizeShardOne, equalTo(snapshotShardStateTwo.getStats().getTotalSize()));
|
|
|
+ assertThat(snapshotShardStateTwo.getStats().getIncrementalFileCount(), equalTo(0));
|
|
|
+ assertThat(snapshotShardStateTwo.getStats().getIncrementalSize(), equalTo(0L));
|
|
|
+ }, 30L, TimeUnit.SECONDS);
|
|
|
+
|
|
|
+ unblockAllDataNodes(repoName);
|
|
|
+ assertThat(responseSnapshotTwo.get().getSnapshotInfo().state(), is(SnapshotState.SUCCESS));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static SnapshotIndexShardStatus stateFirstShard(SnapshotStatus snapshotStatus, String indexName) {
|
|
|
+ return snapshotStatus.getIndices().get(indexName).getShards().get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static SnapshotStatus getSnapshotStatus(String repoName, String snapshotName) {
|
|
|
+ try {
|
|
|
+ return client().admin().cluster().prepareSnapshotStatus(repoName).setSnapshots(snapshotName)
|
|
|
+ .get().getSnapshots().get(0);
|
|
|
+ } catch (SnapshotMissingException e) {
|
|
|
+ throw new AssertionError(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Settings singleShardOneNode(String node) {
|
|
|
+ return Settings.builder()
|
|
|
+ .put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
|
|
|
+ .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
|
|
+ .put("index.routing.allocation.include._name", node).build();
|
|
|
+ }
|
|
|
}
|