|
80 | 80 | import org.elasticsearch.action.support.ActiveShardCount;
|
81 | 81 | import org.elasticsearch.action.support.AutoCreateIndex;
|
82 | 82 | import org.elasticsearch.action.support.DestructiveOperations;
|
| 83 | +import org.elasticsearch.action.support.GroupedActionListener; |
83 | 84 | import org.elasticsearch.action.support.PlainActionFuture;
|
84 | 85 | import org.elasticsearch.action.support.TransportAction;
|
85 | 86 | import org.elasticsearch.action.support.WriteRequest;
|
@@ -502,6 +503,50 @@ public void testConcurrentSnapshotCreateAndDeleteOther() {
|
502 | 503 | }
|
503 | 504 | }
|
504 | 505 |
|
| 506 | + public void testConcurrentSnapshotDeleteAndDeleteIndex() { |
| 507 | + setupTestCluster(randomFrom(1, 3, 5), randomIntBetween(2, 10)); |
| 508 | + |
| 509 | + String repoName = "repo"; |
| 510 | + String snapshotName = "snapshot"; |
| 511 | + final String index = "test"; |
| 512 | + |
| 513 | + TestClusterNodes.TestClusterNode masterNode = |
| 514 | + testClusterNodes.currentMaster(testClusterNodes.nodes.values().iterator().next().clusterService.state()); |
| 515 | + |
| 516 | + final StepListener<Collection<CreateIndexResponse>> createIndicesListener = new StepListener<>(); |
| 517 | + |
| 518 | + continueOrDie(createRepoAndIndex(repoName, index, 1), createIndexResponse -> { |
| 519 | + // create a few more indices to make it more likely that the subsequent index delete operation happens before snapshot |
| 520 | + // finalization |
| 521 | + final int indices = randomIntBetween(5, 20); |
| 522 | + final GroupedActionListener<CreateIndexResponse> listener = new GroupedActionListener<>(createIndicesListener, indices); |
| 523 | + for (int i = 0; i < indices; ++i) { |
| 524 | + client().admin().indices().create(new CreateIndexRequest("index-" + i), listener); |
| 525 | + } |
| 526 | + }); |
| 527 | + |
| 528 | + final StepListener<CreateSnapshotResponse> createSnapshotResponseStepListener = new StepListener<>(); |
| 529 | + |
| 530 | + continueOrDie(createIndicesListener, createIndexResponses -> |
| 531 | + client().admin().cluster().prepareCreateSnapshot(repoName, snapshotName).setWaitForCompletion(false) |
| 532 | + .execute(createSnapshotResponseStepListener)); |
| 533 | + |
| 534 | + continueOrDie(createSnapshotResponseStepListener, |
| 535 | + createSnapshotResponse -> client().admin().indices().delete(new DeleteIndexRequest(index), noopListener())); |
| 536 | + |
| 537 | + deterministicTaskQueue.runAllRunnableTasks(); |
| 538 | + |
| 539 | + SnapshotsInProgress finalSnapshotsInProgress = masterNode.clusterService.state().custom(SnapshotsInProgress.TYPE); |
| 540 | + assertFalse(finalSnapshotsInProgress.entries().stream().anyMatch(entry -> entry.state().completed() == false)); |
| 541 | + final Repository repository = masterNode.repositoriesService.repository(repoName); |
| 542 | + Collection<SnapshotId> snapshotIds = getRepositoryData(repository).getSnapshotIds(); |
| 543 | + assertThat(snapshotIds, hasSize(1)); |
| 544 | + |
| 545 | + final SnapshotInfo snapshotInfo = repository.getSnapshotInfo(snapshotIds.iterator().next()); |
| 546 | + assertEquals(SnapshotState.SUCCESS, snapshotInfo.state()); |
| 547 | + assertEquals(0, snapshotInfo.failedShards()); |
| 548 | + } |
| 549 | + |
505 | 550 | /**
|
506 | 551 | * Simulates concurrent restarts of data and master nodes as well as relocating a primary shard, while starting and subsequently
|
507 | 552 | * deleting a snapshot.
|
|
0 commit comments