57
57
import java .util .Collections ;
58
58
import java .util .HashMap ;
59
59
import java .util .HashSet ;
60
+ import java .util .Iterator ;
60
61
import java .util .List ;
61
62
import java .util .Map ;
62
63
import java .util .Queue ;
@@ -248,18 +249,8 @@ void getMultipleReposSnapshotInfo(ActionListener<GetSnapshotsResponse> listener)
248
249
return ;
249
250
}
250
251
251
- SubscribableListener
252
-
253
- .<RepositoryData >newForked (repositoryDataListener -> {
254
- if (snapshotNamePredicate == SnapshotNamePredicate .MATCH_CURRENT_ONLY ) {
255
- repositoryDataListener .onResponse (null );
256
- } else {
257
- repositoriesService .repository (repoName ).getRepositoryData (executor , repositoryDataListener );
258
- }
259
- })
260
-
252
+ SubscribableListener .<RepositoryData >newForked (l -> maybeGetRepositoryData (repoName , l ))
261
253
.<Void >andThen ((l , repositoryData ) -> loadSnapshotInfos (repoName , repositoryData , l ))
262
-
263
254
.addListener (listeners .acquire ());
264
255
}
265
256
}
@@ -268,6 +259,14 @@ void getMultipleReposSnapshotInfo(ActionListener<GetSnapshotsResponse> listener)
268
259
.addListener (listener .map (ignored -> buildResponse ()), executor , threadPool .getThreadContext ());
269
260
}
270
261
262
+ private void maybeGetRepositoryData (String repositoryName , ActionListener <RepositoryData > listener ) {
263
+ if (snapshotNamePredicate == SnapshotNamePredicate .MATCH_CURRENT_ONLY ) {
264
+ listener .onResponse (null );
265
+ } else {
266
+ repositoriesService .repository (repositoryName ).getRepositoryData (executor , listener );
267
+ }
268
+ }
269
+
271
270
private boolean skipRepository (String repositoryName ) {
272
271
if (sortBy == SnapshotSortKey .REPOSITORY && fromSortValue != null ) {
273
272
// If we are sorting by repository name with an offset given by fromSortValue, skip earlier repositories
@@ -277,61 +276,101 @@ private boolean skipRepository(String repositoryName) {
277
276
}
278
277
}
279
278
280
- private void loadSnapshotInfos (String repo , @ Nullable RepositoryData repositoryData , ActionListener <Void > listener ) {
279
+ private void loadSnapshotInfos (String repositoryName , @ Nullable RepositoryData repositoryData , ActionListener <Void > listener ) {
281
280
assert ThreadPool .assertCurrentThreadPool (ThreadPool .Names .MANAGEMENT );
282
281
283
- if (cancellableTask .notifyIfCancelled (listener )) {
284
- return ;
285
- }
286
-
287
- final Set <String > unmatchedRequiredNames = new HashSet <>(snapshotNamePredicate .requiredNames ());
288
- final Set <Snapshot > toResolve = new HashSet <>();
289
-
290
- for (final var snapshotInProgress : snapshotsInProgress .forRepo (repo )) {
291
- final var snapshotName = snapshotInProgress .snapshot ().getSnapshotId ().getName ();
292
- unmatchedRequiredNames .remove (snapshotName );
293
- if (snapshotNamePredicate .test (snapshotName , true )) {
294
- toResolve .add (snapshotInProgress .snapshot ());
295
- }
296
- }
297
-
298
- if (repositoryData != null ) {
299
- for (final var snapshotId : repositoryData .getSnapshotIds ()) {
300
- final var snapshotName = snapshotId .getName ();
301
- unmatchedRequiredNames .remove (snapshotName );
302
- if (snapshotNamePredicate .test (snapshotName , false ) && matchesPredicates (snapshotId , repositoryData )) {
303
- toResolve .add (new Snapshot (repo , snapshotId ));
304
- }
305
- }
306
- }
307
-
308
- if (unmatchedRequiredNames .isEmpty () == false ) {
309
- throw new SnapshotMissingException (repo , unmatchedRequiredNames .iterator ().next ());
310
- }
282
+ cancellableTask .ensureNotCancelled ();
283
+ ensureRequiredNamesPresent (repositoryName , repositoryData );
311
284
312
285
if (verbose ) {
313
- loadSnapshotInfos (repo , toResolve . stream (). map ( Snapshot :: getSnapshotId ). toList ( ), listener );
286
+ loadSnapshotInfos (repositoryName , getSnapshotIdIterator ( repositoryName , repositoryData ), listener );
314
287
} else {
315
288
assert fromSortValuePredicates .isMatchAll () : "filtering is not supported in non-verbose mode" ;
316
289
assert slmPolicyPredicate == SlmPolicyPredicate .MATCH_ALL_POLICIES : "filtering is not supported in non-verbose mode" ;
317
290
318
291
addSimpleSnapshotInfos (
319
- toResolve ,
320
- repo ,
292
+ getSnapshotIdIterator ( repositoryName , repositoryData ) ,
293
+ repositoryName ,
321
294
repositoryData ,
322
- snapshotsInProgress .forRepo (repo ).stream ().map (entry -> SnapshotInfo .inProgress (entry ).basic ()).toList ()
295
+ snapshotsInProgress .forRepo (repositoryName ).stream ().map (entry -> SnapshotInfo .inProgress (entry ).basic ()).toList ()
323
296
);
324
297
listener .onResponse (null );
325
298
}
326
299
}
327
300
328
- private void loadSnapshotInfos (String repositoryName , Collection <SnapshotId > snapshotIds , ActionListener <Void > listener ) {
301
+ /**
302
+ * Check that the repository contains every <i>required</i> name according to {@link #snapshotNamePredicate}.
303
+ *
304
+ * @throws SnapshotMissingException if one or more required names are missing.
305
+ */
306
+ private void ensureRequiredNamesPresent (String repositoryName , @ Nullable RepositoryData repositoryData ) {
307
+ if (snapshotNamePredicate .requiredNames ().isEmpty ()) {
308
+ return ;
309
+ }
310
+
311
+ final var unmatchedRequiredNames = new HashSet <>(snapshotNamePredicate .requiredNames ());
312
+ for (final var snapshotInProgress : snapshotsInProgress .forRepo (repositoryName )) {
313
+ unmatchedRequiredNames .remove (snapshotInProgress .snapshot ().getSnapshotId ().getName ());
314
+ }
315
+ if (unmatchedRequiredNames .isEmpty ()) {
316
+ return ;
317
+ }
318
+ if (repositoryData != null ) {
319
+ for (final var snapshotId : repositoryData .getSnapshotIds ()) {
320
+ unmatchedRequiredNames .remove (snapshotId .getName ());
321
+ }
322
+ if (unmatchedRequiredNames .isEmpty ()) {
323
+ return ;
324
+ }
325
+ }
326
+ throw new SnapshotMissingException (repositoryName , unmatchedRequiredNames .iterator ().next ());
327
+ }
328
+
329
+ /**
330
+ * @return an iterator over the snapshot IDs in the given repository which match {@link #snapshotNamePredicate}.
331
+ */
332
+ private Iterator <SnapshotId > getSnapshotIdIterator (String repositoryName , @ Nullable RepositoryData repositoryData ) {
333
+
334
+ // now iterate through the snapshots again, returning matching IDs (or null)
335
+ final Set <SnapshotId > matchingInProgressSnapshots = new HashSet <>();
336
+ return Iterators .concat (
337
+ // matching in-progress snapshots first
338
+ Iterators .filter (
339
+ Iterators .map (
340
+ snapshotsInProgress .forRepo (repositoryName ).iterator (),
341
+ snapshotInProgress -> snapshotInProgress .snapshot ().getSnapshotId ()
342
+ ),
343
+ snapshotId -> {
344
+ if (snapshotNamePredicate .test (snapshotId .getName (), true )) {
345
+ matchingInProgressSnapshots .add (snapshotId );
346
+ return true ;
347
+ } else {
348
+ return false ;
349
+ }
350
+ }
351
+ ),
352
+ repositoryData == null
353
+ // only returning in-progress snapshots
354
+ ? Collections .emptyIterator ()
355
+ // also return matching completed snapshots (except any ones that were also found to be in-progress)
356
+ : Iterators .filter (
357
+ repositoryData .getSnapshotIds ().iterator (),
358
+ snapshotId -> matchingInProgressSnapshots .contains (snapshotId ) == false
359
+ && snapshotNamePredicate .test (snapshotId .getName (), false )
360
+ && matchesPredicates (snapshotId , repositoryData )
361
+ )
362
+ );
363
+ }
364
+
365
+ private void loadSnapshotInfos (String repositoryName , Iterator <SnapshotId > snapshotIdIterator , ActionListener <Void > listener ) {
329
366
if (cancellableTask .notifyIfCancelled (listener )) {
330
367
return ;
331
368
}
332
369
final AtomicInteger repositoryTotalCount = new AtomicInteger ();
333
- final List <SnapshotInfo > snapshots = new ArrayList <>(snapshotIds .size ());
334
- final Set <SnapshotId > snapshotIdsToIterate = new HashSet <>(snapshotIds );
370
+ final Set <SnapshotId > snapshotIdsToIterate = new HashSet <>();
371
+ snapshotIdIterator .forEachRemaining (snapshotIdsToIterate ::add );
372
+
373
+ final List <SnapshotInfo > snapshots = new ArrayList <>(snapshotIdsToIterate .size ());
335
374
// first, look at the snapshots in progress
336
375
final List <SnapshotsInProgress .Entry > entries = SnapshotsService .currentSnapshots (
337
376
snapshotsInProgress ,
@@ -409,7 +448,7 @@ public void onFailure(Exception e) {
409
448
}
410
449
})
411
450
412
- // no need to synchronize access to snapshots: Repository#getSnapshotInfo fails fast but we're on the success path here
451
+ // no need to synchronize access to snapshots: all writes happen-before this read
413
452
.andThenAccept (ignored -> addResults (repositoryTotalCount .get (), snapshots ))
414
453
415
454
.addListener (listener );
@@ -422,9 +461,9 @@ private void addResults(int repositoryTotalCount, List<SnapshotInfo> snapshots)
422
461
}
423
462
424
463
private void addSimpleSnapshotInfos (
425
- final Set < Snapshot > toResolve ,
426
- final String repoName ,
427
- final RepositoryData repositoryData ,
464
+ final Iterator < SnapshotId > snapshotIdIterator ,
465
+ final String repositoryName ,
466
+ @ Nullable final RepositoryData repositoryData ,
428
467
final List <SnapshotInfo > currentSnapshots
429
468
) {
430
469
if (repositoryData == null ) {
@@ -433,11 +472,14 @@ private void addSimpleSnapshotInfos(
433
472
return ;
434
473
} // else want non-current snapshots as well, which are found in the repository data
435
474
475
+ final Set <SnapshotId > toResolve = new HashSet <>();
476
+ snapshotIdIterator .forEachRemaining (toResolve ::add );
477
+
436
478
List <SnapshotInfo > snapshotInfos = new ArrayList <>(currentSnapshots .size () + toResolve .size ());
437
479
int repositoryTotalCount = 0 ;
438
480
for (SnapshotInfo snapshotInfo : currentSnapshots ) {
439
481
assert snapshotInfo .startTime () == 0L && snapshotInfo .endTime () == 0L && snapshotInfo .totalShards () == 0L : snapshotInfo ;
440
- if (toResolve .remove (snapshotInfo .snapshot ())) {
482
+ if (toResolve .remove (snapshotInfo .snapshot (). getSnapshotId () )) {
441
483
repositoryTotalCount += 1 ;
442
484
if (afterPredicate .test (snapshotInfo )) {
443
485
snapshotInfos .add (snapshotInfo );
@@ -448,19 +490,19 @@ private void addSimpleSnapshotInfos(
448
490
if (indices ) {
449
491
for (IndexId indexId : repositoryData .getIndices ().values ()) {
450
492
for (SnapshotId snapshotId : repositoryData .getSnapshots (indexId )) {
451
- if (toResolve .contains (new Snapshot ( repoName , snapshotId ) )) {
493
+ if (toResolve .contains (snapshotId )) {
452
494
snapshotsToIndices .computeIfAbsent (snapshotId , (k ) -> new ArrayList <>()).add (indexId .getName ());
453
495
}
454
496
}
455
497
}
456
498
}
457
- for (Snapshot snapshot : toResolve ) {
499
+ for (SnapshotId snapshotId : toResolve ) {
458
500
final var snapshotInfo = new SnapshotInfo (
459
- snapshot ,
460
- snapshotsToIndices .getOrDefault (snapshot . getSnapshotId () , Collections .emptyList ()),
501
+ new Snapshot ( repositoryName , snapshotId ) ,
502
+ snapshotsToIndices .getOrDefault (snapshotId , Collections .emptyList ()),
461
503
Collections .emptyList (),
462
504
Collections .emptyList (),
463
- repositoryData .getSnapshotState (snapshot . getSnapshotId () )
505
+ repositoryData .getSnapshotState (snapshotId )
464
506
);
465
507
repositoryTotalCount += 1 ;
466
508
if (afterPredicate .test (snapshotInfo )) {
0 commit comments