Revert "[7.3.0] Deduplicate locally executed path mapped spawns (#230… (#23290)
…69)"
This reverts commit ffe1df57c3ccbbff815df0068634b881da8c1501.
Causes race conditions, see #23288 for details.
Fixes https://github.com/bazelbuild/bazel/issues/23289
diff --git a/src/main/java/com/google/devtools/build/lib/actions/SpawnResult.java b/src/main/java/com/google/devtools/build/lib/actions/SpawnResult.java
index 95633d1..60c14b8 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/SpawnResult.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/SpawnResult.java
@@ -488,149 +488,6 @@
}
}
- /**
- * A helper class for wrapping an existing {@link SpawnResult} and modifying a subset of its
- * methods.
- */
- class DelegateSpawnResult implements SpawnResult {
- private final SpawnResult delegate;
-
- public DelegateSpawnResult(SpawnResult delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public boolean setupSuccess() {
- return delegate.setupSuccess();
- }
-
- @Override
- public boolean isCatastrophe() {
- return delegate.isCatastrophe();
- }
-
- @Override
- public Status status() {
- return delegate.status();
- }
-
- @Override
- public int exitCode() {
- return delegate.exitCode();
- }
-
- @Override
- @Nullable
- public FailureDetail failureDetail() {
- return delegate.failureDetail();
- }
-
- @Override
- @Nullable
- public String getExecutorHostName() {
- return delegate.getExecutorHostName();
- }
-
- @Override
- public String getRunnerName() {
- return delegate.getRunnerName();
- }
-
- @Override
- public String getRunnerSubtype() {
- return delegate.getRunnerSubtype();
- }
-
- @Override
- @Nullable
- public Instant getStartTime() {
- return delegate.getStartTime();
- }
-
- @Override
- public int getWallTimeInMs() {
- return delegate.getWallTimeInMs();
- }
-
- @Override
- public int getUserTimeInMs() {
- return delegate.getUserTimeInMs();
- }
-
- @Override
- public int getSystemTimeInMs() {
- return delegate.getSystemTimeInMs();
- }
-
- @Override
- @Nullable
- public Long getNumBlockOutputOperations() {
- return delegate.getNumBlockOutputOperations();
- }
-
- @Override
- @Nullable
- public Long getNumBlockInputOperations() {
- return delegate.getNumBlockInputOperations();
- }
-
- @Override
- @Nullable
- public Long getNumInvoluntaryContextSwitches() {
- return delegate.getNumInvoluntaryContextSwitches();
- }
-
- @Override
- @Nullable
- public Long getMemoryInKb() {
- return delegate.getMemoryInKb();
- }
-
- @Override
- public SpawnMetrics getMetrics() {
- return delegate.getMetrics();
- }
-
- @Override
- public boolean isCacheHit() {
- return delegate.isCacheHit();
- }
-
- @Override
- public String getFailureMessage() {
- return delegate.getFailureMessage();
- }
-
- @Override
- @Nullable
- public InputStream getInMemoryOutput(ActionInput output) {
- return delegate.getInMemoryOutput(output);
- }
-
- @Override
- public String getDetailMessage(
- String message, boolean catastrophe, boolean forciblyRunRemotely) {
- return delegate.getDetailMessage(message, catastrophe, forciblyRunRemotely);
- }
-
- @Override
- @Nullable
- public MetadataLog getActionMetadataLog() {
- return delegate.getActionMetadataLog();
- }
-
- @Override
- public boolean wasRemote() {
- return delegate.wasRemote();
- }
-
- @Override
- @Nullable
- public Digest getDigest() {
- return delegate.getDigest();
- }
- }
-
/** Builder class for {@link SpawnResult}. */
final class Builder {
private int exitCode;
diff --git a/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java
index 8e1a1aa..05bf139 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java
@@ -221,7 +221,7 @@
? resultMessage
: CommandFailureUtils.describeCommandFailure(
executionOptions.verboseFailures, cwd, spawn);
- throw new SpawnExecException(message, spawnResult, /* forciblyRunRemotely= */ false);
+ throw new SpawnExecException(message, spawnResult, /*forciblyRunRemotely=*/ false);
}
return ImmutableList.of(spawnResult);
}
diff --git a/src/main/java/com/google/devtools/build/lib/exec/BUILD b/src/main/java/com/google/devtools/build/lib/exec/BUILD
index ef276bd..37870bd 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/exec/BUILD
@@ -225,7 +225,6 @@
deps = [
":spawn_runner",
"//src/main/java/com/google/devtools/build/lib/actions",
- "//src/main/java/com/google/devtools/build/lib/profiler",
],
)
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SpawnCache.java b/src/main/java/com/google/devtools/build/lib/exec/SpawnCache.java
index 694e079..9b46802 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SpawnCache.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SpawnCache.java
@@ -18,7 +18,6 @@
import com.google.devtools.build.lib.actions.ForbiddenActionInputException;
import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.actions.SpawnResult;
-import com.google.devtools.build.lib.actions.Spawns;
import com.google.devtools.build.lib.exec.SpawnRunner.SpawnExecutionContext;
import java.io.Closeable;
import java.io.IOException;
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java
index 893132e..31d7897 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java
@@ -17,7 +17,6 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.isNullOrEmpty;
-import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
import static com.google.common.util.concurrent.Futures.immediateFuture;
import static com.google.common.util.concurrent.Futures.transform;
@@ -63,7 +62,6 @@
import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ArtifactPathResolver;
@@ -130,7 +128,6 @@
import io.reactivex.rxjava3.core.SingleObserver;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
@@ -146,11 +143,9 @@
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.TreeSet;
-import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Phaser;
import java.util.concurrent.Semaphore;
@@ -868,12 +863,15 @@
}
}
- /** Moves the locally created outputs from their temporary location to their declared location. */
+ /**
+ * Copies moves the downloaded outputs from their download location to their declared location.
+ */
private void moveOutputsToFinalLocation(
- Iterable<Path> localOutputs, Map<Path, Path> realToTmpPath) throws IOException {
+ List<FileMetadata> finishedDownloads, Map<Path, Path> realToTmpPath) throws IOException {
// Move the output files from their temporary name to the actual output file name. Executable
// bit is ignored since the file permission will be changed to 0555 after execution.
- for (Path realPath : localOutputs) {
+ for (FileMetadata outputFile : finishedDownloads) {
+ Path realPath = outputFile.path();
Path tmpPath = Preconditions.checkNotNull(realToTmpPath.get(realPath));
realPath.getParentDirectory().createDirectoryAndParents();
FileSystemUtils.moveFile(tmpPath, realPath);
@@ -1272,8 +1270,7 @@
// TODO(chiwang): Stage directories directly
((BazelOutputService) outputService).stageArtifacts(finishedDownloads);
} else {
- moveOutputsToFinalLocation(
- Iterables.transform(finishedDownloads, FileMetadata::path), realToTmpPath);
+ moveOutputsToFinalLocation(finishedDownloads, realToTmpPath);
}
List<SymlinkMetadata> symlinksInDirectories = new ArrayList<>();
@@ -1330,152 +1327,6 @@
return null;
}
- /** An ongoing local execution of a spawn. */
- public static final class LocalExecution {
- private final RemoteAction action;
- private final SettableFuture<SpawnResult> spawnResultFuture;
-
- private LocalExecution(RemoteAction action) {
- this.action = action;
- this.spawnResultFuture = SettableFuture.create();
- }
-
- /**
- * Creates a new {@link LocalExecution} instance tracking the potential local execution of the
- * given {@link RemoteAction} if there is a chance that the same action will be executed by a
- * different Spawn.
- *
- * <p>This is only done for local (as in, non-remote) execution as remote executors are expected
- * to already have deduplication mechanisms for actions in place, perhaps even across different
- * builds and clients.
- */
- @Nullable
- public static LocalExecution createIfDeduplicatable(RemoteAction action) {
- if (action.getSpawn().getPathMapper().isNoop()) {
- return null;
- }
- return new LocalExecution(action);
- }
-
- /**
- * Signals to all potential consumers of the {@link #spawnResultFuture} that this execution has
- * been cancelled and that the result will not be available.
- */
- public void cancel() {
- spawnResultFuture.cancel(true);
- }
- }
-
- /**
- * Makes the {@link SpawnResult} available to all parallel {@link Spawn}s for the same {@link
- * RemoteAction} waiting for it or notifies them that the spawn failed.
- *
- * @return Whether the spawn result should be uploaded to the cache.
- */
- public boolean commitResultAndDecideWhetherToUpload(
- SpawnResult result, @Nullable LocalExecution execution) {
- if (result.status().equals(SpawnResult.Status.SUCCESS) && result.exitCode() == 0) {
- if (execution != null) {
- execution.spawnResultFuture.set(result);
- }
- return true;
- } else {
- if (execution != null) {
- execution.spawnResultFuture.cancel(true);
- }
- return false;
- }
- }
-
- /**
- * Reuses the outputs of a concurrent local execution of the same RemoteAction in a different
- * spawn.
- *
- * <p>Since each output file is generated by a unique action and actions generally take care to
- * run a unique spawn for each output file, this method is only useful with path mapping enabled,
- * which allows different spawns in a single build to have the same RemoteAction.ActionKey.
- *
- * @return The {@link SpawnResult} of the previous execution if it was successful, otherwise null.
- */
- @Nullable
- public SpawnResult waitForAndReuseOutputs(RemoteAction action, LocalExecution previousExecution)
- throws InterruptedException, IOException {
- checkState(!shutdown.get(), "shutdown");
-
- SpawnResult previousSpawnResult;
- try {
- previousSpawnResult = previousExecution.spawnResultFuture.get();
- } catch (CancellationException | ExecutionException e) {
- if (e.getCause() != null) {
- Throwables.throwIfInstanceOf(e.getCause(), InterruptedException.class);
- Throwables.throwIfUnchecked(e.getCause());
- }
- // The spawn this action was deduplicated against failed due to an exception or
- // non-zero exit code. Since it isn't possible to transparently replay its failure for the
- // current spawn, we rerun the action instead.
- return null;
- }
-
- Preconditions.checkArgument(
- action.getActionKey().equals(previousExecution.action.getActionKey()));
-
- ImmutableMap<Path, ActionInput> previousOutputs =
- previousExecution.action.getSpawn().getOutputFiles().stream()
- .collect(toImmutableMap(output -> execRoot.getRelative(output.getExecPath()), o -> o));
- Map<Path, Path> realToTmpPath = new HashMap<>();
- for (String output : action.getCommand().getOutputPathsList()) {
- Path sourcePath =
- previousExecution
- .action
- .getRemotePathResolver()
- .outputPathToLocalPath(encodeBytestringUtf8(output));
- ActionInput outputArtifact = previousOutputs.get(sourcePath);
- Path tmpPath = tempPathGenerator.generateTempPath();
- tmpPath.getParentDirectory().createDirectoryAndParents();
- try {
- if (outputArtifact.isDirectory()) {
- tmpPath.createDirectory();
- FileSystemUtils.copyTreesBelow(sourcePath, tmpPath, Symlinks.NOFOLLOW);
- } else if (outputArtifact.isSymlink()) {
- FileSystemUtils.ensureSymbolicLink(tmpPath, sourcePath.readSymbolicLink());
- } else {
- FileSystemUtils.copyFile(sourcePath, tmpPath);
- }
- } catch (FileNotFoundException e) {
- // The spawn this action was deduplicated against failed to create an output file. If the
- // output is mandatory, we cannot reuse the previous execution.
- if (action.getSpawn().isMandatoryOutput(outputArtifact)) {
- return null;
- }
- }
-
- Path targetPath =
- action.getRemotePathResolver().outputPathToLocalPath(encodeBytestringUtf8(output));
- realToTmpPath.put(targetPath, tmpPath);
- }
-
- // TODO: FileOutErr is action-scoped, not spawn-scoped, but this is not a problem for the
- // current use case of supporting deduplication of path mapped spawns:
- // 1. Starlark and C++ compilation actions always create a single spawn.
- // 2. Java compilation actions may run a fallback spawn, but reset the FileOutErr before
- // running it.
- // If this changes, we will need to introduce a spawn-scoped OutErr.
- FileOutErr.dump(
- previousExecution.action.getSpawnExecutionContext().getFileOutErr(),
- action.getSpawnExecutionContext().getFileOutErr());
-
- action
- .getSpawnExecutionContext()
- .lockOutputFiles(
- previousSpawnResult.exitCode(),
- previousSpawnResult.getFailureMessage(),
- action.getSpawnExecutionContext().getFileOutErr());
- // All outputs are created locally.
- moveOutputsToFinalLocation(realToTmpPath.keySet(), realToTmpPath);
-
- return previousSpawnResult;
- }
-
private boolean shouldDownload(RemoteActionResult result, PathFragment execPath) {
if (outputService instanceof BazelOutputService) {
return false;
@@ -1550,7 +1401,7 @@
}
/** Upload outputs of a remote action which was executed locally to remote cache. */
- public void uploadOutputs(RemoteAction action, SpawnResult spawnResult, Runnable onUploadComplete)
+ public void uploadOutputs(RemoteAction action, SpawnResult spawnResult)
throws InterruptedException, ExecException {
checkState(!shutdown.get(), "shutdown");
checkState(
@@ -1586,7 +1437,6 @@
Profiler.instance()
.completeTask(startTime, ProfilerTask.UPLOAD_TIME, "upload outputs");
backgroundTaskPhaser.arriveAndDeregister();
- onUploadComplete.run();
}
@Override
@@ -1595,7 +1445,6 @@
.completeTask(startTime, ProfilerTask.UPLOAD_TIME, "upload outputs");
backgroundTaskPhaser.arriveAndDeregister();
reportUploadError(e);
- onUploadComplete.run();
}
});
} else {
@@ -1605,8 +1454,6 @@
manifest.upload(action.getRemoteActionExecutionContext(), remoteCache, reporter);
} catch (IOException e) {
reportUploadError(e);
- } finally {
- onUploadComplete.run();
}
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
index 3224f56..ad0c51c 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnCache.java
@@ -26,6 +26,7 @@
import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.actions.SpawnMetrics;
import com.google.devtools.build.lib.actions.SpawnResult;
+import com.google.devtools.build.lib.actions.SpawnResult.Status;
import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.events.Event;
@@ -34,11 +35,9 @@
import com.google.devtools.build.lib.profiler.Profiler;
import com.google.devtools.build.lib.profiler.ProfilerTask;
import com.google.devtools.build.lib.profiler.SilentCloseable;
-import com.google.devtools.build.lib.remote.RemoteExecutionService.LocalExecution;
import com.google.devtools.build.lib.remote.RemoteExecutionService.RemoteActionResult;
import com.google.devtools.build.lib.remote.common.BulkTransferException;
import com.google.devtools.build.lib.remote.common.CacheNotFoundException;
-import com.google.devtools.build.lib.remote.common.RemoteCacheClient;
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;
@@ -46,7 +45,6 @@
import com.google.devtools.build.lib.vfs.Path;
import java.io.IOException;
import java.util.NoSuchElementException;
-import java.util.concurrent.ConcurrentHashMap;
/** A remote {@link SpawnCache} implementation. */
@ThreadSafe // If the RemoteActionCache implementation is thread-safe.
@@ -57,8 +55,6 @@
private final RemoteExecutionService remoteExecutionService;
private final DigestUtil digestUtil;
private final boolean verboseFailures;
- private final ConcurrentHashMap<RemoteCacheClient.ActionKey, LocalExecution> inFlightExecutions =
- new ConcurrentHashMap<>();
RemoteSpawnCache(
Path execRoot,
@@ -100,19 +96,7 @@
context.setDigest(digestUtil.asSpawnLogProto(action.getActionKey()));
Profiler prof = Profiler.instance();
- LocalExecution thisExecution = null;
if (shouldAcceptCachedResult) {
- // With path mapping enabled, different Spawns in a single build can have the same ActionKey.
- // When their result isn't in the cache and two of them are scheduled concurrently, neither
- // will result in a cache hit before the other finishes and uploads its result, which results
- // in unnecessary work. To avoid this, we keep track of in-flight executions as long as their
- // results haven't been uploaded to the cache yet and deduplicate all of them against the
- // first one.
- LocalExecution previousExecution = null;
- thisExecution = LocalExecution.createIfDeduplicatable(action);
- if (shouldUploadLocalResults && thisExecution != null) {
- previousExecution = inFlightExecutions.putIfAbsent(action.getActionKey(), thisExecution);
- }
// Metadata will be available in context.current() until we detach.
// This is done via a thread-local variable.
try {
@@ -162,41 +146,9 @@
remoteExecutionService.report(Event.warn(errorMessage));
}
}
- if (previousExecution != null) {
- Stopwatch fetchTime = Stopwatch.createStarted();
- SpawnResult previousResult;
- try (SilentCloseable c = prof.profile(REMOTE_DOWNLOAD, "reuse outputs")) {
- previousResult = remoteExecutionService.waitForAndReuseOutputs(action, previousExecution);
- }
- if (previousResult != null) {
- spawnMetrics
- .setFetchTimeInMs((int) fetchTime.elapsed().toMillis())
- .setTotalTimeInMs((int) totalTime.elapsed().toMillis())
- .setNetworkTimeInMs((int) action.getNetworkTime().getDuration().toMillis());
- SpawnMetrics buildMetrics = spawnMetrics.build();
- return SpawnCache.success(
- new SpawnResult.DelegateSpawnResult(previousResult) {
- @Override
- public String getRunnerName() {
- return "deduplicated";
- }
-
- @Override
- public SpawnMetrics getMetrics() {
- return buildMetrics;
- }
- });
- }
- // If we reach here, the previous execution was not successful (it encountered an exception
- // or the spawn had an exit code != 0). Since it isn't possible to accurately recreate the
- // failure without rerunning the action, we fall back to running the action locally. This
- // means that we have introduced an unnecessary wait, but that can only happen in the case
- // of a failing build with --keep_going.
- }
}
if (shouldUploadLocalResults) {
- final LocalExecution thisExecutionFinal = thisExecution;
return new CacheHandle() {
@Override
public boolean hasResult() {
@@ -215,8 +167,8 @@
@Override
public void store(SpawnResult result) throws ExecException, InterruptedException {
- if (!remoteExecutionService.commitResultAndDecideWhetherToUpload(
- result, thisExecutionFinal)) {
+ boolean uploadResults = Status.SUCCESS.equals(result.status()) && result.exitCode() == 0;
+ if (!uploadResults) {
return;
}
@@ -233,14 +185,12 @@
}
}
- // As soon as the result is in the cache, actions can get the result from it instead of
- // from the first in-flight execution. Not keeping in-flight executions around
- // indefinitely is important to avoid excessive memory pressure - Spawns can be very
- // large.
- remoteExecutionService.uploadOutputs(
- action, result, () -> inFlightExecutions.remove(action.getActionKey()));
+ remoteExecutionService.uploadOutputs(action, result);
}
+ @Override
+ public void close() {}
+
private void checkForConcurrentModifications()
throws IOException, ForbiddenActionInputException {
for (ActionInput input : action.getInputMap(true).values()) {
@@ -254,13 +204,6 @@
}
}
}
-
- @Override
- public void close() {
- if (thisExecutionFinal != null) {
- thisExecutionFinal.cancel();
- }
- }
};
} else {
return SpawnCache.NO_RESULT_NO_STORE;
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
index f5fa69f..934cdff 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteSpawnRunner.java
@@ -695,7 +695,7 @@
}
}
- remoteExecutionService.uploadOutputs(action, result, () -> {});
+ remoteExecutionService.uploadOutputs(action, result);
return result;
}
diff --git a/src/main/java/com/google/devtools/build/lib/remote/common/RemotePathResolver.java b/src/main/java/com/google/devtools/build/lib/remote/common/RemotePathResolver.java
index 5819cc3a..3a2c708 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/common/RemotePathResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/common/RemotePathResolver.java
@@ -17,6 +17,7 @@
import com.google.common.base.Preconditions;
import com.google.devtools.build.lib.actions.ActionInput;
+import com.google.devtools.build.lib.actions.ActionInputHelper;
import com.google.devtools.build.lib.actions.ForbiddenActionInputException;
import com.google.devtools.build.lib.actions.PathMapper;
import com.google.devtools.build.lib.actions.Spawn;
@@ -75,6 +76,12 @@
*/
Path outputPathToLocalPath(String outputPath);
+ /** Resolves the local {@link Path} for the {@link ActionInput}. */
+ default Path outputPathToLocalPath(ActionInput actionInput) {
+ String outputPath = localPathToOutputPath(actionInput.getExecPath());
+ return outputPathToLocalPath(outputPath);
+ }
+
/** Creates the default {@link RemotePathResolver}. */
static RemotePathResolver createDefault(Path execRoot) {
return new DefaultRemotePathResolver(execRoot);
@@ -132,6 +139,11 @@
public Path outputPathToLocalPath(String outputPath) {
return execRoot.getRelative(outputPath);
}
+
+ @Override
+ public Path outputPathToLocalPath(ActionInput actionInput) {
+ return ActionInputHelper.toInputPath(actionInput, execRoot);
+ }
}
/**
@@ -212,6 +224,10 @@
return getBase().getRelative(outputPath);
}
+ @Override
+ public Path outputPathToLocalPath(ActionInput actionInput) {
+ return ActionInputHelper.toInputPath(actionInput, execRoot);
+ }
}
/**
diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java
index 4a46e6d..653e207 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java
@@ -1646,7 +1646,7 @@
// act
UploadManifest manifest = service.buildUploadManifest(action, spawnResult);
- service.uploadOutputs(action, spawnResult, () -> {});
+ service.uploadOutputs(action, spawnResult);
// assert
ActionResult.Builder expectedResult = ActionResult.newBuilder();
@@ -1693,7 +1693,7 @@
// act
UploadManifest manifest = service.buildUploadManifest(action, spawnResult);
- service.uploadOutputs(action, spawnResult, () -> {});
+ service.uploadOutputs(action, spawnResult);
// assert
ActionResult.Builder expectedResult = ActionResult.newBuilder();
@@ -1767,7 +1767,7 @@
// act
UploadManifest manifest = service.buildUploadManifest(action, spawnResult);
- service.uploadOutputs(action, spawnResult, () -> {});
+ service.uploadOutputs(action, spawnResult);
// assert
ActionResult.Builder expectedResult = ActionResult.newBuilder();
@@ -1803,7 +1803,7 @@
// act
UploadManifest manifest = service.buildUploadManifest(action, spawnResult);
- service.uploadOutputs(action, spawnResult, () -> {});
+ service.uploadOutputs(action, spawnResult);
// assert
ActionResult.Builder expectedResult = ActionResult.newBuilder();
@@ -1855,7 +1855,7 @@
.build();
// act
- service.uploadOutputs(action, spawnResult, () -> {});
+ service.uploadOutputs(action, spawnResult);
// assert
assertThat(
@@ -1881,7 +1881,7 @@
.when(cache)
.uploadActionResult(any(), any(), any());
- service.uploadOutputs(action, spawnResult, () -> {});
+ service.uploadOutputs(action, spawnResult);
assertThat(eventHandler.getEvents()).hasSize(1);
Event evt = eventHandler.getEvents().get(0);
@@ -1906,7 +1906,7 @@
.setRunnerName("test")
.build();
- service.uploadOutputs(action, spawnResult, () -> {});
+ service.uploadOutputs(action, spawnResult);
assertThat(eventHandler.getPosts())
.containsAtLeast(
@@ -1933,7 +1933,7 @@
.setRunnerName("test")
.build();
- service.uploadOutputs(action, spawnResult, () -> {});
+ service.uploadOutputs(action, spawnResult);
// assert
assertThat(cache.getNumFindMissingDigests()).isEmpty();
diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnCacheTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnCacheTest.java
index 057ea41..5f89e19 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnCacheTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnCacheTest.java
@@ -18,7 +18,6 @@
import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat;
import static com.google.common.util.concurrent.Futures.immediateVoidFuture;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-import static java.nio.charset.StandardCharsets.UTF_8;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
@@ -52,7 +51,6 @@
import com.google.devtools.build.lib.actions.InputMetadataProvider;
import com.google.devtools.build.lib.actions.ResourceSet;
import com.google.devtools.build.lib.actions.SimpleSpawn;
-import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.actions.SpawnResult;
import com.google.devtools.build.lib.actions.SpawnResult.Status;
import com.google.devtools.build.lib.clock.JavaClock;
@@ -83,7 +81,6 @@
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;
import com.google.devtools.build.lib.vfs.OutputService;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -100,7 +97,6 @@
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@@ -122,7 +118,7 @@
private Path execRoot;
private TempPathGenerator tempPathGenerator;
private SimpleSpawn simpleSpawn;
- private SpawnExecutionContext simplePolicy;
+ private FakeActionInputFileCache fakeFileCache;
@Mock private RemoteCache remoteCache;
private FileOutErr outErr;
@@ -131,102 +127,101 @@
private Reporter reporter;
private RemotePathResolver remotePathResolver;
- private static SpawnExecutionContext createSpawnExecutionContext(
- Spawn spawn, Path execRoot, FakeActionInputFileCache fakeFileCache, FileOutErr outErr) {
- return new SpawnExecutionContext() {
- @Nullable private com.google.devtools.build.lib.exec.Protos.Digest digest;
+ private final SpawnExecutionContext simplePolicy =
+ new SpawnExecutionContext() {
+ @Nullable private com.google.devtools.build.lib.exec.Protos.Digest digest;
- @Override
- public int getId() {
- return 0;
- }
+ @Override
+ public int getId() {
+ return 0;
+ }
- @Override
- public void setDigest(com.google.devtools.build.lib.exec.Protos.Digest digest) {
- checkState(this.digest == null);
- this.digest = digest;
- }
+ @Override
+ public void setDigest(com.google.devtools.build.lib.exec.Protos.Digest digest) {
+ checkState(this.digest == null);
+ this.digest = digest;
+ }
- @Override
- @Nullable
- public com.google.devtools.build.lib.exec.Protos.Digest getDigest() {
- return digest;
- }
+ @Override
+ @Nullable
+ public com.google.devtools.build.lib.exec.Protos.Digest getDigest() {
+ return digest;
+ }
- @Override
- public ListenableFuture<Void> prefetchInputs() {
- return immediateVoidFuture();
- }
+ @Override
+ public ListenableFuture<Void> prefetchInputs() {
+ return immediateVoidFuture();
+ }
- @Override
- public void lockOutputFiles(int exitCode, String errorMessage, FileOutErr outErr) {}
+ @Override
+ public void lockOutputFiles(int exitCode, String errorMessage, FileOutErr outErr) {}
- @Override
- public boolean speculating() {
- return false;
- }
+ @Override
+ public boolean speculating() {
+ return false;
+ }
- @Override
- public InputMetadataProvider getInputMetadataProvider() {
- return fakeFileCache;
- }
+ @Override
+ public InputMetadataProvider getInputMetadataProvider() {
+ return fakeFileCache;
+ }
- @Override
- public ArtifactPathResolver getPathResolver() {
- return ArtifactPathResolver.forExecRoot(execRoot);
- }
+ @Override
+ public ArtifactPathResolver getPathResolver() {
+ return ArtifactPathResolver.forExecRoot(execRoot);
+ }
- @Override
- public ArtifactExpander getArtifactExpander() {
- throw new UnsupportedOperationException();
- }
+ @Override
+ public ArtifactExpander getArtifactExpander() {
+ throw new UnsupportedOperationException();
+ }
- @Override
- public SpawnInputExpander getSpawnInputExpander() {
- return new SpawnInputExpander(execRoot, /*strict*/ false);
- }
+ @Override
+ public SpawnInputExpander getSpawnInputExpander() {
+ return new SpawnInputExpander(execRoot, /*strict*/ false);
+ }
- @Override
- public Duration getTimeout() {
- return Duration.ZERO;
- }
+ @Override
+ public Duration getTimeout() {
+ return Duration.ZERO;
+ }
- @Override
- public FileOutErr getFileOutErr() {
- return outErr;
- }
+ @Override
+ public FileOutErr getFileOutErr() {
+ return outErr;
+ }
- @Override
- public SortedMap<PathFragment, ActionInput> getInputMapping(
- PathFragment baseDirectory, boolean willAccessRepeatedly)
- throws IOException, ForbiddenActionInputException {
- return getSpawnInputExpander()
- .getInputMapping(spawn, SIMPLE_ARTIFACT_EXPANDER, baseDirectory, fakeFileCache);
- }
+ @Override
+ public SortedMap<PathFragment, ActionInput> getInputMapping(
+ PathFragment baseDirectory, boolean willAccessRepeatedly)
+ throws IOException, ForbiddenActionInputException {
+ return getSpawnInputExpander()
+ .getInputMapping(simpleSpawn, SIMPLE_ARTIFACT_EXPANDER, baseDirectory, fakeFileCache);
+ }
- @Override
- public void report(ProgressStatus progress) {}
+ @Override
+ public void report(ProgressStatus progress) {
+ }
- @Override
- public boolean isRewindingEnabled() {
- return false;
- }
+ @Override
+ public boolean isRewindingEnabled() {
+ return false;
+ }
- @Override
- public void checkForLostInputs() {}
+ @Override
+ public void checkForLostInputs() {}
- @Override
- public <T extends ActionContext> T getContext(Class<T> identifyingType) {
- throw new UnsupportedOperationException();
- }
+ @Override
+ public <T extends ActionContext> T getContext(Class<T> identifyingType) {
+ throw new UnsupportedOperationException();
+ }
- @Nullable
- @Override
- public FileSystem getActionFileSystem() {
- return null;
- }
- };
- }
+ @Nullable
+ @Override
+ public FileSystem getActionFileSystem() {
+ return null;
+ }
+ };
private static SimpleSpawn simpleSpawnWithExecutionInfo(
ImmutableMap<String, String> executionInfo) {
@@ -241,27 +236,6 @@
ResourceSet.ZERO);
}
- private static SimpleSpawn simplePathMappedSpawn(String configSegment) {
- String inputPath = "bazel-bin/%s/bin/input";
- String outputPath = "bazel-bin/%s/bin/output";
- return new SimpleSpawn(
- new FakeOwner("Mnemonic", "Progress Message", "//dummy:label"),
- ImmutableList.of("cp", inputPath.formatted("cfg"), outputPath.formatted("cfg")),
- ImmutableMap.of("VARIABLE", "value"),
- ImmutableMap.of(ExecutionRequirements.SUPPORTS_PATH_MAPPING, ""),
- /* runfilesSupplier= */ null,
- /* filesetMappings= */ ImmutableMap.of(),
- /* inputs= */ NestedSetBuilder.create(
- Order.STABLE_ORDER, ActionInputHelper.fromPath(inputPath.formatted(configSegment))),
- /* tools= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
- /* outputs= */ ImmutableSet.of(
- ActionInputHelper.fromPath(outputPath.formatted(configSegment))),
- /* mandatoryOutputs= */ null,
- ResourceSet.ZERO,
- execPath ->
- execPath.subFragment(0, 1).getRelative("cfg").getRelative(execPath.subFragment(2)));
- }
-
private RemoteSpawnCache createRemoteSpawnCache() {
return remoteSpawnCacheWithOptions(Options.getDefaults(RemoteOptions.class));
}
@@ -297,7 +271,7 @@
execRoot = fs.getPath("/exec/root");
execRoot.createDirectoryAndParents();
tempPathGenerator = new TempPathGenerator(fs.getPath("/execroot/_tmp/actions/remote"));
- FakeActionInputFileCache fakeFileCache = new FakeActionInputFileCache(execRoot);
+ fakeFileCache = new FakeActionInputFileCache(execRoot);
simpleSpawn = simpleSpawnWithExecutionInfo(ImmutableMap.of());
Path stdout = fs.getPath("/tmp/stdout");
@@ -310,7 +284,6 @@
reporter.addHandler(eventHandler);
remotePathResolver = RemotePathResolver.createDefault(execRoot);
- simplePolicy = createSpawnExecutionContext(simpleSpawn, execRoot, fakeFileCache, outErr);
fakeFileCache.createScratchInput(simpleSpawn.getInputFiles().getSingleton(), "xyz");
}
@@ -363,7 +336,7 @@
verify(service)
.downloadOutputs(
any(), eq(RemoteActionResult.createFromCache(CachedActionResult.remote(actionResult))));
- verify(service, never()).uploadOutputs(any(), any(), any());
+ verify(service, never()).uploadOutputs(any(), any());
assertThat(result.getDigest())
.isEqualTo(digestUtil.asSpawnLogProto(actionKeyCaptor.getValue()));
assertThat(result.setupSuccess()).isTrue();
@@ -394,9 +367,9 @@
.setStatus(Status.SUCCESS)
.setRunnerName("test")
.build();
- doNothing().when(service).uploadOutputs(any(), any(), any());
+ doNothing().when(service).uploadOutputs(any(), any());
entry.store(result);
- verify(service).uploadOutputs(any(), any(), any());
+ verify(service).uploadOutputs(any(), any());
}
@Test
@@ -560,7 +533,7 @@
.setRunnerName("test")
.build();
entry.store(result);
- verify(service, never()).uploadOutputs(any(), any(), any());
+ verify(service, never()).uploadOutputs(any(), any());
}
@Test
@@ -583,9 +556,9 @@
.setRunnerName("test")
.build();
- doNothing().when(service).uploadOutputs(any(), any(), any());
+ doNothing().when(service).uploadOutputs(any(), any());
entry.store(result);
- verify(service).uploadOutputs(any(), eq(result), any());
+ verify(service).uploadOutputs(any(), eq(result));
assertThat(eventHandler.getEvents()).hasSize(1);
Event evt = eventHandler.getEvents().get(0);
@@ -631,9 +604,9 @@
.setRunnerName("test")
.build();
- doNothing().when(service).uploadOutputs(any(), any(), any());
+ doNothing().when(service).uploadOutputs(any(), any());
entry.store(result);
- verify(service).uploadOutputs(any(), eq(result), any());
+ verify(service).uploadOutputs(any(), eq(result));
assertThat(eventHandler.getEvents()).isEmpty(); // no warning is printed.
}
@@ -707,141 +680,4 @@
assertThat(evt.getKind()).isEqualTo(EventKind.WARNING);
assertThat(evt.getMessage()).contains(downloadFailure.getMessage());
}
-
- @Test
- public void pathMappedActionIsDeduplicated() throws Exception {
- // arrange
- RemoteSpawnCache cache = createRemoteSpawnCache();
-
- SimpleSpawn firstSpawn = simplePathMappedSpawn("k8-fastbuild");
- FakeActionInputFileCache firstFakeFileCache = new FakeActionInputFileCache(execRoot);
- firstFakeFileCache.createScratchInput(firstSpawn.getInputFiles().getSingleton(), "xyz");
- SpawnExecutionContext firstPolicy =
- createSpawnExecutionContext(firstSpawn, execRoot, firstFakeFileCache, outErr);
-
- SimpleSpawn secondSpawn = simplePathMappedSpawn("k8-opt");
- FakeActionInputFileCache secondFakeFileCache = new FakeActionInputFileCache(execRoot);
- secondFakeFileCache.createScratchInput(secondSpawn.getInputFiles().getSingleton(), "xyz");
- SpawnExecutionContext secondPolicy =
- createSpawnExecutionContext(secondSpawn, execRoot, secondFakeFileCache, outErr);
-
- RemoteExecutionService remoteExecutionService = cache.getRemoteExecutionService();
- Mockito.doCallRealMethod().when(remoteExecutionService).waitForAndReuseOutputs(any(), any());
- // Simulate a very slow upload to the remote cache to ensure that the second spawn is
- // deduplicated rather than a cache hit. This is a slight hack, but also avoid introducing
- // concurrency to this test.
- Mockito.doNothing().when(remoteExecutionService).uploadOutputs(any(), any(), any());
-
- // act
- try (CacheHandle firstCacheHandle = cache.lookup(firstSpawn, firstPolicy)) {
- FileSystemUtils.writeContent(
- fs.getPath("/exec/root/bazel-bin/k8-fastbuild/bin/output"), UTF_8, "hello");
- firstCacheHandle.store(
- new SpawnResult.Builder()
- .setExitCode(0)
- .setStatus(Status.SUCCESS)
- .setRunnerName("test")
- .build());
- }
- CacheHandle secondCacheHandle = cache.lookup(secondSpawn, secondPolicy);
-
- // assert
- assertThat(secondCacheHandle.hasResult()).isTrue();
- assertThat(secondCacheHandle.getResult().getRunnerName()).isEqualTo("deduplicated");
- assertThat(
- FileSystemUtils.readContent(
- fs.getPath("/exec/root/bazel-bin/k8-opt/bin/output"), UTF_8))
- .isEqualTo("hello");
- assertThat(secondCacheHandle.willStore()).isFalse();
- }
-
- @Test
- public void deduplicatedActionWithNonZeroExitCodeIsACacheMiss() throws Exception {
- // arrange
- RemoteSpawnCache cache = createRemoteSpawnCache();
-
- SimpleSpawn firstSpawn = simplePathMappedSpawn("k8-fastbuild");
- FakeActionInputFileCache firstFakeFileCache = new FakeActionInputFileCache(execRoot);
- firstFakeFileCache.createScratchInput(firstSpawn.getInputFiles().getSingleton(), "xyz");
- SpawnExecutionContext firstPolicy =
- createSpawnExecutionContext(firstSpawn, execRoot, firstFakeFileCache, outErr);
-
- SimpleSpawn secondSpawn = simplePathMappedSpawn("k8-opt");
- FakeActionInputFileCache secondFakeFileCache = new FakeActionInputFileCache(execRoot);
- secondFakeFileCache.createScratchInput(secondSpawn.getInputFiles().getSingleton(), "xyz");
- SpawnExecutionContext secondPolicy =
- createSpawnExecutionContext(secondSpawn, execRoot, secondFakeFileCache, outErr);
-
- RemoteExecutionService remoteExecutionService = cache.getRemoteExecutionService();
- Mockito.doCallRealMethod().when(remoteExecutionService).waitForAndReuseOutputs(any(), any());
- // Simulate a very slow upload to the remote cache to ensure that the second spawn is
- // deduplicated rather than a cache hit. This is a slight hack, but also avoid introducing
- // concurrency to this test.
- Mockito.doNothing().when(remoteExecutionService).uploadOutputs(any(), any(), any());
-
- // act
- try (CacheHandle firstCacheHandle = cache.lookup(firstSpawn, firstPolicy)) {
- FileSystemUtils.writeContent(
- fs.getPath("/exec/root/bazel-bin/k8-fastbuild/bin/output"), UTF_8, "hello");
- firstCacheHandle.store(
- new SpawnResult.Builder()
- .setExitCode(1)
- .setStatus(Status.NON_ZERO_EXIT)
- .setFailureDetail(
- FailureDetail.newBuilder()
- .setMessage("test spawn failed")
- .setSpawn(
- FailureDetails.Spawn.newBuilder()
- .setCode(FailureDetails.Spawn.Code.NON_ZERO_EXIT))
- .build())
- .setRunnerName("test")
- .build());
- }
- CacheHandle secondCacheHandle = cache.lookup(secondSpawn, secondPolicy);
-
- // assert
- assertThat(secondCacheHandle.hasResult()).isFalse();
- assertThat(secondCacheHandle.willStore()).isTrue();
- }
-
- @Test
- public void deduplicatedActionWithMissingOutputIsACacheMiss() throws Exception {
- // arrange
- RemoteSpawnCache cache = createRemoteSpawnCache();
-
- SimpleSpawn firstSpawn = simplePathMappedSpawn("k8-fastbuild");
- FakeActionInputFileCache firstFakeFileCache = new FakeActionInputFileCache(execRoot);
- firstFakeFileCache.createScratchInput(firstSpawn.getInputFiles().getSingleton(), "xyz");
- SpawnExecutionContext firstPolicy =
- createSpawnExecutionContext(firstSpawn, execRoot, firstFakeFileCache, outErr);
-
- SimpleSpawn secondSpawn = simplePathMappedSpawn("k8-opt");
- FakeActionInputFileCache secondFakeFileCache = new FakeActionInputFileCache(execRoot);
- secondFakeFileCache.createScratchInput(secondSpawn.getInputFiles().getSingleton(), "xyz");
- SpawnExecutionContext secondPolicy =
- createSpawnExecutionContext(secondSpawn, execRoot, secondFakeFileCache, outErr);
-
- RemoteExecutionService remoteExecutionService = cache.getRemoteExecutionService();
- Mockito.doCallRealMethod().when(remoteExecutionService).waitForAndReuseOutputs(any(), any());
- // Simulate a very slow upload to the remote cache to ensure that the second spawn is
- // deduplicated rather than a cache hit. This is a slight hack, but also avoid introducing
- // concurrency to this test.
- Mockito.doNothing().when(remoteExecutionService).uploadOutputs(any(), any(), any());
-
- // act
- try (CacheHandle firstCacheHandle = cache.lookup(firstSpawn, firstPolicy)) {
- // Do not create the output.
- firstCacheHandle.store(
- new SpawnResult.Builder()
- .setExitCode(0)
- .setStatus(Status.SUCCESS)
- .setRunnerName("test")
- .build());
- }
- CacheHandle secondCacheHandle = cache.lookup(secondSpawn, secondPolicy);
-
- // assert
- assertThat(secondCacheHandle.hasResult()).isFalse();
- assertThat(secondCacheHandle.willStore()).isTrue();
- }
}
diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerTest.java
index 616e404..ce9c71a 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerTest.java
@@ -242,7 +242,7 @@
// TODO(olaola): verify that the uploaded action has the doNotCache set.
verify(service, never()).lookupCache(any());
- verify(service, never()).uploadOutputs(any(), any(), any());
+ verify(service, never()).uploadOutputs(any(), any());
verifyNoMoreInteractions(localRunner);
}
@@ -317,7 +317,7 @@
RemoteSpawnRunner runner = spy(newSpawnRunner());
RemoteExecutionService service = runner.getRemoteExecutionService();
- doNothing().when(service).uploadOutputs(any(), any(), any());
+ doNothing().when(service).uploadOutputs(any(), any());
// Throw an IOException to trigger the local fallback.
when(executor.executeRemotely(
@@ -343,7 +343,7 @@
verify(localRunner).exec(eq(spawn), eq(policy));
verify(runner)
.execLocallyAndUpload(any(), eq(spawn), eq(policy), /* uploadLocalResults= */ eq(true));
- verify(service).uploadOutputs(any(), eq(res), any());
+ verify(service).uploadOutputs(any(), eq(res));
}
@Test
@@ -376,7 +376,7 @@
verify(localRunner).exec(eq(spawn), eq(policy));
verify(runner)
.execLocallyAndUpload(any(), eq(spawn), eq(policy), /* uploadLocalResults= */ eq(true));
- verify(service, never()).uploadOutputs(any(), any(), any());
+ verify(service, never()).uploadOutputs(any(), any());
}
@Test
@@ -403,7 +403,7 @@
any(ExecuteRequest.class),
any(OperationObserver.class)))
.thenThrow(IOException.class);
- doNothing().when(service).uploadOutputs(any(), any(), any());
+ doNothing().when(service).uploadOutputs(any(), any());
Spawn spawn = newSimpleSpawn();
SpawnExecutionContext policy = getSpawnContext(spawn);
@@ -421,7 +421,7 @@
verify(localRunner).exec(eq(spawn), eq(policy));
verify(runner)
.execLocallyAndUpload(any(), eq(spawn), eq(policy), /* uploadLocalResults= */ eq(true));
- verify(service).uploadOutputs(any(), eq(result), any());
+ verify(service).uploadOutputs(any(), eq(result));
verify(service, never()).downloadOutputs(any(), any());
}
diff --git a/src/test/shell/bazel/path_mapping_test.sh b/src/test/shell/bazel/path_mapping_test.sh
index 4199c82..682c04e 100755
--- a/src/test/shell/bazel/path_mapping_test.sh
+++ b/src/test/shell/bazel/path_mapping_test.sh
@@ -46,15 +46,6 @@
source "$(rlocation "io_bazel/src/test/shell/bazel/remote/remote_utils.sh")" \
|| { echo "remote_utils.sh not found!" >&2; exit 1; }
-case "$(uname -s | tr [:upper:] [:lower:])" in
-msys*|mingw*|cygwin*)
- function is_windows() { true; }
- ;;
-*)
- function is_windows() { false; }
- ;;
-esac
-
function set_up() {
start_worker
@@ -603,269 +594,4 @@
expect_log ' 3 remote cache hit'
}
-function test_path_stripping_deduplicated_action() {
- if is_windows; then
- echo "Skipping test_path_stripping_deduplicated_action on Windows as it requires sandboxing"
- return
- fi
-
- mkdir rules
- touch rules/BUILD
- cat > rules/defs.bzl <<'EOF'
-def _slow_rule_impl(ctx):
- out_file = ctx.actions.declare_file(ctx.attr.name + "_file")
- out_dir = ctx.actions.declare_directory(ctx.attr.name + "_dir")
- out_symlink = ctx.actions.declare_symlink(ctx.attr.name + "_symlink")
- outs = [out_file, out_dir, out_symlink]
- args = ctx.actions.args().add_all(outs, expand_directories = False)
- ctx.actions.run_shell(
- outputs = outs,
- command = """
- # Sleep to ensure that two actions are scheduled in parallel.
- sleep 3
-
- echo "Hello, stdout!"
- >&2 echo "Hello, stderr!"
-
- echo 'echo "Hello, file!"' > $1
- chmod +x $1
- echo 'Hello, dir!' > $2/file
- ln -s $(basename $2)/file $3
- """,
- arguments = [args],
- execution_requirements = {"supports-path-mapping": ""},
- )
- return [
- DefaultInfo(files = depset(outs)),
- ]
-
-slow_rule = rule(_slow_rule_impl)
-EOF
-
- mkdir -p pkg
- cat > pkg/BUILD <<'EOF'
-load("//rules:defs.bzl", "slow_rule")
-
-slow_rule(name = "my_rule")
-
-COMMAND = """
-function validate() {
- # Sorted by file name.
- local -r dir=$$1
- local -r file=$$2
- local -r symlink=$$3
-
- [[ $$($$file) == "Hello, file!" ]] || exit 1
-
- [[ -d $$dir ]] || exit 1
- [[ $$(cat $$dir/file) == "Hello, dir!" ]] || exit 1
-
- [[ -L $$symlink ]] || exit 1
- [[ $$(cat $$symlink) == "Hello, dir!" ]] || exit 1
-}
-validate $(execpaths :my_rule)
-touch $@
-"""
-
-genrule(
- name = "gen_exec",
- outs = ["out_exec"],
- cmd = COMMAND,
- tools = [":my_rule"],
-)
-
-genrule(
- name = "gen_target",
- outs = ["out_target"],
- cmd = COMMAND,
- srcs = [":my_rule"],
-)
-EOF
-
- bazel build \
- --experimental_output_paths=strip \
- --remote_cache=grpc://localhost:${worker_port} \
- //pkg:all &> $TEST_log || fail "build failed unexpectedly"
- # The first slow_write action plus two genrules.
- expect_log '3 \(linux\|darwin\|processwrapper\)-sandbox'
- expect_log '1 deduplicated'
-
- # Even though the spawn is only executed once, its stdout/stderr should be
- # printed as if it wasn't deduplicated.
- expect_log_once 'INFO: From Action pkg/my_rule_file:'
- expect_log_once 'INFO: From Action pkg/my_rule_file \[for tool\]:'
- expect_log_n 'Hello, stderr!' 2
- expect_log_n 'Hello, stdout!' 2
-
- bazel clean || fail "clean failed unexpectedly"
- bazel build \
- --experimental_output_paths=strip \
- --remote_cache=grpc://localhost:${worker_port} \
- //pkg:all &> $TEST_log || fail "build failed unexpectedly"
- # The cache is checked before deduplication.
- expect_log '4 remote cache hit'
-}
-
-function test_path_stripping_deduplicated_action_output_not_created() {
- if is_windows; then
- echo "Skipping test_path_stripping_deduplicated_action_output_not_created on Windows as it requires sandboxing"
- return
- fi
-
- mkdir rules
- touch rules/BUILD
- cat > rules/defs.bzl <<'EOF'
-def _slow_rule_impl(ctx):
- out_file = ctx.actions.declare_file(ctx.attr.name + "_file")
- outs = [out_file]
- args = ctx.actions.args().add_all(outs)
- ctx.actions.run_shell(
- outputs = outs,
- command = """
- # Sleep to ensure that two actions are scheduled in parallel.
- sleep 3
-
- echo "Hello, stdout!"
- >&2 echo "Hello, stderr!"
-
- # Do not create the output file
- """,
- arguments = [args],
- execution_requirements = {"supports-path-mapping": ""},
- )
- return [
- DefaultInfo(files = depset(outs)),
- ]
-
-slow_rule = rule(_slow_rule_impl)
-EOF
-
- mkdir -p pkg
- cat > pkg/BUILD <<'EOF'
-load("//rules:defs.bzl", "slow_rule")
-
-slow_rule(name = "my_rule")
-
-COMMAND = """
-[[ $$($(execpath :my_rule)) == "Hello, file!" ]] || exit 1
-touch $@
-"""
-
-genrule(
- name = "gen_exec",
- outs = ["out_exec"],
- cmd = COMMAND,
- tools = [":my_rule"],
-)
-
-genrule(
- name = "gen_target",
- outs = ["out_target"],
- cmd = COMMAND,
- srcs = [":my_rule"],
-)
-EOF
-
- bazel build \
- --experimental_output_paths=strip \
- --remote_cache=grpc://localhost:${worker_port} \
- --keep_going \
- //pkg:all &> $TEST_log && fail "build succeeded unexpectedly"
- # The second action runs normally after discovering that the first one failed
- # to create the output file.
- expect_log '2 \(linux\|darwin\|processwrapper\)-sandbox'
- expect_not_log '[0-9] deduplicated'
-
- expect_log 'Action pkg/my_rule_file failed:'
- expect_log 'Action pkg/my_rule_file \[for tool\] failed:'
- # Remote cache warning.
- expect_log 'Expected output pkg/my_rule_file was not created locally.'
-
- expect_log_once 'INFO: From Action pkg/my_rule_file:'
- expect_log_once 'INFO: From Action pkg/my_rule_file \[for tool\]:'
- expect_log_n 'Hello, stderr!' 2
- expect_log_n 'Hello, stdout!' 2
-}
-
-function test_path_stripping_deduplicated_action_non_zero_exit_code() {
- if is_windows; then
- echo "Skipping test_path_stripping_deduplicated_action_non_zero_exit_code on Windows as it requires sandboxing"
- return
- fi
-
- mkdir rules
- touch rules/BUILD
- cat > rules/defs.bzl <<'EOF'
-def _slow_rule_impl(ctx):
- out_file = ctx.actions.declare_file(ctx.attr.name + "_file")
- outs = [out_file]
- args = ctx.actions.args().add_all(outs)
- ctx.actions.run_shell(
- outputs = outs,
- command = """
- # Sleep to ensure that two actions are scheduled in parallel.
- sleep 3
-
- echo "Hello, stdout!"
- >&2 echo "Hello, stderr!"
-
- # Create the output file, but with a non-zero exit code.
- echo 'echo "Hello, file!"' > $1
- exit 1
- """,
- arguments = [args],
- execution_requirements = {"supports-path-mapping": ""},
- )
- return [
- DefaultInfo(files = depset(outs)),
- ]
-
-slow_rule = rule(_slow_rule_impl)
-EOF
-
- mkdir -p pkg
- cat > pkg/BUILD <<'EOF'
-load("//rules:defs.bzl", "slow_rule")
-
-slow_rule(name = "my_rule")
-
-COMMAND = """
-[[ $$($(execpath :my_rule)) == "Hello, file!" ]] || exit 1
-touch $@
-"""
-
-genrule(
- name = "gen_exec",
- outs = ["out_exec"],
- cmd = COMMAND,
- tools = [":my_rule"],
-)
-
-genrule(
- name = "gen_target",
- outs = ["out_target"],
- cmd = COMMAND,
- srcs = [":my_rule"],
-)
-EOF
-
- bazel build \
- --experimental_output_paths=strip \
- --remote_cache=grpc://localhost:${worker_port} \
- --keep_going \
- //pkg:all &> $TEST_log && fail "build succeeded unexpectedly"
- # Failing actions are not deduplicated.
- expect_not_log '[0-9] deduplicated'
-
- expect_log 'Action pkg/my_rule_file failed:'
- expect_log 'Action pkg/my_rule_file \[for tool\] failed:'
-
- # The first execution emits stdout/stderr, the second doesn't.
- # stdout/stderr are emitted as part of the failing action error, not as an
- # info.
- expect_not_log 'INFO: From Action pkg/my_rule_file'
- expect_log_n 'Hello, stderr!' 2
- expect_log_n 'Hello, stdout!' 2
-}
-
run_suite "path mapping tests"