42
42
import com .google .devtools .build .lib .events .Event ;
43
43
import com .google .devtools .build .lib .events .ExtendedEventHandler .Postable ;
44
44
import com .google .devtools .build .lib .events .Reporter ;
45
+ import com .google .devtools .build .lib .remote .common .CacheNotFoundException ;
45
46
import com .google .devtools .build .lib .remote .util .AsyncTaskCache ;
46
47
import com .google .devtools .build .lib .remote .util .RxUtils .TransferResult ;
47
48
import com .google .devtools .build .lib .remote .util .TempPathGenerator ;
61
62
import java .util .Set ;
62
63
import java .util .concurrent .atomic .AtomicBoolean ;
63
64
import java .util .regex .Pattern ;
65
+ import javax .annotation .Nullable ;
64
66
65
67
/**
66
68
* Abstract implementation of {@link ActionInputPrefetcher} which implements the orchestration of
@@ -78,6 +80,8 @@ public abstract class AbstractActionInputPrefetcher implements ActionInputPrefet
78
80
protected final Path execRoot ;
79
81
protected final ImmutableList <Pattern > patternsToDownload ;
80
82
83
+ private final Set <ActionInput > missingActionInputs = Sets .newConcurrentHashSet ();
84
+
81
85
private static class Context {
82
86
private final Set <Path > nonWritableDirs = Sets .newConcurrentHashSet ();
83
87
@@ -399,7 +403,8 @@ private Completable prefetchInputFileOrSymlink(
399
403
PathFragment prefetchExecPath = metadata .getMaterializationExecPath ().orElse (execPath );
400
404
401
405
Completable prefetch =
402
- downloadFileNoCheckRx (context , execRoot .getRelative (prefetchExecPath ), metadata , priority );
406
+ downloadFileNoCheckRx (
407
+ context , execRoot .getRelative (prefetchExecPath ), input , metadata , priority );
403
408
404
409
// If prefetching to a different path, plant a symlink into it.
405
410
if (!prefetchExecPath .equals (execPath )) {
@@ -418,15 +423,23 @@ private Completable prefetchInputFileOrSymlink(
418
423
* download finished.
419
424
*/
420
425
private Completable downloadFileRx (
421
- Context context , Path path , FileArtifactValue metadata , Priority priority ) {
426
+ Context context ,
427
+ Path path ,
428
+ @ Nullable ActionInput actionInput ,
429
+ FileArtifactValue metadata ,
430
+ Priority priority ) {
422
431
if (!canDownloadFile (path , metadata )) {
423
432
return Completable .complete ();
424
433
}
425
- return downloadFileNoCheckRx (context , path , metadata , priority );
434
+ return downloadFileNoCheckRx (context , path , actionInput , metadata , priority );
426
435
}
427
436
428
437
private Completable downloadFileNoCheckRx (
429
- Context context , Path path , FileArtifactValue metadata , Priority priority ) {
438
+ Context context ,
439
+ Path path ,
440
+ @ Nullable ActionInput actionInput ,
441
+ FileArtifactValue metadata ,
442
+ Priority priority ) {
430
443
if (path .isSymbolicLink ()) {
431
444
try {
432
445
path = path .getRelative (path .readSymbolicLink ());
@@ -440,26 +453,32 @@ private Completable downloadFileNoCheckRx(
440
453
AtomicBoolean completed = new AtomicBoolean (false );
441
454
Completable download =
442
455
Completable .using (
443
- tempPathGenerator ::generateTempPath ,
444
- tempPath ->
445
- toCompletable (
446
- () ->
447
- doDownloadFile (
448
- tempPath , finalPath .relativeTo (execRoot ), metadata , priority ),
449
- directExecutor ())
450
- .doOnComplete (
451
- () -> {
452
- finalizeDownload (context , tempPath , finalPath );
453
- completed .set (true );
454
- }),
455
- tempPath -> {
456
- if (!completed .get ()) {
457
- deletePartialDownload (tempPath );
458
- }
459
- },
460
- // Set eager=false here because we want cleanup the download *after* upstream is
461
- // disposed.
462
- /* eager= */ false );
456
+ tempPathGenerator ::generateTempPath ,
457
+ tempPath ->
458
+ toCompletable (
459
+ () ->
460
+ doDownloadFile (
461
+ tempPath , finalPath .relativeTo (execRoot ), metadata , priority ),
462
+ directExecutor ())
463
+ .doOnComplete (
464
+ () -> {
465
+ finalizeDownload (context , tempPath , finalPath );
466
+ completed .set (true );
467
+ }),
468
+ tempPath -> {
469
+ if (!completed .get ()) {
470
+ deletePartialDownload (tempPath );
471
+ }
472
+ },
473
+ // Set eager=false here because we want cleanup the download *after* upstream is
474
+ // disposed.
475
+ /* eager= */ false )
476
+ .doOnError (
477
+ error -> {
478
+ if (error instanceof CacheNotFoundException && actionInput != null ) {
479
+ missingActionInputs .add (actionInput );
480
+ }
481
+ });
463
482
464
483
return downloadCache .executeIfNot (
465
484
finalPath ,
@@ -479,19 +498,27 @@ private Completable downloadFileNoCheckRx(
479
498
* <p>The file will be written into a temporary file and moved to the final destination after the
480
499
* download finished.
481
500
*/
482
- public void downloadFile (Path path , FileArtifactValue metadata )
501
+ public void downloadFile (Path path , @ Nullable ActionInput actionInput , FileArtifactValue metadata )
483
502
throws IOException , InterruptedException {
484
- getFromFuture (downloadFileAsync (path .asFragment (), metadata , Priority .CRITICAL ));
503
+ getFromFuture (downloadFileAsync (path .asFragment (), actionInput , metadata , Priority .CRITICAL ));
485
504
}
486
505
487
506
protected ListenableFuture <Void > downloadFileAsync (
488
- PathFragment path , FileArtifactValue metadata , Priority priority ) {
507
+ PathFragment path ,
508
+ @ Nullable ActionInput actionInput ,
509
+ FileArtifactValue metadata ,
510
+ Priority priority ) {
489
511
Context context = new Context ();
490
512
return toListenableFuture (
491
513
Completable .using (
492
514
() -> context ,
493
515
ctx ->
494
- downloadFileRx (context , execRoot .getFileSystem ().getPath (path ), metadata , priority ),
516
+ downloadFileRx (
517
+ context ,
518
+ execRoot .getFileSystem ().getPath (path ),
519
+ actionInput ,
520
+ metadata ,
521
+ priority ),
495
522
Context ::finalizeContext ));
496
523
}
497
524
@@ -648,4 +675,8 @@ private boolean outputMatchesPattern(Artifact output) {
648
675
public void flushOutputTree () throws InterruptedException {
649
676
downloadCache .awaitInProgressTasks ();
650
677
}
678
+
679
+ public ImmutableSet <ActionInput > getMissingActionInputs () {
680
+ return ImmutableSet .copyOf (missingActionInputs );
681
+ }
651
682
}
0 commit comments