|
@@ -30,6 +30,7 @@ import org.elasticsearch.action.ResultDeduplicator;
|
|
|
import org.elasticsearch.action.StepListener;
|
|
|
import org.elasticsearch.action.support.GroupedActionListener;
|
|
|
import org.elasticsearch.action.support.ListenableActionFuture;
|
|
|
+import org.elasticsearch.action.support.PlainActionFuture;
|
|
|
import org.elasticsearch.action.support.ThreadedActionListener;
|
|
|
import org.elasticsearch.cluster.ClusterState;
|
|
|
import org.elasticsearch.cluster.ClusterStateUpdateTask;
|
|
@@ -66,6 +67,7 @@ import org.elasticsearch.common.unit.ByteSizeValue;
|
|
|
import org.elasticsearch.common.util.BigArrays;
|
|
|
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
|
|
|
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
|
|
|
+import org.elasticsearch.common.util.concurrent.FutureUtils;
|
|
|
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
|
|
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
|
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
@@ -423,6 +425,30 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent imp
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // listeners to invoke when a restore completes and there are no more restores running
|
|
|
+ @Nullable
|
|
|
+ private List<ActionListener<Void>> emptyListeners;
|
|
|
+
|
|
|
+ // Set of shard ids that this repository is currently restoring
|
|
|
+ private final Set<ShardId> ongoingRestores = new HashSet<>();
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void awaitIdle() {
|
|
|
+ assert lifecycle.stoppedOrClosed();
|
|
|
+ final PlainActionFuture<Void> future;
|
|
|
+ synchronized (ongoingRestores) {
|
|
|
+ if (ongoingRestores.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ future = new PlainActionFuture<>();
|
|
|
+ if (emptyListeners == null) {
|
|
|
+ emptyListeners = new ArrayList<>();
|
|
|
+ }
|
|
|
+ emptyListeners.add(future);
|
|
|
+ }
|
|
|
+ FutureUtils.get(future);
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public void executeConsistentStateUpdate(
|
|
|
Function<RepositoryData, ClusterStateUpdateTask> createUpdateTask,
|
|
@@ -2885,7 +2911,30 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent imp
|
|
|
);
|
|
|
final Executor executor = threadPool.executor(ThreadPool.Names.SNAPSHOT);
|
|
|
final BlobContainer container = shardContainer(indexId, snapshotShardId);
|
|
|
- executor.execute(ActionRunnable.wrap(restoreListener, l -> {
|
|
|
+ synchronized (ongoingRestores) {
|
|
|
+ if (store.isClosing()) {
|
|
|
+ restoreListener.onFailure(new AlreadyClosedException("store is closing"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (lifecycle.started() == false) {
|
|
|
+ restoreListener.onFailure(new AlreadyClosedException("repository [" + metadata.name() + "] closed"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ final boolean added = ongoingRestores.add(shardId);
|
|
|
+ assert added : "add restore for [" + shardId + "] that already has an existing restore";
|
|
|
+ }
|
|
|
+ executor.execute(ActionRunnable.wrap(ActionListener.runAfter(restoreListener, () -> {
|
|
|
+ final List<ActionListener<Void>> onEmptyListeners;
|
|
|
+ synchronized (ongoingRestores) {
|
|
|
+ if (ongoingRestores.remove(shardId) && ongoingRestores.isEmpty() && emptyListeners != null) {
|
|
|
+ onEmptyListeners = emptyListeners;
|
|
|
+ emptyListeners = null;
|
|
|
+ } else {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ActionListener.onResponse(onEmptyListeners, null);
|
|
|
+ }), l -> {
|
|
|
final BlobStoreIndexShardSnapshot snapshot = loadShardSnapshot(container, snapshotId);
|
|
|
final SnapshotFiles snapshotFiles = new SnapshotFiles(snapshot.snapshot(), snapshot.indexFiles(), null);
|
|
|
new FileRestoreContext(metadata.name(), shardId, snapshotId, recoveryState) {
|
|
@@ -2991,6 +3040,9 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent imp
|
|
|
if (store.isClosing()) {
|
|
|
throw new AlreadyClosedException("store is closing");
|
|
|
}
|
|
|
+ if (lifecycle.started() == false) {
|
|
|
+ throw new AlreadyClosedException("repository [" + metadata.name() + "] closed");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
}.restore(snapshotFiles, store, l);
|