|
@@ -80,6 +80,7 @@ import org.elasticsearch.action.support.ActionTestUtils;
|
|
|
import org.elasticsearch.action.support.ActiveShardCount;
|
|
|
import org.elasticsearch.action.support.AutoCreateIndex;
|
|
|
import org.elasticsearch.action.support.DestructiveOperations;
|
|
|
+import org.elasticsearch.action.support.GroupedActionListener;
|
|
|
import org.elasticsearch.action.support.PlainActionFuture;
|
|
|
import org.elasticsearch.action.support.TransportAction;
|
|
|
import org.elasticsearch.action.support.WriteRequest;
|
|
@@ -502,6 +503,50 @@ public class SnapshotResiliencyTests extends ESTestCase {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public void testConcurrentSnapshotDeleteAndDeleteIndex() {
|
|
|
+ setupTestCluster(randomFrom(1, 3, 5), randomIntBetween(2, 10));
|
|
|
+
|
|
|
+ String repoName = "repo";
|
|
|
+ String snapshotName = "snapshot";
|
|
|
+ final String index = "test";
|
|
|
+
|
|
|
+ TestClusterNodes.TestClusterNode masterNode =
|
|
|
+ testClusterNodes.currentMaster(testClusterNodes.nodes.values().iterator().next().clusterService.state());
|
|
|
+
|
|
|
+ final StepListener<Collection<CreateIndexResponse>> createIndicesListener = new StepListener<>();
|
|
|
+
|
|
|
+ continueOrDie(createRepoAndIndex(repoName, index, 1), createIndexResponse -> {
|
|
|
+ // create a few more indices to make it more likely that the subsequent index delete operation happens before snapshot
|
|
|
+ // finalization
|
|
|
+ final int indices = randomIntBetween(5, 20);
|
|
|
+ final GroupedActionListener<CreateIndexResponse> listener = new GroupedActionListener<>(createIndicesListener, indices);
|
|
|
+ for (int i = 0; i < indices; ++i) {
|
|
|
+ client().admin().indices().create(new CreateIndexRequest("index-" + i), listener);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ final StepListener<CreateSnapshotResponse> createSnapshotResponseStepListener = new StepListener<>();
|
|
|
+
|
|
|
+ continueOrDie(createIndicesListener, createIndexResponses ->
|
|
|
+ client().admin().cluster().prepareCreateSnapshot(repoName, snapshotName).setWaitForCompletion(false)
|
|
|
+ .execute(createSnapshotResponseStepListener));
|
|
|
+
|
|
|
+ continueOrDie(createSnapshotResponseStepListener,
|
|
|
+ createSnapshotResponse -> client().admin().indices().delete(new DeleteIndexRequest(index), noopListener()));
|
|
|
+
|
|
|
+ deterministicTaskQueue.runAllRunnableTasks();
|
|
|
+
|
|
|
+ SnapshotsInProgress finalSnapshotsInProgress = masterNode.clusterService.state().custom(SnapshotsInProgress.TYPE);
|
|
|
+ assertFalse(finalSnapshotsInProgress.entries().stream().anyMatch(entry -> entry.state().completed() == false));
|
|
|
+ final Repository repository = masterNode.repositoriesService.repository(repoName);
|
|
|
+ Collection<SnapshotId> snapshotIds = getRepositoryData(repository).getSnapshotIds();
|
|
|
+ assertThat(snapshotIds, hasSize(1));
|
|
|
+
|
|
|
+ final SnapshotInfo snapshotInfo = repository.getSnapshotInfo(snapshotIds.iterator().next());
|
|
|
+ assertEquals(SnapshotState.SUCCESS, snapshotInfo.state());
|
|
|
+ assertEquals(0, snapshotInfo.failedShards());
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Simulates concurrent restarts of data and master nodes as well as relocating a primary shard, while starting and subsequently
|
|
|
* deleting a snapshot.
|