Pull upload(ActionResult) into super class.
Remove the custom upload(ActionResult) implementations from SimpleBlobStoreActionCache and GrpcRemoteCache.
This is a big step towards merging SimpleBlobStoreActionCache and GrpcRemoteCache.
Closes #9167.
PiperOrigin-RevId: 264563384
diff --git a/src/main/java/com/google/devtools/build/lib/remote/AbstractRemoteActionCache.java b/src/main/java/com/google/devtools/build/lib/remote/AbstractRemoteActionCache.java
index d53bb72..b5dbc4c 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/AbstractRemoteActionCache.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/AbstractRemoteActionCache.java
@@ -29,6 +29,7 @@
import build.bazel.remote.execution.v2.Tree;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -79,6 +80,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
@@ -120,20 +122,8 @@
abstract ActionResult getCachedActionResult(ActionKey actionKey)
throws IOException, InterruptedException;
- /**
- * Upload the result of a locally executed action to the remote cache.
- *
- * @throws IOException if there was an error uploading to the remote cache
- * @throws ExecException if uploading any of the action outputs is not supported
- */
- abstract void upload(
- SimpleBlobStore.ActionKey actionKey,
- Action action,
- Command command,
- Path execRoot,
- Collection<Path> files,
- FileOutErr outErr)
- throws ExecException, IOException, InterruptedException;
+ protected abstract void setCachedActionResult(ActionKey actionKey, ActionResult action)
+ throws IOException, InterruptedException;
/**
* Uploads a file
@@ -157,6 +147,116 @@
*/
protected abstract ListenableFuture<Void> uploadBlob(Digest digest, ByteString data);
+ protected abstract ImmutableSet<Digest> getMissingDigests(Iterable<Digest> digests)
+ throws IOException, InterruptedException;
+
+ /**
+ * Upload the result of a locally executed action to the remote cache.
+ *
+ * @throws IOException if there was an error uploading to the remote cache
+ * @throws ExecException if uploading any of the action outputs is not supported
+ */
+ public ActionResult upload(
+ ActionKey actionKey,
+ Action action,
+ Command command,
+ Path execRoot,
+ Collection<Path> outputs,
+ FileOutErr outErr,
+ int exitCode)
+ throws ExecException, IOException, InterruptedException {
+ ActionResult.Builder resultBuilder = ActionResult.newBuilder();
+ uploadOutputs(execRoot, actionKey, action, command, outputs, outErr, resultBuilder);
+ resultBuilder.setExitCode(exitCode);
+ ActionResult result = resultBuilder.build();
+ if (exitCode == 0 && !action.getDoNotCache()) {
+ setCachedActionResult(actionKey, result);
+ }
+ return result;
+ }
+
+ public ActionResult upload(
+ ActionKey actionKey,
+ Action action,
+ Command command,
+ Path execRoot,
+ Collection<Path> outputs,
+ FileOutErr outErr)
+ throws ExecException, IOException, InterruptedException {
+ return upload(actionKey, action, command, execRoot, outputs, outErr, /* exitCode= */ 0);
+ }
+
+ private void uploadOutputs(
+ Path execRoot,
+ ActionKey actionKey,
+ Action action,
+ Command command,
+ Collection<Path> files,
+ FileOutErr outErr,
+ ActionResult.Builder result)
+ throws ExecException, IOException, InterruptedException {
+ UploadManifest manifest =
+ new UploadManifest(
+ digestUtil,
+ result,
+ execRoot,
+ options.incompatibleRemoteSymlinks,
+ options.allowSymlinkUpload);
+ manifest.addFiles(files);
+ manifest.setStdoutStderr(outErr);
+ manifest.addAction(actionKey, action, command);
+
+ Map<Digest, Path> digestToFile = manifest.getDigestToFile();
+ Map<Digest, ByteString> digestToBlobs = manifest.getDigestToBlobs();
+ Collection<Digest> digests = new ArrayList<>();
+ digests.addAll(digestToFile.keySet());
+ digests.addAll(digestToBlobs.keySet());
+
+ ImmutableSet<Digest> digestsToUpload = getMissingDigests(digests);
+ ImmutableList.Builder<ListenableFuture<Void>> uploads = ImmutableList.builder();
+ for (Digest digest : digestsToUpload) {
+ Path file = digestToFile.get(digest);
+ if (file != null) {
+ uploads.add(uploadFile(digest, file));
+ } else {
+ ByteString blob = digestToBlobs.get(digest);
+ if (blob == null) {
+ String message = "FindMissingBlobs call returned an unknown digest: " + digest;
+ throw new IOException(message);
+ }
+ uploads.add(uploadBlob(digest, blob));
+ }
+ }
+
+ waitForUploads(uploads.build());
+
+ if (manifest.getStderrDigest() != null) {
+ result.setStderrDigest(manifest.getStderrDigest());
+ }
+ if (manifest.getStdoutDigest() != null) {
+ result.setStdoutDigest(manifest.getStdoutDigest());
+ }
+ }
+
+ private static void waitForUploads(List<ListenableFuture<Void>> uploads)
+ throws IOException, InterruptedException {
+ try {
+ for (ListenableFuture<Void> upload : uploads) {
+ upload.get();
+ }
+ } catch (ExecutionException e) {
+ // TODO(buchgr): Add support for cancellation and factor this method out to be shared
+ // between ByteStreamUploader as well.
+ Throwable cause = e.getCause();
+ Throwables.throwIfInstanceOf(cause, IOException.class);
+ Throwables.throwIfInstanceOf(cause, InterruptedException.class);
+ if (cause != null) {
+ throw new IOException(cause);
+ }
+ throw new IOException(e);
+ }
+ }
+
/**
* Downloads a blob with a content hash {@code digest} to {@code out}.
*
diff --git a/src/main/java/com/google/devtools/build/lib/remote/GrpcRemoteCache.java b/src/main/java/com/google/devtools/build/lib/remote/GrpcRemoteCache.java
index e6c5c63..e9fdb16 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/GrpcRemoteCache.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/GrpcRemoteCache.java
@@ -17,11 +17,9 @@
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.String.format;
-import build.bazel.remote.execution.v2.Action;
import build.bazel.remote.execution.v2.ActionCacheGrpc;
import build.bazel.remote.execution.v2.ActionCacheGrpc.ActionCacheBlockingStub;
import build.bazel.remote.execution.v2.ActionResult;
-import build.bazel.remote.execution.v2.Command;
import build.bazel.remote.execution.v2.ContentAddressableStorageGrpc;
import build.bazel.remote.execution.v2.ContentAddressableStorageGrpc.ContentAddressableStorageFutureStub;
import build.bazel.remote.execution.v2.Digest;
@@ -38,7 +36,6 @@
import com.google.common.base.Ascii;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
@@ -50,7 +47,6 @@
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import com.google.devtools.build.lib.actions.ActionInput;
-import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.remote.RemoteRetrier.ProgressiveBackoff;
import com.google.devtools.build.lib.remote.common.SimpleBlobStore.ActionKey;
@@ -58,7 +54,6 @@
import com.google.devtools.build.lib.remote.options.RemoteOptions;
import com.google.devtools.build.lib.remote.util.DigestUtil;
import com.google.devtools.build.lib.remote.util.TracingMetadataUtils;
-import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.Path;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
@@ -70,7 +65,6 @@
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@@ -166,17 +160,8 @@
|| Ascii.toLowerCase(options.remoteCache).startsWith("https://"));
}
- private ListenableFuture<FindMissingBlobsResponse> getMissingDigests(
- FindMissingBlobsRequest request) throws IOException, InterruptedException {
- Context ctx = Context.current();
- try {
- return retrier.executeAsync(() -> ctx.call(() -> casFutureStub().findMissingBlobs(request)));
- } catch (StatusRuntimeException e) {
- throw new IOException(e);
- }
- }
-
- private ImmutableSet<Digest> getMissingDigests(Iterable<Digest> digests)
+ @Override
+ protected ImmutableSet<Digest> getMissingDigests(Iterable<Digest> digests)
throws IOException, InterruptedException {
if (Iterables.isEmpty(digests)) {
return ImmutableSet.of();
@@ -208,6 +193,16 @@
return result.build();
}
+ private ListenableFuture<FindMissingBlobsResponse> getMissingDigests(
+ FindMissingBlobsRequest request) throws IOException, InterruptedException {
+ Context ctx = Context.current();
+ try {
+ return retrier.executeAsync(() -> ctx.call(() -> casFutureStub().findMissingBlobs(request)));
+ } catch (StatusRuntimeException e) {
+ throw new IOException(e);
+ }
+ }
+
/**
* Ensures that the tree structure of the inputs, the input files themselves, and the command are
* available in the remote cache, such that the tree can be reassembled and executed on another
@@ -377,32 +372,6 @@
}
@Override
- public void upload(
- ActionKey actionKey,
- Action action,
- Command command,
- Path execRoot,
- Collection<Path> files,
- FileOutErr outErr)
- throws ExecException, IOException, InterruptedException {
- ActionResult.Builder result = ActionResult.newBuilder();
- upload(execRoot, actionKey, action, command, files, outErr, result);
- try {
- retrier.execute(
- () ->
- acBlockingStub()
- .updateActionResult(
- UpdateActionResultRequest.newBuilder()
- .setInstanceName(options.remoteInstanceName)
- .setActionDigest(actionKey.getDigest())
- .setActionResult(result)
- .build()));
- } catch (StatusRuntimeException e) {
- throw new IOException(e);
- }
- }
-
- @Override
protected ListenableFuture<Void> uploadFile(Digest digest, Path path) {
return uploader.uploadBlobAsync(
HashCode.fromString(digest.getHash()),
@@ -418,77 +387,6 @@
/* forceUpload= */ true);
}
- void upload(
- Path execRoot,
- ActionKey actionKey,
- Action action,
- Command command,
- Collection<Path> files,
- FileOutErr outErr,
- ActionResult.Builder result)
- throws ExecException, IOException, InterruptedException {
- UploadManifest manifest =
- new UploadManifest(
- digestUtil,
- result,
- execRoot,
- options.incompatibleRemoteSymlinks,
- options.allowSymlinkUpload);
- manifest.addFiles(files);
- manifest.setStdoutStderr(outErr);
- manifest.addAction(actionKey, action, command);
-
- Map<Digest, Path> digestToFile = manifest.getDigestToFile();
- Map<Digest, ByteString> digestToBlobs = manifest.getDigestToBlobs();
- Collection<Digest> digests = new ArrayList<>();
- digests.addAll(digestToFile.keySet());
- digests.addAll(digestToBlobs.keySet());
-
- ImmutableSet<Digest> digestsToUpload = getMissingDigests(digests);
- ImmutableList.Builder<ListenableFuture<Void>> uploads = ImmutableList.builder();
- for (Digest digest : digestsToUpload) {
- Path file = digestToFile.get(digest);
- if (file != null) {
- uploads.add(uploadFile(digest, file));
- } else {
- ByteString blob = digestToBlobs.get(digest);
- if (blob == null) {
- String message = "FindMissingBlobs call returned an unknown digest: " + digest;
- throw new IOException(message);
- }
- uploads.add(uploadBlob(digest, blob));
- }
- }
-
- waitForUploads(uploads.build());
-
- if (manifest.getStderrDigest() != null) {
- result.setStderrDigest(manifest.getStderrDigest());
- }
- if (manifest.getStdoutDigest() != null) {
- result.setStdoutDigest(manifest.getStdoutDigest());
- }
- }
-
- private static void waitForUploads(List<ListenableFuture<Void>> uploads)
- throws IOException, InterruptedException {
- try {
- for (ListenableFuture<Void> upload : uploads) {
- upload.get();
- }
- } catch (ExecutionException e) {
- // TODO(buchgr): Add support for cancellation and factor this method out to be shared
- // between ByteStreamUploader as well.
- Throwable cause = e.getCause();
- Throwables.throwIfInstanceOf(cause, IOException.class);
- Throwables.throwIfInstanceOf(cause, InterruptedException.class);
- if (cause != null) {
- throw new IOException(cause);
- }
- throw new IOException(e);
- }
- }
-
// Execution Cache API
@Override
@@ -511,4 +409,22 @@
throw new IOException(e);
}
}
+
+ @Override
+ protected void setCachedActionResult(ActionKey actionKey, ActionResult result)
+ throws IOException, InterruptedException {
+ try {
+ retrier.execute(
+ () ->
+ acBlockingStub()
+ .updateActionResult(
+ UpdateActionResultRequest.newBuilder()
+ .setInstanceName(options.remoteInstanceName)
+ .setActionDigest(actionKey.getDigest())
+ .setActionResult(result)
+ .build()));
+ } catch (StatusRuntimeException e) {
+ throw new IOException(e);
+ }
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/remote/SimpleBlobStoreActionCache.java b/src/main/java/com/google/devtools/build/lib/remote/SimpleBlobStoreActionCache.java
index fba3ba0..8822c0d 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/SimpleBlobStoreActionCache.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/SimpleBlobStoreActionCache.java
@@ -14,35 +14,30 @@
package com.google.devtools.build.lib.remote;
-import build.bazel.remote.execution.v2.Action;
import build.bazel.remote.execution.v2.ActionResult;
-import build.bazel.remote.execution.v2.Command;
import build.bazel.remote.execution.v2.Digest;
import build.bazel.remote.execution.v2.Directory;
import build.bazel.remote.execution.v2.DirectoryNode;
import build.bazel.remote.execution.v2.FileNode;
+import com.google.common.collect.ImmutableSet;
import com.google.common.hash.HashingOutputStream;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
-import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.remote.common.SimpleBlobStore;
import com.google.devtools.build.lib.remote.common.SimpleBlobStore.ActionKey;
import com.google.devtools.build.lib.remote.options.RemoteOptions;
import com.google.devtools.build.lib.remote.util.DigestUtil;
import com.google.devtools.build.lib.remote.util.Utils;
-import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.Path;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
-import java.util.Collection;
-import java.util.Map;
import javax.annotation.Nullable;
/**
@@ -77,60 +72,6 @@
}
@Override
- public void upload(
- SimpleBlobStore.ActionKey actionKey,
- Action action,
- Command command,
- Path execRoot,
- Collection<Path> files,
- FileOutErr outErr)
- throws ExecException, IOException, InterruptedException {
- ActionResult.Builder result = ActionResult.newBuilder();
- upload(result, actionKey, action, command, execRoot, files, /* uploadAction= */ true);
- if (outErr.getErrorPath().exists()) {
- Digest stdErrDigest = digestUtil.compute(outErr.getErrorPath());
- getFromFuture(uploadFile(stdErrDigest, outErr.getErrorPath()));
- result.setStderrDigest(stdErrDigest);
- }
- if (outErr.getOutputPath().exists()) {
- Digest stdoutDigest = digestUtil.compute(outErr.getOutputPath());
- getFromFuture(uploadFile(stdoutDigest, outErr.getOutputPath()));
- result.setStdoutDigest(stdoutDigest);
- }
- blobStore.putActionResult(actionKey, result.build());
- }
-
- public void upload(
- ActionResult.Builder result,
- SimpleBlobStore.ActionKey actionKey,
- Action action,
- Command command,
- Path execRoot,
- Collection<Path> files,
- boolean uploadAction)
- throws ExecException, IOException, InterruptedException {
- UploadManifest manifest =
- new UploadManifest(
- digestUtil,
- result,
- execRoot,
- options.incompatibleRemoteSymlinks,
- options.allowSymlinkUpload);
- manifest.addFiles(files);
- if (uploadAction) {
- manifest.addAction(actionKey, action, command);
- }
-
- for (Map.Entry<Digest, Path> entry : manifest.getDigestToFile().entrySet()) {
- getFromFuture(uploadFile(entry.getKey(), entry.getValue()));
- }
-
- for (Map.Entry<Digest, ByteString> entry : manifest.getDigestToBlobs().entrySet()) {
- getFromFuture(uploadBlob(entry.getKey(), entry.getValue()));
- }
- }
-
- @Override
public ListenableFuture<Void> uploadFile(Digest digest, Path file) {
return blobStore.uploadFile(digest, file);
}
@@ -140,6 +81,11 @@
return blobStore.uploadBlob(digest, data);
}
+ @Override
+ protected ImmutableSet<Digest> getMissingDigests(Iterable<Digest> digests) {
+ return ImmutableSet.copyOf(digests);
+ }
+
public boolean containsKey(Digest digest) throws IOException, InterruptedException {
return blobStore.contains(digest.getHash());
}
diff --git a/src/test/java/com/google/devtools/build/lib/remote/AbstractRemoteActionCacheTests.java b/src/test/java/com/google/devtools/build/lib/remote/AbstractRemoteActionCacheTests.java
index d8e6959..a9b274f 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/AbstractRemoteActionCacheTests.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/AbstractRemoteActionCacheTests.java
@@ -24,9 +24,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import build.bazel.remote.execution.v2.Action;
import build.bazel.remote.execution.v2.ActionResult;
-import build.bazel.remote.execution.v2.Command;
import build.bazel.remote.execution.v2.Digest;
import build.bazel.remote.execution.v2.Directory;
import build.bazel.remote.execution.v2.DirectoryNode;
@@ -38,6 +36,7 @@
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@@ -76,7 +75,6 @@
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -1150,20 +1148,12 @@
@Nullable
@Override
- ActionResult getCachedActionResult(ActionKey actionKey)
- throws IOException, InterruptedException {
+ ActionResult getCachedActionResult(ActionKey actionKey) {
throw new UnsupportedOperationException();
}
@Override
- void upload(
- ActionKey actionKey,
- Action action,
- Command command,
- Path execRoot,
- Collection<Path> files,
- FileOutErr outErr)
- throws ExecException, IOException, InterruptedException {
+ protected void setCachedActionResult(ActionKey actionKey, ActionResult action) {
throw new UnsupportedOperationException();
}
@@ -1178,6 +1168,11 @@
}
@Override
+ protected ImmutableSet<Digest> getMissingDigests(Iterable<Digest> digests) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
protected ListenableFuture<Void> downloadBlob(Digest digest, OutputStream out) {
SettableFuture<Void> result = SettableFuture.create();
ListenableFuture<byte[]> downloadResult = downloadResults.get(digest);
diff --git a/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteCacheTest.java b/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteCacheTest.java
index bfa5320..4d8119ef 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteCacheTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/GrpcRemoteCacheTest.java
@@ -530,6 +530,15 @@
responseObserver.onCompleted();
}
});
+ serviceRegistry.addService(
+ new ActionCacheImplBase() {
+ @Override
+ public void updateActionResult(
+ UpdateActionResultRequest request, StreamObserver<ActionResult> responseObserver) {
+ responseObserver.onNext(request.getActionResult());
+ responseObserver.onCompleted();
+ }
+ });
ActionResult result = uploadDirectory(client, ImmutableList.<Path>of(fooFile, barDir));
ActionResult.Builder expectedResult = ActionResult.newBuilder();
@@ -558,6 +567,15 @@
responseObserver.onCompleted();
}
});
+ serviceRegistry.addService(
+ new ActionCacheImplBase() {
+ @Override
+ public void updateActionResult(
+ UpdateActionResultRequest request, StreamObserver<ActionResult> responseObserver) {
+ responseObserver.onNext(request.getActionResult());
+ responseObserver.onCompleted();
+ }
+ });
ActionResult result = uploadDirectory(client, ImmutableList.<Path>of(barDir));
ActionResult.Builder expectedResult = ActionResult.newBuilder();
@@ -608,6 +626,15 @@
responseObserver.onCompleted();
}
});
+ serviceRegistry.addService(
+ new ActionCacheImplBase() {
+ @Override
+ public void updateActionResult(
+ UpdateActionResultRequest request, StreamObserver<ActionResult> responseObserver) {
+ responseObserver.onNext(request.getActionResult());
+ responseObserver.onCompleted();
+ }
+ });
ActionResult result = uploadDirectory(client, ImmutableList.of(barDir));
ActionResult.Builder expectedResult = ActionResult.newBuilder();
@@ -617,12 +644,10 @@
private ActionResult uploadDirectory(GrpcRemoteCache client, List<Path> outputs)
throws Exception {
- ActionResult.Builder result = ActionResult.newBuilder();
Action action = Action.getDefaultInstance();
ActionKey actionKey = DIGEST_UTIL.computeActionKey(action);
Command cmd = Command.getDefaultInstance();
- client.upload(execRoot, actionKey, action, cmd, outputs, outErr, result);
- return result.build();
+ return client.upload(actionKey, action, cmd, execRoot, outputs, outErr);
}
@Test
@@ -662,16 +687,24 @@
responseObserver.onCompleted();
}
});
+ serviceRegistry.addService(
+ new ActionCacheImplBase() {
+ @Override
+ public void updateActionResult(
+ UpdateActionResultRequest request, StreamObserver<ActionResult> responseObserver) {
+ responseObserver.onNext(request.getActionResult());
+ responseObserver.onCompleted();
+ }
+ });
- ActionResult.Builder result = ActionResult.newBuilder();
- client.upload(
- execRoot,
- DIGEST_UTIL.asActionKey(actionDigest),
- action,
- command,
- ImmutableList.<Path>of(fooFile, barFile),
- outErr,
- result);
+ ActionResult result =
+ client.upload(
+ DIGEST_UTIL.asActionKey(actionDigest),
+ action,
+ command,
+ execRoot,
+ ImmutableList.of(fooFile, barFile),
+ outErr);
ActionResult.Builder expectedResult = ActionResult.newBuilder();
expectedResult.setStdoutDigest(stdoutDigest);
expectedResult.setStderrDigest(stderrDigest);
@@ -681,7 +714,7 @@
.setPath("bar")
.setDigest(barDigest)
.setIsExecutable(true);
- assertThat(result.build()).isEqualTo(expectedResult.build());
+ assertThat(result).isEqualTo(expectedResult.build());
}
@Test
@@ -711,19 +744,27 @@
responseObserver.onCompleted();
}
});
+ serviceRegistry.addService(
+ new ActionCacheImplBase() {
+ @Override
+ public void updateActionResult(
+ UpdateActionResultRequest request, StreamObserver<ActionResult> responseObserver) {
+ responseObserver.onNext(request.getActionResult());
+ responseObserver.onCompleted();
+ }
+ });
RemoteOptions options = Options.getDefaults(RemoteOptions.class);
options.maxOutboundMessageSize = 80; // Enough for one digest, but not two.
final GrpcRemoteCache client = newClient(options);
- ActionResult.Builder result = ActionResult.newBuilder();
- client.upload(
- execRoot,
- DIGEST_UTIL.asActionKey(actionDigest),
- action,
- command,
- ImmutableList.<Path>of(fooFile, barFile),
- outErr,
- result);
+ ActionResult result =
+ client.upload(
+ DIGEST_UTIL.asActionKey(actionDigest),
+ action,
+ command,
+ execRoot,
+ ImmutableList.of(fooFile, barFile),
+ outErr);
ActionResult.Builder expectedResult = ActionResult.newBuilder();
expectedResult.addOutputFilesBuilder().setPath("a/foo").setDigest(fooDigest);
expectedResult
@@ -731,7 +772,7 @@
.setPath("bar")
.setDigest(barDigest)
.setIsExecutable(true);
- assertThat(result.build()).isEqualTo(expectedResult.build());
+ assertThat(result).isEqualTo(expectedResult.build());
assertThat(numGetMissingCalls.get()).isEqualTo(4);
}
diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteActionInputFetcherTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteActionInputFetcherTest.java
index 24ad516..6c5fe6d 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/RemoteActionInputFetcherTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteActionInputFetcherTest.java
@@ -16,12 +16,11 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
-import build.bazel.remote.execution.v2.Action;
import build.bazel.remote.execution.v2.ActionResult;
-import build.bazel.remote.execution.v2.Command;
import build.bazel.remote.execution.v2.Digest;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.hash.HashCode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@@ -39,7 +38,6 @@
import com.google.devtools.build.lib.remote.util.DigestUtil;
import com.google.devtools.build.lib.remote.util.StaticMetadataProvider;
import com.google.devtools.build.lib.remote.util.StringActionInput;
-import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.DigestHashFunction;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -52,7 +50,6 @@
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
-import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
@@ -232,13 +229,7 @@
}
@Override
- void upload(
- ActionKey actionKey,
- Action action,
- Command command,
- Path execRoot,
- Collection<Path> files,
- FileOutErr outErr) {
+ protected void setCachedActionResult(ActionKey actionKey, ActionResult action) {
throw new UnsupportedOperationException();
}
@@ -253,6 +244,11 @@
}
@Override
+ protected ImmutableSet<Digest> getMissingDigests(Iterable<Digest> digests) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
protected ListenableFuture<Void> downloadBlob(Digest digest, OutputStream out) {
ByteString data = cacheEntries.get(digest);
if (data == null) {
diff --git a/src/test/java/com/google/devtools/build/lib/remote/SimpleBlobStoreActionCacheTest.java b/src/test/java/com/google/devtools/build/lib/remote/SimpleBlobStoreActionCacheTest.java
index 271dc69..4071de4 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/SimpleBlobStoreActionCacheTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/SimpleBlobStoreActionCacheTest.java
@@ -37,6 +37,7 @@
import com.google.devtools.build.lib.remote.options.RemoteOptions;
import com.google.devtools.build.lib.remote.util.DigestUtil;
import com.google.devtools.build.lib.remote.util.TracingMetadataUtils;
+import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.DigestHashFunction;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -315,22 +316,21 @@
final ConcurrentMap<String, byte[]> map = new ConcurrentHashMap<>();
final SimpleBlobStoreActionCache client = newClient(map);
- ActionResult.Builder result = ActionResult.newBuilder();
- client.upload(
- result,
- DIGEST_UTIL.asActionKey(actionDigest),
- action,
- cmd,
- execRoot,
- ImmutableList.<Path>of(fooFile, barDir),
- /* uploadAction= */ true);
+ ActionResult result =
+ client.upload(
+ DIGEST_UTIL.asActionKey(actionDigest),
+ action,
+ cmd,
+ execRoot,
+ ImmutableList.of(fooFile, barDir),
+ new FileOutErr(execRoot.getRelative("stdout"), execRoot.getRelative("stderr")));
ActionResult.Builder expectedResult = ActionResult.newBuilder();
expectedResult.addOutputFilesBuilder().setPath("a/foo").setDigest(fooDigest);
expectedResult.addOutputDirectoriesBuilder().setPath("bar").setTreeDigest(barDigest);
- assertThat(result.build()).isEqualTo(expectedResult.build());
+ assertThat(result).isEqualTo(expectedResult.build());
assertThat(map.keySet())
- .containsExactly(
+ .containsAtLeast(
fooDigest.getHash(),
quxDigest.getHash(),
barDigest.getHash(),
@@ -402,12 +402,16 @@
private ActionResult uploadDirectory(SimpleBlobStoreActionCache client, List<Path> outputs)
throws Exception {
- ActionResult.Builder result = ActionResult.newBuilder();
Action action = Action.getDefaultInstance();
ActionKey actionKey = DIGEST_UTIL.computeActionKey(action);
Command cmd = Command.getDefaultInstance();
- client.upload(result, actionKey, action, cmd, execRoot, outputs, /* uploadAction= */ true);
- return result.build();
+ return client.upload(
+ actionKey,
+ action,
+ cmd,
+ execRoot,
+ outputs,
+ new FileOutErr(execRoot.getRelative("stdout"), execRoot.getRelative("stderr")));
}
@Test
diff --git a/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/BUILD b/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/BUILD
index 4c6659f..e9dc09d 100644
--- a/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/BUILD
+++ b/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/BUILD
@@ -16,6 +16,7 @@
visibility = ["//src/tools/remote:__subpackages__"],
deps = [
"//src/main/java/com/google/devtools/build/lib:build-base",
+ "//src/main/java/com/google/devtools/build/lib:io",
"//src/main/java/com/google/devtools/build/lib:os_util",
"//src/main/java/com/google/devtools/build/lib:packages-internal",
"//src/main/java/com/google/devtools/build/lib:process_util",
diff --git a/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/ExecutionServer.java b/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/ExecutionServer.java
index abc3e6f..925c944 100644
--- a/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/ExecutionServer.java
+++ b/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/ExecutionServer.java
@@ -47,11 +47,11 @@
import com.google.devtools.build.lib.shell.CommandException;
import com.google.devtools.build.lib.shell.CommandResult;
import com.google.devtools.build.lib.shell.FutureCommandResult;
+import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.longrunning.Operation;
import com.google.protobuf.Any;
-import com.google.protobuf.ByteString;
import com.google.protobuf.util.Durations;
import com.google.rpc.Code;
import com.google.rpc.Status;
@@ -284,84 +284,80 @@
long startTime = System.currentTimeMillis();
CommandResult cmdResult = null;
- FutureCommandResult futureCmdResult = null;
- try {
- futureCmdResult = cmd.executeAsync();
- } catch (CommandException e) {
- Throwables.throwIfInstanceOf(e.getCause(), IOException.class);
- }
+ String uuid = UUID.randomUUID().toString();
+ Path stdout = execRoot.getChild("stdout-" + uuid);
+ Path stderr = execRoot.getChild("stderr-" + uuid);
+ try (FileOutErr outErr = new FileOutErr(stdout, stderr)) {
- if (futureCmdResult != null) {
+ FutureCommandResult futureCmdResult = null;
try {
- cmdResult = futureCmdResult.get();
- } catch (AbnormalTerminationException e) {
- cmdResult = e.getResult();
+ futureCmdResult = cmd.executeAsync(outErr.getOutputStream(), outErr.getErrorStream());
+ } catch (CommandException e) {
+ Throwables.throwIfInstanceOf(e.getCause(), IOException.class);
}
- }
- long timeoutMillis =
- action.hasTimeout()
- ? Durations.toMillis(action.getTimeout())
- : TimeUnit.MINUTES.toMillis(15);
- boolean wasTimeout =
- (cmdResult != null && cmdResult.getTerminationStatus().timedOut())
- || wasTimeout(timeoutMillis, System.currentTimeMillis() - startTime);
- final int exitCode;
- Status errStatus = null;
- ExecuteResponse.Builder resp = ExecuteResponse.newBuilder();
- if (wasTimeout) {
- final String errMessage =
- String.format(
- "Command:\n%s\nexceeded deadline of %f seconds.",
- Arrays.toString(command.getArgumentsList().toArray()), timeoutMillis / 1000.0);
- logger.warning(errMessage);
- errStatus =
- Status.newBuilder()
- .setCode(Code.DEADLINE_EXCEEDED.getNumber())
- .setMessage(errMessage)
- .build();
- exitCode = LOCAL_EXEC_ERROR;
- } else if (cmdResult == null) {
- exitCode = LOCAL_EXEC_ERROR;
- } else {
- exitCode = cmdResult.getTerminationStatus().getRawExitCode();
- }
+ if (futureCmdResult != null) {
+ try {
+ cmdResult = futureCmdResult.get();
+ } catch (AbnormalTerminationException e) {
+ cmdResult = e.getResult();
+ }
+ }
- ActionResult.Builder result = ActionResult.newBuilder();
- boolean setResult = exitCode == 0 && !action.getDoNotCache();
- try {
- cache.upload(result, actionKey, action, command, execRoot, outputs, setResult);
- } catch (ExecException e) {
- if (errStatus == null) {
+ long timeoutMillis =
+ action.hasTimeout()
+ ? Durations.toMillis(action.getTimeout())
+ : TimeUnit.MINUTES.toMillis(15);
+ boolean wasTimeout =
+ (cmdResult != null && cmdResult.getTerminationStatus().timedOut())
+ || wasTimeout(timeoutMillis, System.currentTimeMillis() - startTime);
+ final int exitCode;
+ Status errStatus = null;
+ ExecuteResponse.Builder resp = ExecuteResponse.newBuilder();
+ if (wasTimeout) {
+ final String errMessage =
+ String.format(
+ "Command:\n%s\nexceeded deadline of %f seconds.",
+ Arrays.toString(command.getArgumentsList().toArray()), timeoutMillis / 1000.0);
+ logger.warning(errMessage);
errStatus =
Status.newBuilder()
- .setCode(Code.FAILED_PRECONDITION.getNumber())
- .setMessage(e.getMessage())
+ .setCode(Code.DEADLINE_EXCEEDED.getNumber())
+ .setMessage(errMessage)
.build();
+ exitCode = LOCAL_EXEC_ERROR;
+ } else if (cmdResult == null) {
+ exitCode = LOCAL_EXEC_ERROR;
+ } else {
+ exitCode = cmdResult.getTerminationStatus().getRawExitCode();
}
- }
- byte[] stdout = cmdResult.getStdout();
- if (stdout.length > 0) {
- Digest stdoutDigest = digestUtil.compute(stdout);
- getFromFuture(cache.uploadBlob(stdoutDigest, ByteString.copyFrom(stdout)));
- result.setStdoutDigest(stdoutDigest);
- }
- byte[] stderr = cmdResult.getStderr();
- if (stderr.length > 0) {
- Digest stderrDigest = digestUtil.compute(stderr);
- getFromFuture(cache.uploadBlob(stderrDigest, ByteString.copyFrom(stderr)));
- result.setStderrDigest(stderrDigest);
- }
- ActionResult finalResult = result.setExitCode(exitCode).build();
- resp.setResult(finalResult);
- if (errStatus != null) {
- resp.setStatus(errStatus);
- throw new ExecutionStatusException(errStatus, resp.build());
- } else if (setResult) {
- cache.setCachedActionResult(actionKey, finalResult);
+ ActionResult result = null;
+ try {
+ result = cache.upload(actionKey, action, command, execRoot, outputs, outErr, exitCode);
+ } catch (ExecException e) {
+ if (errStatus == null) {
+ errStatus =
+ Status.newBuilder()
+ .setCode(Code.FAILED_PRECONDITION.getNumber())
+ .setMessage(e.getMessage())
+ .build();
+ }
+ }
+
+ if (result == null) {
+ result = ActionResult.newBuilder().setExitCode(exitCode).build();
+ }
+
+ resp.setResult(result);
+
+ if (errStatus != null) {
+ resp.setStatus(errStatus);
+ throw new ExecutionStatusException(errStatus, resp.build());
+ }
+
+ return result;
}
- return finalResult;
}
// Returns true if the OS being run on is Windows (or some close approximation thereof).