Skip to content

Commit

Permalink
RemoteCacheClient: add getServerCapabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
sluongng committed Sep 11, 2024
1 parent ffc5a49 commit da30780
Show file tree
Hide file tree
Showing 19 changed files with 717 additions and 117 deletions.
17 changes: 13 additions & 4 deletions src/main/java/com/google/devtools/build/lib/remote/ApiVersion.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,21 @@ public class ApiVersion implements Comparable<ApiVersion> {
public final int patch;
public final String prerelease;

// The version of the Remote Execution API that Bazel supports initially.
public static final ApiVersion twoPointZero =
new ApiVersion(SemVer.newBuilder().setMajor(2).setMinor(0).build());
// The version of the Remote Execution API that starts supporting the
// Command.output_paths and ActionResult.output_symlinks fields.
public static final ApiVersion twoPointOne =
new ApiVersion(SemVer.newBuilder().setMajor(2).setMinor(1).build());
// The latest version of the Remote Execution API that Bazel is compatible with.
public static final ApiVersion twoPointTwo =
new ApiVersion(SemVer.newBuilder().setMajor(2).setMinor(2).build());

// The current lowest/highest versions (inclusive) of the Remote Execution API that Bazel
// supports. These fields will need to be updated together with all version changes.
public static final ApiVersion low =
new ApiVersion(SemVer.newBuilder().setMajor(2).setMinor(0).build());
public static final ApiVersion high =
new ApiVersion(SemVer.newBuilder().setMajor(2).setMinor(0).build());
public static final ApiVersion low = twoPointZero;
public static final ApiVersion high = twoPointTwo;

public ApiVersion(int major, int minor, int patch, String prerelease) {
this.major = major;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import build.bazel.remote.execution.v2.FindMissingBlobsResponse;
import build.bazel.remote.execution.v2.GetActionResultRequest;
import build.bazel.remote.execution.v2.RequestMetadata;
import build.bazel.remote.execution.v2.ServerCapabilities;
import build.bazel.remote.execution.v2.UpdateActionResultRequest;
import com.google.bytestream.ByteStreamGrpc;
import com.google.bytestream.ByteStreamGrpc.ByteStreamStub;
Expand Down Expand Up @@ -270,6 +271,11 @@ public CacheCapabilities getCacheCapabilities() throws IOException {
return channel.getServerCapabilities().getCacheCapabilities();
}

@Override
public ServerCapabilities getServerCapabilities() throws IOException {
return channel.getServerCapabilities();
}

@Override
public ListenableFuture<String> getAuthority() {
return channel.withChannelFuture(ch -> Futures.immediateFuture(ch.authority()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import build.bazel.remote.execution.v2.ActionResult;
import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Digest;
import build.bazel.remote.execution.v2.ServerCapabilities;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.flogger.GoogleLogger;
Expand Down Expand Up @@ -120,6 +121,13 @@ public ListenableFuture<String> getRemoteAuthority() {
return remoteCacheClient.getAuthority();
}

public ServerCapabilities getServerCapabilities() throws IOException {
if (remoteCacheClient == null) {
return ServerCapabilities.getDefaultInstance();
}
return remoteCacheClient.getServerCapabilities();
}

public CachedActionResult downloadActionResult(
RemoteActionExecutionContext context, ActionKey actionKey, boolean inlineOutErr)
throws IOException, InterruptedException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ public class RemoteExecutionService {
@Nullable private final Scrubber scrubber;
private final Set<Digest> knownMissingCasDigests;

private Boolean useOutputPaths;

public RemoteExecutionService(
Executor executor,
Reporter reporter,
Expand Down Expand Up @@ -242,32 +244,40 @@ public RemoteExecutionService(
}

private Command buildCommand(
boolean useOutputPaths,
Collection<? extends ActionInput> outputs,
List<String> arguments,
ImmutableMap<String, String> env,
@Nullable Platform platform,
RemotePathResolver remotePathResolver,
@Nullable SpawnScrubber spawnScrubber) {
Command.Builder command = Command.newBuilder();
ArrayList<String> outputFiles = new ArrayList<>();
ArrayList<String> outputDirectories = new ArrayList<>();
ArrayList<String> outputPaths = new ArrayList<>();
for (ActionInput output : outputs) {
String pathString =
reencodeInternalToExternal(remotePathResolver.localPathToOutputPath(output));
if (output.isDirectory()) {
outputDirectories.add(pathString);
} else {
outputFiles.add(pathString);
if (useOutputPaths) {
var outputPaths = new ArrayList<String>();
for (ActionInput output : outputs) {
String pathString =
reencodeInternalToExternal(remotePathResolver.localPathToOutputPath(output));
outputPaths.add(pathString);
}
Collections.sort(outputPaths);
command.addAllOutputPaths(outputPaths);
} else {
var outputFiles = new ArrayList<String>();
var outputDirectories = new ArrayList<String>();
for (ActionInput output : outputs) {
String pathString =
reencodeInternalToExternal(remotePathResolver.localPathToOutputPath(output));
if (output.isDirectory()) {
outputDirectories.add(pathString);
} else {
outputFiles.add(pathString);
}
}
outputPaths.add(pathString);
Collections.sort(outputFiles);
Collections.sort(outputDirectories);
command.addAllOutputFiles(outputFiles);
command.addAllOutputDirectories(outputDirectories);
}
Collections.sort(outputFiles);
Collections.sort(outputDirectories);
Collections.sort(outputPaths);
command.addAllOutputFiles(outputFiles);
command.addAllOutputDirectories(outputDirectories);
command.addAllOutputPaths(outputPaths);

if (platform != null) {
command.setPlatform(platform);
Expand Down Expand Up @@ -542,6 +552,63 @@ private void maybeReleaseRemoteActionBuildingSemaphore() {
remoteActionBuildingSemaphore.release();
}

private synchronized void initUseOutputPaths() {
// If this has already been initialized, return
if (this.useOutputPaths != null) {
return;
}
this.useOutputPaths = remoteOptions.useOutputPaths;
try {
// If both Remote Executor and Remote Cache are configured,
// use the highest version that is supported by both server to compare.
if (remoteExecutor != null && remoteCache != null) {
var executorSupportStatus =
ClientApiVersion.current.checkServerSupportedVersions(
remoteExecutor.getServerCapabilities());
var cacheSupportStatus =
ClientApiVersion.current.checkServerSupportedVersions(
remoteCache.getServerCapabilities());

ApiVersion highestSupportedApiVersion = ApiVersion.low;
if (executorSupportStatus.isSupported() && cacheSupportStatus.isSupported()) {
var executorHighestVersion = executorSupportStatus.getHighestSupportedVersion();
var cacheHighestVersion = cacheSupportStatus.getHighestSupportedVersion();

var commonServerVersion =
executorHighestVersion.compareTo(cacheHighestVersion) <= 0
? executorHighestVersion
: cacheHighestVersion;
this.useOutputPaths = commonServerVersion.compareTo(ApiVersion.twoPointOne) >= 0;
return;
}
}

if (remoteExecutor != null) {
var capabilities = remoteExecutor.getServerCapabilities();
if (capabilities != null) {
var supportStatus = ClientApiVersion.current.checkServerSupportedVersions(capabilities);
if (supportStatus.isSupported()) {
this.useOutputPaths =
supportStatus.getHighestSupportedVersion().compareTo(ApiVersion.twoPointOne) >= 0;
return;
}
}
}
if (remoteCache != null) {
var capabilities = remoteCache.getServerCapabilities();
if (capabilities != null) {
var supportStatus = ClientApiVersion.current.checkServerSupportedVersions(capabilities);
if (supportStatus.isSupported()) {
this.useOutputPaths =
supportStatus.getHighestSupportedVersion().compareTo(ApiVersion.twoPointOne) >= 0;
}
}
}
} catch (IOException e) {
// If we can't determine the server capabilities, use the default value.
}
}

/** Creates a new {@link RemoteAction} instance from spawn. */
public RemoteAction buildRemoteAction(Spawn spawn, SpawnExecutionContext context)
throws IOException, ExecException, ForbiddenActionInputException, InterruptedException {
Expand All @@ -568,8 +635,12 @@ public RemoteAction buildRemoteAction(Spawn spawn, SpawnExecutionContext context
platform = PlatformUtils.getPlatformProto(spawn, remoteOptions);
}

if (this.useOutputPaths == null) {
initUseOutputPaths();
}
Command command =
buildCommand(
this.useOutputPaths,
spawn.getOutputFiles(),
spawn.getArguments(),
spawn.getEnvironment(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import build.bazel.remote.execution.v2.ActionResult;
import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Digest;
import build.bazel.remote.execution.v2.ServerCapabilities;
import com.google.auto.value.AutoValue;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.ListenableFuture;
Expand All @@ -35,6 +36,8 @@
public interface RemoteCacheClient extends MissingDigestsFinder {
CacheCapabilities getCacheCapabilities() throws IOException;

ServerCapabilities getServerCapabilities() throws IOException;

ListenableFuture<String> getAuthority();

/**
Expand Down
Loading

0 comments on commit da30780

Please sign in to comment.