26
26
import com .google .devtools .build .lib .actions .ExecException ;
27
27
import com .google .devtools .build .lib .actions .cache .OutputMetadataStore ;
28
28
import com .google .devtools .build .lib .events .EventHandler ;
29
+ import com .google .devtools .build .lib .remote .BazelOutputServiceProto .BatchStatRequest ;
30
+ import com .google .devtools .build .lib .remote .BazelOutputServiceProto .BatchStatResponse ;
29
31
import com .google .devtools .build .lib .remote .BazelOutputServiceProto .CleanRequest ;
30
32
import com .google .devtools .build .lib .remote .BazelOutputServiceProto .CleanResponse ;
31
33
import com .google .devtools .build .lib .remote .BazelOutputServiceProto .FinalizeArtifactsRequest ;
53
55
import com .google .devtools .build .lib .vfs .OutputService ;
54
56
import com .google .devtools .build .lib .vfs .Path ;
55
57
import com .google .devtools .build .lib .vfs .PathFragment ;
58
+ import com .google .devtools .build .lib .vfs .XattrProvider ;
59
+ import com .google .devtools .build .lib .vfs .XattrProvider .DelegatingXattrProvider ;
56
60
import com .google .protobuf .Any ;
57
61
import io .grpc .Status ;
58
62
import io .grpc .StatusRuntimeException ;
63
+ import java .io .FileNotFoundException ;
59
64
import java .io .IOException ;
60
65
import java .util .List ;
61
66
import java .util .Map ;
@@ -76,6 +81,7 @@ public class BazelOutputService implements OutputService {
76
81
private final ReferenceCountedChannel channel ;
77
82
78
83
@ Nullable private String buildId ;
84
+ @ Nullable private PathFragment outputPathTarget ;
79
85
80
86
public BazelOutputService (
81
87
Path outputBase ,
@@ -223,7 +229,8 @@ public ModifiedFileSet startBuild(
223
229
.build ()));
224
230
}
225
231
226
- var outputPathTarget = constructOutputPathTarget (outputPathPrefix , response );
232
+ checkState (outputPathTarget == null , "outputPathTarget must be null" );
233
+ outputPathTarget = constructOutputPathTarget (outputPathPrefix , response );
227
234
prepareOutputPath (outputPath , outputPathTarget );
228
235
229
236
if (finalizeActions ) {
@@ -314,6 +321,7 @@ public void finalizeBuild(boolean buildSuccessful)
314
321
.build ()));
315
322
} finally {
316
323
this .buildId = null ;
324
+ this .outputPathTarget = null ;
317
325
}
318
326
}
319
327
@@ -432,4 +440,72 @@ private CleanResponse clean(CleanRequest request) throws IOException, Interrupte
432
440
}
433
441
}));
434
442
}
443
+
444
+ private BatchStatResponse batchStat (BatchStatRequest request )
445
+ throws IOException , InterruptedException {
446
+ return retrier .execute (
447
+ () ->
448
+ channel .withChannelBlocking (
449
+ channel -> {
450
+ try {
451
+ return BazelOutputServiceGrpc .newBlockingStub (channel ).batchStat (request );
452
+ } catch (StatusRuntimeException e ) {
453
+ throw new IOException (e );
454
+ }
455
+ }));
456
+ }
457
+
458
+ @ Override
459
+ public XattrProvider getXattrProvider (XattrProvider delegate ) {
460
+ return new DelegatingXattrProvider (delegate ) {
461
+ @ Nullable
462
+ @ Override
463
+ public byte [] getFastDigest (Path path ) throws IOException {
464
+ var outputPath = outputPathSupplier .get ();
465
+ var buildId = checkNotNull (BazelOutputService .this .buildId );
466
+ var outputPathTarget = checkNotNull (BazelOutputService .this .outputPathTarget );
467
+
468
+ String pathString = null ;
469
+ if (path .startsWith (outputPath )) {
470
+ pathString = path .relativeTo (outputPath ).toString ();
471
+ } else if (path .startsWith (outputPathTarget )) {
472
+ pathString = path .asFragment ().relativeTo (outputPathTarget ).toString ();
473
+ }
474
+ if (pathString == null ) {
475
+ return super .getFastDigest (path );
476
+ }
477
+
478
+ var request =
479
+ BatchStatRequest .newBuilder ().setBuildId (buildId ).addPaths (pathString ).build ();
480
+ BatchStatResponse response ;
481
+ try {
482
+ response = batchStat (request );
483
+ } catch (InterruptedException e ) {
484
+ throw new IOException (e );
485
+ }
486
+
487
+ if (response .getResponsesCount () != 1 ) {
488
+ throw new IOException (
489
+ String .format (
490
+ "BatchStat failed: expect 1 response, got %s" , response .getResponsesCount ()));
491
+ }
492
+
493
+ var statResponse = response .getResponses (0 );
494
+ if (!statResponse .hasStat ()) {
495
+ throw new FileNotFoundException (path .getPathString ());
496
+ }
497
+
498
+ var stat = statResponse .getStat ();
499
+ if (stat .hasFile ()) {
500
+ var file = stat .getFile ();
501
+ if (file .hasLocator ()) {
502
+ var locator = file .getLocator ().unpack (FileArtifactLocator .class );
503
+ return DigestUtil .toBinaryDigest (locator .getDigest ());
504
+ }
505
+ }
506
+
507
+ return null ;
508
+ }
509
+ };
510
+ }
435
511
}
0 commit comments