|
30 | 30 | import org.elasticsearch.action.StepListener;
|
31 | 31 | import org.elasticsearch.action.support.GroupedActionListener;
|
32 | 32 | import org.elasticsearch.action.support.ListenableActionFuture;
|
| 33 | +import org.elasticsearch.action.support.PlainActionFuture; |
33 | 34 | import org.elasticsearch.action.support.ThreadedActionListener;
|
34 | 35 | import org.elasticsearch.cluster.ClusterState;
|
35 | 36 | import org.elasticsearch.cluster.ClusterStateUpdateTask;
|
|
66 | 67 | import org.elasticsearch.common.util.BigArrays;
|
67 | 68 | import org.elasticsearch.common.util.concurrent.AbstractRunnable;
|
68 | 69 | import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
|
| 70 | +import org.elasticsearch.common.util.concurrent.FutureUtils; |
69 | 71 | import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
70 | 72 | import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
71 | 73 | import org.elasticsearch.common.xcontent.XContentBuilder;
|
@@ -427,6 +429,30 @@ protected void doClose() {
|
427 | 429 | }
|
428 | 430 | }
|
429 | 431 |
|
| 432 | + // listeners to invoke when a restore completes and there are no more restores running |
| 433 | + @Nullable |
| 434 | + private List<ActionListener<Void>> emptyListeners; |
| 435 | + |
| 436 | + // Set of shard ids that this repository is currently restoring |
| 437 | + private final Set<ShardId> ongoingRestores = new HashSet<>(); |
| 438 | + |
| 439 | + @Override |
| 440 | + public void awaitIdle() { |
| 441 | + assert lifecycle.stoppedOrClosed(); |
| 442 | + final PlainActionFuture<Void> future; |
| 443 | + synchronized (ongoingRestores) { |
| 444 | + if (ongoingRestores.isEmpty()) { |
| 445 | + return; |
| 446 | + } |
| 447 | + future = new PlainActionFuture<>(); |
| 448 | + if (emptyListeners == null) { |
| 449 | + emptyListeners = new ArrayList<>(); |
| 450 | + } |
| 451 | + emptyListeners.add(future); |
| 452 | + } |
| 453 | + FutureUtils.get(future); |
| 454 | + } |
| 455 | + |
430 | 456 | @Override
|
431 | 457 | public void executeConsistentStateUpdate(
|
432 | 458 | Function<RepositoryData, ClusterStateUpdateTask> createUpdateTask,
|
@@ -2897,7 +2923,30 @@ public void restoreShard(
|
2897 | 2923 | );
|
2898 | 2924 | final Executor executor = threadPool.executor(ThreadPool.Names.SNAPSHOT);
|
2899 | 2925 | final BlobContainer container = shardContainer(indexId, snapshotShardId);
|
2900 |
| - executor.execute(ActionRunnable.wrap(restoreListener, l -> { |
| 2926 | + synchronized (ongoingRestores) { |
| 2927 | + if (store.isClosing()) { |
| 2928 | + restoreListener.onFailure(new AlreadyClosedException("store is closing")); |
| 2929 | + return; |
| 2930 | + } |
| 2931 | + if (lifecycle.started() == false) { |
| 2932 | + restoreListener.onFailure(new AlreadyClosedException("repository [" + metadata.name() + "] closed")); |
| 2933 | + return; |
| 2934 | + } |
| 2935 | + final boolean added = ongoingRestores.add(shardId); |
| 2936 | + assert added : "add restore for [" + shardId + "] that already has an existing restore"; |
| 2937 | + } |
| 2938 | + executor.execute(ActionRunnable.wrap(ActionListener.runAfter(restoreListener, () -> { |
| 2939 | + final List<ActionListener<Void>> onEmptyListeners; |
| 2940 | + synchronized (ongoingRestores) { |
| 2941 | + if (ongoingRestores.remove(shardId) && ongoingRestores.isEmpty() && emptyListeners != null) { |
| 2942 | + onEmptyListeners = emptyListeners; |
| 2943 | + emptyListeners = null; |
| 2944 | + } else { |
| 2945 | + return; |
| 2946 | + } |
| 2947 | + } |
| 2948 | + ActionListener.onResponse(onEmptyListeners, null); |
| 2949 | + }), l -> { |
2901 | 2950 | final BlobStoreIndexShardSnapshot snapshot = loadShardSnapshot(container, snapshotId);
|
2902 | 2951 | final SnapshotFiles snapshotFiles = new SnapshotFiles(snapshot.snapshot(), snapshot.indexFiles(), null);
|
2903 | 2952 | new FileRestoreContext(metadata.name(), shardId, snapshotId, recoveryState) {
|
@@ -3003,6 +3052,9 @@ void ensureNotClosing(final Store store) throws AlreadyClosedException {
|
3003 | 3052 | if (store.isClosing()) {
|
3004 | 3053 | throw new AlreadyClosedException("store is closing");
|
3005 | 3054 | }
|
| 3055 | + if (lifecycle.started() == false) { |
| 3056 | + throw new AlreadyClosedException("repository [" + metadata.name() + "] closed"); |
| 3057 | + } |
3006 | 3058 | }
|
3007 | 3059 |
|
3008 | 3060 | }.restore(snapshotFiles, store, l);
|
|
0 commit comments