1313import org .apache .logging .log4j .LogManager ;
1414import org .apache .logging .log4j .Logger ;
1515import org .elasticsearch .action .ActionListener ;
16- import org .elasticsearch .action .ActionRunnable ;
16+ import org .elasticsearch .action .StepListener ;
1717import org .elasticsearch .action .support .ActionFilters ;
1818import org .elasticsearch .action .support .master .TransportMasterNodeAction ;
1919import org .elasticsearch .client .node .NodeClient ;
2727import org .elasticsearch .common .Strings ;
2828import org .elasticsearch .common .inject .Inject ;
2929import org .elasticsearch .common .util .CollectionUtils ;
30- import org .elasticsearch .common .util .concurrent .ListenableFuture ;
3130import org .elasticsearch .common .util .set .Sets ;
3231import org .elasticsearch .index .shard .ShardId ;
3332import org .elasticsearch .index .snapshots .IndexShardSnapshotStatus ;
33+ import org .elasticsearch .repositories .GetSnapshotInfoContext ;
3434import org .elasticsearch .repositories .IndexId ;
3535import org .elasticsearch .repositories .RepositoriesService ;
3636import org .elasticsearch .repositories .Repository ;
5252import java .io .IOException ;
5353import java .util .ArrayList ;
5454import java .util .Arrays ;
55+ import java .util .Collection ;
5556import java .util .Collections ;
5657import java .util .HashMap ;
5758import java .util .HashSet ;
6263import java .util .stream .Collectors ;
6364
6465import static java .util .Collections .unmodifiableMap ;
66+ import static org .elasticsearch .cluster .SnapshotsInProgress .ShardState .SUCCESS ;
6567
6668public class TransportSnapshotsStatusAction extends TransportMasterNodeAction <SnapshotsStatusRequest , SnapshotsStatusResponse > {
6769
@@ -90,7 +92,7 @@ public TransportSnapshotsStatusAction(
9092 SnapshotsStatusRequest ::new ,
9193 indexNameExpressionResolver ,
9294 SnapshotsStatusResponse ::new ,
93- ThreadPool .Names .GENERIC
95+ ThreadPool .Names .SAME
9496 );
9597 this .repositoriesService = repositoriesService ;
9698 this .client = client ;
@@ -142,13 +144,14 @@ protected void masterOperation(
142144 new TransportNodesSnapshotsStatus .Request (nodesIds .toArray (Strings .EMPTY_ARRAY )).snapshots (snapshots )
143145 .timeout (request .masterNodeTimeout ()),
144146 ActionListener .wrap (
145- nodeSnapshotStatuses -> threadPool .generic ()
146- .execute (
147- ActionRunnable .wrap (
148- listener ,
149- l -> buildResponse (snapshotsInProgress , request , currentSnapshots , nodeSnapshotStatuses , cancellableTask , l )
150- )
151- ),
147+ nodeSnapshotStatuses -> buildResponse (
148+ snapshotsInProgress ,
149+ request ,
150+ currentSnapshots ,
151+ nodeSnapshotStatuses ,
152+ cancellableTask ,
153+ listener
154+ ),
152155 listener ::onFailure
153156 )
154157 );
@@ -192,8 +195,7 @@ private void buildResponse(
192195 SnapshotIndexShardStatus shardStatus = shardStatues .get (shardEntry .key );
193196 if (shardStatus != null ) {
194197 // We have full information about this shard
195- if (shardStatus .getStage () == SnapshotIndexShardStage .DONE
196- && shardEntry .value .state () != SnapshotsInProgress .ShardState .SUCCESS ) {
198+ if (shardStatus .getStage () == SnapshotIndexShardStage .DONE && shardEntry .value .state () != SUCCESS ) {
197199 // Unlikely edge case:
198200 // Data node has finished snapshotting the shard but the cluster state has not yet been updated
199201 // to reflect this. We adjust the status to show up as snapshot metadata being written because
@@ -286,9 +288,10 @@ private void loadRepositoryData(
286288 ActionListener <SnapshotsStatusResponse > listener
287289 ) {
288290 final Set <String > requestedSnapshotNames = Sets .newHashSet (request .snapshots ());
289- final ListenableFuture <RepositoryData > repositoryDataListener = new ListenableFuture <>();
291+ final StepListener <RepositoryData > repositoryDataListener = new StepListener <>();
290292 repositoriesService .getRepositoryData (repositoryName , repositoryDataListener );
291- repositoryDataListener .addListener (ActionListener .wrap (repositoryData -> {
293+ final Collection <SnapshotId > snapshotIdsToLoad = new ArrayList <>();
294+ repositoryDataListener .whenComplete (repositoryData -> {
292295 ensureNotCancelled (task );
293296 final Map <String , SnapshotId > matchedSnapshotIds = repositoryData .getSnapshotIds ()
294297 .stream ()
@@ -314,73 +317,62 @@ private void loadRepositoryData(
314317 throw new SnapshotMissingException (repositoryName , snapshotName );
315318 }
316319 }
317- SnapshotInfo snapshotInfo = snapshot (snapshotsInProgress , repositoryName , snapshotId );
318- List <SnapshotIndexShardStatus > shardStatusBuilder = new ArrayList <>();
319- if (snapshotInfo .state ().completed ()) {
320- Map <ShardId , IndexShardSnapshotStatus > shardStatuses = snapshotShards (
321- repositoryName ,
322- repositoryData ,
323- task ,
324- snapshotInfo
325- );
326- for (Map .Entry <ShardId , IndexShardSnapshotStatus > shardStatus : shardStatuses .entrySet ()) {
327- IndexShardSnapshotStatus .Copy lastSnapshotStatus = shardStatus .getValue ().asCopy ();
328- shardStatusBuilder .add (new SnapshotIndexShardStatus (shardStatus .getKey (), lastSnapshotStatus ));
329- }
330- final SnapshotsInProgress .State state ;
331- switch (snapshotInfo .state ()) {
332- case FAILED :
333- state = SnapshotsInProgress .State .FAILED ;
334- break ;
335- case SUCCESS :
336- case PARTIAL :
337- // Translating both PARTIAL and SUCCESS to SUCCESS for now
338- // TODO: add the differentiation on the metadata level in the next major release
339- state = SnapshotsInProgress .State .SUCCESS ;
340- break ;
341- default :
342- throw new IllegalArgumentException ("Unknown snapshot state " + snapshotInfo .state ());
343- }
344- final long startTime = snapshotInfo .startTime ();
345- final long endTime = snapshotInfo .endTime ();
346- assert endTime >= startTime || (endTime == 0L && snapshotInfo .state ().completed () == false )
347- : "Inconsistent timestamps found in SnapshotInfo [" + snapshotInfo + "]" ;
348- builder .add (
349- new SnapshotStatus (
350- new Snapshot (repositoryName , snapshotId ),
351- state ,
352- Collections .unmodifiableList (shardStatusBuilder ),
353- snapshotInfo .includeGlobalState (),
354- startTime ,
355- // Use current time to calculate overall runtime for in-progress snapshots that have endTime == 0
356- (endTime == 0 ? threadPool .absoluteTimeInMillis () : endTime ) - startTime
357- )
358- );
320+ if (snapshotsInProgress .snapshot (new Snapshot (repositoryName , snapshotId )) == null ) {
321+ snapshotIdsToLoad .add (snapshotId );
359322 }
360323 }
361- listener .onResponse (new SnapshotsStatusResponse (Collections .unmodifiableList (builder )));
362- }, listener ::onFailure ), threadPool .generic (), null );
363- }
364324
365- /**
366- * Retrieves snapshot from repository
367- *
368- * @param snapshotsInProgress snapshots in progress in the cluster state
369- * @param repositoryName repository name
370- * @param snapshotId snapshot id
371- * @return snapshot
372- * @throws SnapshotMissingException if snapshot is not found
373- */
374- private SnapshotInfo snapshot (SnapshotsInProgress snapshotsInProgress , String repositoryName , SnapshotId snapshotId ) {
375- List <SnapshotsInProgress .Entry > entries = SnapshotsService .currentSnapshots (
376- snapshotsInProgress ,
377- repositoryName ,
378- Collections .singletonList (snapshotId .getName ())
379- );
380- if (entries .isEmpty () == false ) {
381- return new SnapshotInfo (entries .iterator ().next ());
382- }
383- return repositoriesService .repository (repositoryName ).getSnapshotInfo (snapshotId );
325+ if (snapshotIdsToLoad .isEmpty ()) {
326+ listener .onResponse (new SnapshotsStatusResponse (Collections .unmodifiableList (builder )));
327+ } else {
328+ final List <SnapshotStatus > threadSafeBuilder = Collections .synchronizedList (builder );
329+ repositoriesService .repository (repositoryName )
330+ .getSnapshotInfo (new GetSnapshotInfoContext (snapshotIdsToLoad , true , task ::isCancelled , (context , snapshotInfo ) -> {
331+ List <SnapshotIndexShardStatus > shardStatusBuilder = new ArrayList <>();
332+ final Map <ShardId , IndexShardSnapshotStatus > shardStatuses ;
333+ try {
334+ shardStatuses = snapshotShards (repositoryName , repositoryData , task , snapshotInfo );
335+ } catch (Exception e ) {
336+ // stops all further fetches of snapshotInfo since context is fail-fast
337+ context .onFailure (e );
338+ return ;
339+ }
340+ for (Map .Entry <ShardId , IndexShardSnapshotStatus > shardStatus : shardStatuses .entrySet ()) {
341+ IndexShardSnapshotStatus .Copy lastSnapshotStatus = shardStatus .getValue ().asCopy ();
342+ shardStatusBuilder .add (new SnapshotIndexShardStatus (shardStatus .getKey (), lastSnapshotStatus ));
343+ }
344+ final SnapshotsInProgress .State state ;
345+ switch (snapshotInfo .state ()) {
346+ case FAILED :
347+ state = SnapshotsInProgress .State .FAILED ;
348+ break ;
349+ case SUCCESS :
350+ case PARTIAL :
351+ // Translating both PARTIAL and SUCCESS to SUCCESS for now
352+ // TODO: add the differentiation on the metadata level in the next major release
353+ state = SnapshotsInProgress .State .SUCCESS ;
354+ break ;
355+ default :
356+ throw new IllegalArgumentException ("Unknown snapshot state " + snapshotInfo .state ());
357+ }
358+ final long startTime = snapshotInfo .startTime ();
359+ final long endTime = snapshotInfo .endTime ();
360+ assert endTime >= startTime || (endTime == 0L && snapshotInfo .state ().completed () == false )
361+ : "Inconsistent timestamps found in SnapshotInfo [" + snapshotInfo + "]" ;
362+ threadSafeBuilder .add (
363+ new SnapshotStatus (
364+ new Snapshot (repositoryName , snapshotInfo .snapshotId ()),
365+ state ,
366+ Collections .unmodifiableList (shardStatusBuilder ),
367+ snapshotInfo .includeGlobalState (),
368+ startTime ,
369+ // Use current time to calculate overall runtime for in-progress snapshots that have endTime == 0
370+ (endTime == 0 ? threadPool .absoluteTimeInMillis () : endTime ) - startTime
371+ )
372+ );
373+ }, listener .map (v -> new SnapshotsStatusResponse (List .copyOf (threadSafeBuilder )))));
374+ }
375+ }, listener ::onFailure );
384376 }
385377
386378 /**
0 commit comments