|
@@ -47,7 +47,6 @@ import org.elasticsearch.action.support.ActiveShardCount;
|
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
|
import org.elasticsearch.client.Client;
|
|
import org.elasticsearch.client.Client;
|
|
import org.elasticsearch.cluster.ClusterState;
|
|
import org.elasticsearch.cluster.ClusterState;
|
|
-import org.elasticsearch.cluster.ClusterStateListener;
|
|
|
|
import org.elasticsearch.cluster.ClusterStateUpdateTask;
|
|
import org.elasticsearch.cluster.ClusterStateUpdateTask;
|
|
import org.elasticsearch.cluster.RestoreInProgress;
|
|
import org.elasticsearch.cluster.RestoreInProgress;
|
|
import org.elasticsearch.cluster.SnapshotsInProgress;
|
|
import org.elasticsearch.cluster.SnapshotsInProgress;
|
|
@@ -110,7 +109,6 @@ import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
-import java.util.concurrent.CopyOnWriteArrayList;
|
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
import java.util.concurrent.CountDownLatch;
|
|
import java.util.concurrent.ExecutionException;
|
|
import java.util.concurrent.ExecutionException;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.TimeUnit;
|
|
@@ -2538,28 +2536,15 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
|
|
|
|
|
|
Client client = client();
|
|
Client client = client();
|
|
|
|
|
|
- boolean allowPartial = randomBoolean();
|
|
|
|
logger.info("--> creating repository");
|
|
logger.info("--> creating repository");
|
|
|
|
|
|
- // only block on repo init if we have partial snapshot or we run into deadlock when acquiring shard locks for index deletion/closing
|
|
|
|
- boolean initBlocking = allowPartial || randomBoolean();
|
|
|
|
- if (initBlocking) {
|
|
|
|
- assertAcked(client.admin().cluster().preparePutRepository("test-repo")
|
|
|
|
- .setType("mock").setSettings(Settings.builder()
|
|
|
|
- .put("location", randomRepoPath())
|
|
|
|
- .put("compress", randomBoolean())
|
|
|
|
- .put("chunk_size", randomIntBetween(100, 1000), ByteSizeUnit.BYTES)
|
|
|
|
- .put("block_on_init", true)
|
|
|
|
- ));
|
|
|
|
- } else {
|
|
|
|
- assertAcked(client.admin().cluster().preparePutRepository("test-repo")
|
|
|
|
- .setType("mock").setSettings(Settings.builder()
|
|
|
|
- .put("location", randomRepoPath())
|
|
|
|
- .put("compress", randomBoolean())
|
|
|
|
- .put("chunk_size", randomIntBetween(100, 1000), ByteSizeUnit.BYTES)
|
|
|
|
- .put("block_on_data", true)
|
|
|
|
- ));
|
|
|
|
- }
|
|
|
|
|
|
+ assertAcked(client.admin().cluster().preparePutRepository("test-repo")
|
|
|
|
+ .setType("mock").setSettings(Settings.builder()
|
|
|
|
+ .put("location", randomRepoPath())
|
|
|
|
+ .put("compress", randomBoolean())
|
|
|
|
+ .put("chunk_size", randomIntBetween(100, 1000), ByteSizeUnit.BYTES)
|
|
|
|
+ .put("block_on_data", true)));
|
|
|
|
+
|
|
|
|
|
|
createIndex("test-idx-1", "test-idx-2", "test-idx-3");
|
|
createIndex("test-idx-1", "test-idx-2", "test-idx-3");
|
|
ensureGreen();
|
|
ensureGreen();
|
|
@@ -2575,70 +2560,40 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
|
|
assertThat(client.prepareSearch("test-idx-2").setSize(0).get().getHits().getTotalHits().value, equalTo(100L));
|
|
assertThat(client.prepareSearch("test-idx-2").setSize(0).get().getHits().getTotalHits().value, equalTo(100L));
|
|
assertThat(client.prepareSearch("test-idx-3").setSize(0).get().getHits().getTotalHits().value, equalTo(100L));
|
|
assertThat(client.prepareSearch("test-idx-3").setSize(0).get().getHits().getTotalHits().value, equalTo(100L));
|
|
|
|
|
|
- logger.info("--> snapshot allow partial {}", allowPartial);
|
|
|
|
|
|
+ logger.info("--> snapshot");
|
|
ActionFuture<CreateSnapshotResponse> future = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
|
|
ActionFuture<CreateSnapshotResponse> future = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
|
|
- .setIndices("test-idx-*").setWaitForCompletion(true).setPartial(allowPartial).execute();
|
|
|
|
|
|
+ .setIndices("test-idx-*").setWaitForCompletion(true).setPartial(false).execute();
|
|
logger.info("--> wait for block to kick in");
|
|
logger.info("--> wait for block to kick in");
|
|
- if (initBlocking) {
|
|
|
|
- waitForBlock(internalCluster().getMasterName(), "test-repo", TimeValue.timeValueMinutes(1));
|
|
|
|
- } else {
|
|
|
|
- waitForBlockOnAnyDataNode("test-repo", TimeValue.timeValueMinutes(1));
|
|
|
|
- }
|
|
|
|
- boolean closedOnPartial = false;
|
|
|
|
|
|
+ waitForBlockOnAnyDataNode("test-repo", TimeValue.timeValueMinutes(1));
|
|
|
|
+
|
|
try {
|
|
try {
|
|
- if (allowPartial) {
|
|
|
|
- // partial snapshots allow close / delete operations
|
|
|
|
- if (randomBoolean()) {
|
|
|
|
- logger.info("--> delete index while partial snapshot is running");
|
|
|
|
|
|
+ // non-partial snapshots do not allow close / delete operations on indices where snapshot has not been completed
|
|
|
|
+ if (randomBoolean()) {
|
|
|
|
+ try {
|
|
|
|
+ logger.info("--> delete index while non-partial snapshot is running");
|
|
client.admin().indices().prepareDelete("test-idx-1").get();
|
|
client.admin().indices().prepareDelete("test-idx-1").get();
|
|
- } else {
|
|
|
|
- logger.info("--> close index while partial snapshot is running");
|
|
|
|
- closedOnPartial = true;
|
|
|
|
- client.admin().indices().prepareClose("test-idx-1").get();
|
|
|
|
|
|
+ fail("Expected deleting index to fail during snapshot");
|
|
|
|
+ } catch (SnapshotInProgressException e) {
|
|
|
|
+ assertThat(e.getMessage(), containsString("Cannot delete indices that are being snapshotted: [[test-idx-1/"));
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- // non-partial snapshots do not allow close / delete operations on indices where snapshot has not been completed
|
|
|
|
- if (randomBoolean()) {
|
|
|
|
- try {
|
|
|
|
- logger.info("--> delete index while non-partial snapshot is running");
|
|
|
|
- client.admin().indices().prepareDelete("test-idx-1").get();
|
|
|
|
- fail("Expected deleting index to fail during snapshot");
|
|
|
|
- } catch (SnapshotInProgressException e) {
|
|
|
|
- assertThat(e.getMessage(), containsString("Cannot delete indices that are being snapshotted: [[test-idx-1/"));
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- try {
|
|
|
|
- logger.info("--> close index while non-partial snapshot is running");
|
|
|
|
- client.admin().indices().prepareClose("test-idx-1").get();
|
|
|
|
- fail("Expected closing index to fail during snapshot");
|
|
|
|
- } catch (SnapshotInProgressException e) {
|
|
|
|
- assertThat(e.getMessage(), containsString("Cannot close indices that are being snapshotted: [[test-idx-1/"));
|
|
|
|
- }
|
|
|
|
|
|
+ try {
|
|
|
|
+ logger.info("--> close index while non-partial snapshot is running");
|
|
|
|
+ client.admin().indices().prepareClose("test-idx-1").get();
|
|
|
|
+ fail("Expected closing index to fail during snapshot");
|
|
|
|
+ } catch (SnapshotInProgressException e) {
|
|
|
|
+ assertThat(e.getMessage(), containsString("Cannot close indices that are being snapshotted: [[test-idx-1/"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} finally {
|
|
} finally {
|
|
- if (initBlocking) {
|
|
|
|
- logger.info("--> unblock running master node");
|
|
|
|
- unblockNode("test-repo", internalCluster().getMasterName());
|
|
|
|
- } else {
|
|
|
|
- logger.info("--> unblock all data nodes");
|
|
|
|
- unblockAllDataNodes("test-repo");
|
|
|
|
- }
|
|
|
|
|
|
+ logger.info("--> unblock all data nodes");
|
|
|
|
+ unblockAllDataNodes("test-repo");
|
|
}
|
|
}
|
|
logger.info("--> waiting for snapshot to finish");
|
|
logger.info("--> waiting for snapshot to finish");
|
|
CreateSnapshotResponse createSnapshotResponse = future.get();
|
|
CreateSnapshotResponse createSnapshotResponse = future.get();
|
|
|
|
|
|
- if (allowPartial && closedOnPartial == false) {
|
|
|
|
- logger.info("Deleted/Closed index during snapshot, but allow partial");
|
|
|
|
- assertThat(createSnapshotResponse.getSnapshotInfo().state(), equalTo((SnapshotState.PARTIAL)));
|
|
|
|
- assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
|
|
|
|
- assertThat(createSnapshotResponse.getSnapshotInfo().failedShards(), greaterThan(0));
|
|
|
|
- assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
|
|
|
|
- lessThan(createSnapshotResponse.getSnapshotInfo().totalShards()));
|
|
|
|
- } else {
|
|
|
|
- logger.info("Snapshot successfully completed");
|
|
|
|
- assertThat(createSnapshotResponse.getSnapshotInfo().state(), equalTo((SnapshotState.SUCCESS)));
|
|
|
|
- }
|
|
|
|
|
|
+ logger.info("Snapshot successfully completed");
|
|
|
|
+ assertThat(createSnapshotResponse.getSnapshotInfo().state(), equalTo((SnapshotState.SUCCESS)));
|
|
}
|
|
}
|
|
|
|
|
|
public void testCloseIndexDuringRestore() throws Exception {
|
|
public void testCloseIndexDuringRestore() throws Exception {
|
|
@@ -3493,7 +3448,7 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
|
|
assertThat(shardFailure.reason(), containsString("Random IOException"));
|
|
assertThat(shardFailure.reason(), containsString("Random IOException"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- } catch (SnapshotCreationException | RepositoryException ex) {
|
|
|
|
|
|
+ } catch (SnapshotException | RepositoryException ex) {
|
|
// sometimes, the snapshot will fail with a top level I/O exception
|
|
// sometimes, the snapshot will fail with a top level I/O exception
|
|
assertThat(ExceptionsHelper.stackTrace(ex), containsString("Random IOException"));
|
|
assertThat(ExceptionsHelper.stackTrace(ex), containsString("Random IOException"));
|
|
}
|
|
}
|
|
@@ -3856,76 +3811,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
|
|
assertThat(client.prepareGet(restoredIndexName2, typeName, sameSourceIndex ? docId : docId2).get().isExists(), equalTo(true));
|
|
assertThat(client.prepareGet(restoredIndexName2, typeName, sameSourceIndex ? docId : docId2).get().isExists(), equalTo(true));
|
|
}
|
|
}
|
|
|
|
|
|
- public void testAbortedSnapshotDuringInitDoesNotStart() throws Exception {
|
|
|
|
- final Client client = client();
|
|
|
|
-
|
|
|
|
- // Blocks on initialization
|
|
|
|
- assertAcked(client.admin().cluster().preparePutRepository("repository")
|
|
|
|
- .setType("mock").setSettings(Settings.builder()
|
|
|
|
- .put("location", randomRepoPath())
|
|
|
|
- .put("block_on_init", true)
|
|
|
|
- ));
|
|
|
|
-
|
|
|
|
- createIndex("test-idx");
|
|
|
|
- final int nbDocs = scaledRandomIntBetween(100, 500);
|
|
|
|
- for (int i = 0; i < nbDocs; i++) {
|
|
|
|
- index("test-idx", "_doc", Integer.toString(i), "foo", "bar" + i);
|
|
|
|
- }
|
|
|
|
- flushAndRefresh("test-idx");
|
|
|
|
- assertThat(client.prepareSearch("test-idx").setSize(0).get().getHits().getTotalHits().value, equalTo((long) nbDocs));
|
|
|
|
-
|
|
|
|
- // Create a snapshot
|
|
|
|
- client.admin().cluster().prepareCreateSnapshot("repository", "snap").execute();
|
|
|
|
- waitForBlock(internalCluster().getMasterName(), "repository", TimeValue.timeValueMinutes(1));
|
|
|
|
- boolean blocked = true;
|
|
|
|
-
|
|
|
|
- // Snapshot is initializing (and is blocked at this stage)
|
|
|
|
- SnapshotsStatusResponse snapshotsStatus = client.admin().cluster().prepareSnapshotStatus("repository").setSnapshots("snap").get();
|
|
|
|
- assertThat(snapshotsStatus.getSnapshots().iterator().next().getState(), equalTo(State.INIT));
|
|
|
|
-
|
|
|
|
- final List<State> states = new CopyOnWriteArrayList<>();
|
|
|
|
- final ClusterStateListener listener = event -> {
|
|
|
|
- SnapshotsInProgress snapshotsInProgress = event.state().custom(SnapshotsInProgress.TYPE);
|
|
|
|
- for (SnapshotsInProgress.Entry entry : snapshotsInProgress.entries()) {
|
|
|
|
- if ("snap".equals(entry.snapshot().getSnapshotId().getName())) {
|
|
|
|
- states.add(entry.state());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- // Record the upcoming states of the snapshot on all nodes
|
|
|
|
- internalCluster().getInstances(ClusterService.class).forEach(clusterService -> clusterService.addListener(listener));
|
|
|
|
-
|
|
|
|
- // Delete the snapshot while it is being initialized
|
|
|
|
- ActionFuture<AcknowledgedResponse> delete = client.admin().cluster().prepareDeleteSnapshot("repository", "snap").execute();
|
|
|
|
-
|
|
|
|
- // The deletion must set the snapshot in the ABORTED state
|
|
|
|
- assertBusy(() -> {
|
|
|
|
- SnapshotsStatusResponse status =
|
|
|
|
- client.admin().cluster().prepareSnapshotStatus("repository").setSnapshots("snap").get();
|
|
|
|
- assertThat(status.getSnapshots().iterator().next().getState(), equalTo(State.ABORTED));
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- // Now unblock the repository
|
|
|
|
- unblockNode("repository", internalCluster().getMasterName());
|
|
|
|
- blocked = false;
|
|
|
|
-
|
|
|
|
- assertAcked(delete.get());
|
|
|
|
- expectThrows(SnapshotMissingException.class, () ->
|
|
|
|
- client.admin().cluster().prepareGetSnapshots("repository").setSnapshots("snap").get()
|
|
|
|
- .getSnapshots("repository"));
|
|
|
|
-
|
|
|
|
- assertFalse("Expecting snapshot state to be updated", states.isEmpty());
|
|
|
|
- assertFalse("Expecting snapshot to be aborted and not started at all", states.contains(State.STARTED));
|
|
|
|
- } finally {
|
|
|
|
- internalCluster().getInstances(ClusterService.class).forEach(clusterService -> clusterService.removeListener(listener));
|
|
|
|
- if (blocked) {
|
|
|
|
- unblockNode("repository", internalCluster().getMasterName());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
public void testRestoreIncreasesPrimaryTerms() {
|
|
public void testRestoreIncreasesPrimaryTerms() {
|
|
final String indexName = randomAlphaOfLengthBetween(5, 10).toLowerCase(Locale.ROOT);
|
|
final String indexName = randomAlphaOfLengthBetween(5, 10).toLowerCase(Locale.ROOT);
|
|
createIndex(indexName, Settings.builder()
|
|
createIndex(indexName, Settings.builder()
|