3131import org .elasticsearch .common .util .Maps ;
3232import org .elasticsearch .common .util .concurrent .ThrottledTaskRunner ;
3333import org .elasticsearch .core .Nullable ;
34+ import org .elasticsearch .core .Releasable ;
3435import org .elasticsearch .index .IndexVersion ;
3536import org .elasticsearch .index .engine .Engine ;
3637import org .elasticsearch .index .seqno .SequenceNumbers ;
5657import org .elasticsearch .transport .TransportService ;
5758
5859import java .io .IOException ;
59- import java .util .ArrayList ;
6060import java .util .HashMap ;
6161import java .util .HashSet ;
6262import java .util .Iterator ;
@@ -98,6 +98,9 @@ public final class SnapshotShardsService extends AbstractLifecycleComponent impl
9898 // A map of snapshots to the shardIds that we already reported to the master as failed
9999 private final ResultDeduplicator <UpdateIndexShardSnapshotStatusRequest , Void > remoteFailedRequestDeduplicator ;
100100
101+ // Runs the tasks that start each shard snapshot (e.g. acquiring the index commit)
102+ private final ThrottledTaskRunner startShardSnapshotTaskRunner ;
103+
101104 // Runs the tasks that promptly notify shards of aborted snapshots so that resources can be released ASAP
102105 private final ThrottledTaskRunner notifyOnAbortTaskRunner ;
103106
@@ -131,6 +134,11 @@ public SnapshotShardsService(
131134 threadPool .info (ThreadPool .Names .SNAPSHOT ).getMax (),
132135 threadPool .generic ()
133136 );
137+ this .startShardSnapshotTaskRunner = new ThrottledTaskRunner (
138+ "start-shard-snapshots" ,
139+ threadPool .info (ThreadPool .Names .SNAPSHOT ).getMax (),
140+ threadPool .executor (ThreadPool .Names .SNAPSHOT )
141+ );
134142 }
135143
136144 @ Override
@@ -384,7 +392,6 @@ private void startNewShardSnapshots(String localNodeId, SnapshotsInProgress.Entr
384392
385393 final var newSnapshotShards = shardSnapshots .computeIfAbsent (snapshot , s -> new HashMap <>());
386394
387- final List <Runnable > shardSnapshotTasks = new ArrayList <>(shardsToStart .size ());
388395 for (final Map .Entry <ShardId , ShardGeneration > shardEntry : shardsToStart .entrySet ()) {
389396 final ShardId shardId = shardEntry .getKey ();
390397 final IndexShardSnapshotStatus snapshotStatus = IndexShardSnapshotStatus .newInitializing (shardEntry .getValue ());
@@ -396,11 +403,37 @@ private void startNewShardSnapshots(String localNodeId, SnapshotsInProgress.Entr
396403 : "Found non-null, non-numeric shard generation ["
397404 + snapshotStatus .generation ()
398405 + "] for snapshot with old-format compatibility" ;
399- shardSnapshotTasks .add (newShardSnapshotTask (shardId , snapshot , indexId , snapshotStatus , entry .version (), entry .startTime ()));
400- snapshotStatus .updateStatusDescription ("shard snapshot scheduled to start" );
406+ final var shardSnapshotTask = newShardSnapshotTask (
407+ shardId ,
408+ snapshot ,
409+ indexId ,
410+ snapshotStatus ,
411+ entry .version (),
412+ entry .startTime ()
413+ );
414+ startShardSnapshotTaskRunner .enqueueTask (new ActionListener <>() {
415+ @ Override
416+ public void onResponse (Releasable releasable ) {
417+ try (releasable ) {
418+ shardSnapshotTask .run ();
419+ }
420+ }
421+
422+ @ Override
423+ public void onFailure (Exception e ) {
424+ final var wrapperException = new IllegalStateException (
425+ "impossible failure starting shard snapshot for " + shardId + " in " + snapshot ,
426+ e
427+ );
428+ logger .error (wrapperException .getMessage (), wrapperException );
429+ assert false : wrapperException ; // impossible
430+ }
431+ });
432+ snapshotStatus .updateStatusDescription ("shard snapshot enqueued to start" );
401433 }
402434
403- threadPool .executor (ThreadPool .Names .SNAPSHOT ).execute (() -> shardSnapshotTasks .forEach (Runnable ::run ));
435+ // apply some backpressure by reserving one SNAPSHOT thread for the startup work
436+ startShardSnapshotTaskRunner .runSyncTasksEagerly (threadPool .executor (ThreadPool .Names .SNAPSHOT ));
404437 }
405438
406439 private void pauseShardSnapshotsForNodeRemoval (String localNodeId , SnapshotsInProgress .Entry entry ) {
0 commit comments