|
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;
|
@@ -423,6 +425,30 @@ protected void doClose() {
|
423 | 425 | }
|
424 | 426 | }
|
425 | 427 |
|
| 428 | + // listeners to invoke when a restore completes and there are no more restores running |
| 429 | + @Nullable |
| 430 | + private List<ActionListener<Void>> emptyListeners; |
| 431 | + |
| 432 | + // Set of shard ids that this repository is currently restoring |
| 433 | + private final Set<ShardId> ongoingRestores = new HashSet<>(); |
| 434 | + |
| 435 | + @Override |
| 436 | + public void awaitIdle() { |
| 437 | + assert lifecycle.stoppedOrClosed(); |
| 438 | + final PlainActionFuture<Void> future; |
| 439 | + synchronized (ongoingRestores) { |
| 440 | + if (ongoingRestores.isEmpty()) { |
| 441 | + return; |
| 442 | + } |
| 443 | + future = new PlainActionFuture<>(); |
| 444 | + if (emptyListeners == null) { |
| 445 | + emptyListeners = new ArrayList<>(); |
| 446 | + } |
| 447 | + emptyListeners.add(future); |
| 448 | + } |
| 449 | + FutureUtils.get(future); |
| 450 | + } |
| 451 | + |
426 | 452 | @Override
|
427 | 453 | public void executeConsistentStateUpdate(
|
428 | 454 | Function<RepositoryData, ClusterStateUpdateTask> createUpdateTask,
|
@@ -2885,7 +2911,30 @@ public void restoreShard(
|
2885 | 2911 | );
|
2886 | 2912 | final Executor executor = threadPool.executor(ThreadPool.Names.SNAPSHOT);
|
2887 | 2913 | final BlobContainer container = shardContainer(indexId, snapshotShardId);
|
2888 |
| - executor.execute(ActionRunnable.wrap(restoreListener, l -> { |
| 2914 | + synchronized (ongoingRestores) { |
| 2915 | + if (store.isClosing()) { |
| 2916 | + restoreListener.onFailure(new AlreadyClosedException("store is closing")); |
| 2917 | + return; |
| 2918 | + } |
| 2919 | + if (lifecycle.started() == false) { |
| 2920 | + restoreListener.onFailure(new AlreadyClosedException("repository [" + metadata.name() + "] closed")); |
| 2921 | + return; |
| 2922 | + } |
| 2923 | + final boolean added = ongoingRestores.add(shardId); |
| 2924 | + assert added : "add restore for [" + shardId + "] that already has an existing restore"; |
| 2925 | + } |
| 2926 | + executor.execute(ActionRunnable.wrap(ActionListener.runAfter(restoreListener, () -> { |
| 2927 | + final List<ActionListener<Void>> onEmptyListeners; |
| 2928 | + synchronized (ongoingRestores) { |
| 2929 | + if (ongoingRestores.remove(shardId) && ongoingRestores.isEmpty() && emptyListeners != null) { |
| 2930 | + onEmptyListeners = emptyListeners; |
| 2931 | + emptyListeners = null; |
| 2932 | + } else { |
| 2933 | + return; |
| 2934 | + } |
| 2935 | + } |
| 2936 | + ActionListener.onResponse(onEmptyListeners, null); |
| 2937 | + }), l -> { |
2889 | 2938 | final BlobStoreIndexShardSnapshot snapshot = loadShardSnapshot(container, snapshotId);
|
2890 | 2939 | final SnapshotFiles snapshotFiles = new SnapshotFiles(snapshot.snapshot(), snapshot.indexFiles(), null);
|
2891 | 2940 | new FileRestoreContext(metadata.name(), shardId, snapshotId, recoveryState) {
|
@@ -2991,6 +3040,9 @@ void ensureNotClosing(final Store store) throws AlreadyClosedException {
|
2991 | 3040 | if (store.isClosing()) {
|
2992 | 3041 | throw new AlreadyClosedException("store is closing");
|
2993 | 3042 | }
|
| 3043 | + if (lifecycle.started() == false) { |
| 3044 | + throw new AlreadyClosedException("repository [" + metadata.name() + "] closed"); |
| 3045 | + } |
2994 | 3046 | }
|
2995 | 3047 |
|
2996 | 3048 | }.restore(snapshotFiles, store, l);
|
|
0 commit comments