Skip to content

Commit c580d62

Browse files
bazel-iocoeuvre
andauthored
[7.2.0] Implement XattrProvider which uses BatchStat to getFastDigest (bazelbuild#21946)
If `--experimental_remote_output_service` is set, a `XattrProvider` which uses `BatchStat` RPC to get the digest of a file will be used for Bazel to get digests for outputs. Working towards bazelbuild#21630. Closes bazelbuild#21812. PiperOrigin-RevId: 619539349 Change-Id: I71364e78c45c37e834c71e120a109c8de602db77 Commit bazelbuild@30aa5d0 Co-authored-by: Chi Wang <[email protected]>
1 parent d09983b commit c580d62

File tree

5 files changed

+124
-13
lines changed

5 files changed

+124
-13
lines changed

src/main/java/com/google/devtools/build/lib/remote/BazelOutputService.java

+77-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import com.google.devtools.build.lib.actions.ExecException;
2727
import com.google.devtools.build.lib.actions.cache.OutputMetadataStore;
2828
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;
2931
import com.google.devtools.build.lib.remote.BazelOutputServiceProto.CleanRequest;
3032
import com.google.devtools.build.lib.remote.BazelOutputServiceProto.CleanResponse;
3133
import com.google.devtools.build.lib.remote.BazelOutputServiceProto.FinalizeArtifactsRequest;
@@ -53,9 +55,12 @@
5355
import com.google.devtools.build.lib.vfs.OutputService;
5456
import com.google.devtools.build.lib.vfs.Path;
5557
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;
5660
import com.google.protobuf.Any;
5761
import io.grpc.Status;
5862
import io.grpc.StatusRuntimeException;
63+
import java.io.FileNotFoundException;
5964
import java.io.IOException;
6065
import java.util.List;
6166
import java.util.Map;
@@ -76,6 +81,7 @@ public class BazelOutputService implements OutputService {
7681
private final ReferenceCountedChannel channel;
7782

7883
@Nullable private String buildId;
84+
@Nullable private PathFragment outputPathTarget;
7985

8086
public BazelOutputService(
8187
Path outputBase,
@@ -223,7 +229,8 @@ public ModifiedFileSet startBuild(
223229
.build()));
224230
}
225231

226-
var outputPathTarget = constructOutputPathTarget(outputPathPrefix, response);
232+
checkState(outputPathTarget == null, "outputPathTarget must be null");
233+
outputPathTarget = constructOutputPathTarget(outputPathPrefix, response);
227234
prepareOutputPath(outputPath, outputPathTarget);
228235

229236
if (finalizeActions) {
@@ -314,6 +321,7 @@ public void finalizeBuild(boolean buildSuccessful)
314321
.build()));
315322
} finally {
316323
this.buildId = null;
324+
this.outputPathTarget = null;
317325
}
318326
}
319327

@@ -432,4 +440,72 @@ private CleanResponse clean(CleanRequest request) throws IOException, Interrupte
432440
}
433441
}));
434442
}
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+
}
435511
}

src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java

+17-12
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public void injectTree(SpecialArtifact output, TreeArtifactValue tree) {
217217
@Nullable private ActionCompletedReceiver completionReceiver;
218218

219219
private final AtomicReference<ActionExecutionStatusReporter> statusReporterRef;
220-
private OutputService outputService;
220+
@Nullable private OutputService outputService;
221221
private boolean finalizeActions;
222222
private boolean rewindingEnabled;
223223
private final Supplier<ImmutableList<Root>> sourceRootSupplier;
@@ -283,7 +283,7 @@ void prepareForExecution(
283283
OptionsProvider options,
284284
ActionCacheChecker actionCacheChecker,
285285
ActionOutputDirectoryHelper outputDirectoryHelper,
286-
OutputService outputService,
286+
@Nullable OutputService outputService,
287287
boolean trackIncrementalState) {
288288
this.reporter = checkNotNull(reporter);
289289
this.executorEngine = checkNotNull(executor);
@@ -361,6 +361,10 @@ OutputPermissions getOutputPermissions() {
361361
}
362362

363363
XattrProvider getXattrProvider() {
364+
if (outputService != null) {
365+
return checkNotNull(outputService.getXattrProvider(syscallCache));
366+
}
367+
364368
return syscallCache;
365369
}
366370

@@ -369,14 +373,15 @@ FileSystem createActionFileSystem(
369373
String relativeOutputPath,
370374
ActionInputMap inputArtifactData,
371375
Iterable<Artifact> outputArtifacts) {
372-
return outputService.createActionFileSystem(
373-
executorEngine.getFileSystem(),
374-
executorEngine.getExecRoot().asFragment(),
375-
relativeOutputPath,
376-
sourceRootSupplier.get(),
377-
inputArtifactData,
378-
outputArtifacts,
379-
rewindingEnabled);
376+
return checkNotNull(outputService)
377+
.createActionFileSystem(
378+
executorEngine.getFileSystem(),
379+
executorEngine.getExecRoot().asFragment(),
380+
relativeOutputPath,
381+
sourceRootSupplier.get(),
382+
inputArtifactData,
383+
outputArtifacts,
384+
rewindingEnabled);
380385
}
381386

382387
private void updateActionFileSystemContext(
@@ -385,8 +390,8 @@ private void updateActionFileSystemContext(
385390
Environment env,
386391
MetadataInjector metadataInjector,
387392
ImmutableMap<Artifact, ImmutableList<FilesetOutputSymlink>> filesets) {
388-
outputService.updateActionFileSystemContext(
389-
action, actionFileSystem, env, metadataInjector, filesets);
393+
checkNotNull(outputService)
394+
.updateActionFileSystemContext(action, actionFileSystem, env, metadataInjector, filesets);
390395
}
391396

392397
void executionOver() {

src/main/java/com/google/devtools/build/lib/vfs/OutputService.java

+4
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,8 @@ default ArtifactPathResolver createPathResolverForArtifactValues(
241241
default BulkDeleter bulkDeleter() {
242242
return null;
243243
}
244+
245+
default XattrProvider getXattrProvider(XattrProvider delegate) {
246+
return delegate;
247+
}
244248
}

src/main/java/com/google/devtools/build/lib/vfs/XattrProvider.java

+25
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,29 @@ default byte[] getxattr(Path path, String xattrName) throws IOException {
3838
default byte[] getxattr(Path path, String xattrName, Symlinks followSymlinks) throws IOException {
3939
return path.getxattr(xattrName, followSymlinks);
4040
}
41+
42+
/** Delegates to another {@link XattrProvider}. */
43+
class DelegatingXattrProvider implements XattrProvider {
44+
private final XattrProvider delegate;
45+
46+
public DelegatingXattrProvider(XattrProvider delegate) {
47+
this.delegate = delegate;
48+
}
49+
50+
@Override
51+
public byte[] getFastDigest(Path path) throws IOException {
52+
return delegate.getFastDigest(path);
53+
}
54+
55+
@Override
56+
public byte[] getxattr(Path path, String xattrName) throws IOException {
57+
return delegate.getxattr(path, xattrName);
58+
}
59+
60+
@Override
61+
public byte[] getxattr(Path path, String xattrName, Symlinks followSymlinks)
62+
throws IOException {
63+
return delegate.getxattr(path, xattrName, followSymlinks);
64+
}
65+
}
4166
}

src/test/java/com/google/devtools/build/lib/skyframe/OutputsInvalidationIntegrationTest.java

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public void prepareOutputServiceMock()
5757
when(outputService.getFilesSystemName()).thenReturn("fileSystemName");
5858
when(outputService.startBuild(any(), any(), anyBoolean()))
5959
.thenReturn(ModifiedFileSet.EVERYTHING_MODIFIED);
60+
when(outputService.getXattrProvider(any())).thenAnswer(i -> i.getArgument(0));
6061
}
6162

6263
@Override

0 commit comments

Comments
 (0)