Simplify the Action interface by asking it a set of allowed inputs instead of to resolve exec paths found in the action cache.
The resolution algorithm was the same in all cases where it was implemented.
--
PiperOrigin-RevId: 146344672
MOS_MIGRATED_REVID=146344672
diff --git a/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java b/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java
index 4acc46a..7919529 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java
@@ -39,14 +39,12 @@
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
-import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.Symlinks;
import com.google.devtools.build.skyframe.SkyFunction;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
-import javax.annotation.Nullable;
/**
* Abstract implementation of Action which implements basic functionality: the inputs, outputs, and
@@ -188,13 +186,8 @@
return null;
}
- @Nullable
@Override
- public Iterable<Artifact> resolveInputsFromCache(
- ArtifactResolver artifactResolver,
- PackageRootResolver resolver,
- Collection<PathFragment> inputPaths)
- throws PackageRootResolutionException, InterruptedException {
+ public Iterable<Artifact> getAllowedDerivedInputs() {
throw new IllegalStateException(
"Method must be overridden for actions that may have unknown inputs.");
}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Action.java b/src/main/java/com/google/devtools/build/lib/actions/Action.java
index 6985fa2..bee4774 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Action.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Action.java
@@ -18,10 +18,8 @@
import com.google.devtools.build.lib.concurrent.ThreadSafety.ConditionallyThreadCompatible;
import com.google.devtools.build.lib.profiler.Describable;
import com.google.devtools.build.lib.vfs.Path;
-import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.SkyFunction;
import java.io.IOException;
-import java.util.Collection;
import javax.annotation.Nullable;
/**
@@ -165,25 +163,15 @@
throws ActionExecutionException, InterruptedException;
/**
- * Method used to resolve action inputs based on the information contained in the action cache. It
- * will be called iff inputsKnown() is false for the given action instance and there is a related
- * cache entry in the action cache.
+ * Returns the set of artifacts that can possibly be inputs. It will be called iff inputsKnown()
+ * is false for the given action instance and there is a related cache entry in the action cache.
*
* <p>Method must be redefined for any action that may return inputsKnown() == false.
*
- * @param artifactResolver the artifact factory that can be used to manufacture artifacts
- * @param resolver object which helps to resolve some of the artifacts
- * @param inputPaths List of relative (to the execution root) input paths
- * @return List of Artifacts corresponding to inputPaths, or null if some dependencies were
- * missing and we need to try again later.
- * @throws PackageRootResolutionException on failure to determine package roots of inputPaths
+ * <p>The method is allowed to return source artifacts. They are useless, though, since exec paths
+ * in the action cache referring to source artifacts are always resolved.
*/
- @Nullable
- Iterable<Artifact> resolveInputsFromCache(
- ArtifactResolver artifactResolver,
- PackageRootResolver resolver,
- Collection<PathFragment> inputPaths)
- throws PackageRootResolutionException, InterruptedException;
+ Iterable<Artifact> getAllowedDerivedInputs();
/**
* Informs the action that its inputs are {@code inputs}, and that its inputs are now known. Can
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java b/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java
index b97d323..4f2a33c 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java
@@ -300,16 +300,57 @@
for (Artifact output : action.getOutputs()) {
outputs.add(output.getExecPath());
}
- List<PathFragment> inputs = new ArrayList<>();
+ List<PathFragment> inputExecPaths = new ArrayList<>();
for (String path : entry.getPaths()) {
PathFragment execPath = new PathFragment(path);
// Code assumes that action has only 1-2 outputs and ArrayList.contains() will be
// most efficient.
if (!outputs.contains(execPath)) {
- inputs.add(execPath);
+ inputExecPaths.add(execPath);
}
}
- return action.resolveInputsFromCache(artifactResolver, resolver, inputs);
+
+ // Note that this method may trigger a violation of the desirable invariant that getInputs()
+ // is a superset of getMandatoryInputs(). See bug about an "action not in canonical form"
+ // error message and the integration test test_crosstool_change_and_failure().
+ Map<PathFragment, Artifact> allowedDerivedInputsMap = new HashMap<>();
+ for (Artifact derivedInput : action.getAllowedDerivedInputs()) {
+ if (!derivedInput.isSourceArtifact()) {
+ allowedDerivedInputsMap.put(derivedInput.getExecPath(), derivedInput);
+ }
+ }
+
+ List<Artifact> inputArtifacts = new ArrayList<>();
+ List<PathFragment> unresolvedPaths = new ArrayList<>();
+ for (PathFragment execPath : inputExecPaths) {
+ Artifact artifact = allowedDerivedInputsMap.get(execPath);
+ if (artifact != null) {
+ inputArtifacts.add(artifact);
+ } else {
+ // Remember this execPath, we will try to resolve it as a source artifact.
+ unresolvedPaths.add(execPath);
+ }
+ }
+
+ Map<PathFragment, Artifact> resolvedArtifacts =
+ artifactResolver.resolveSourceArtifacts(unresolvedPaths, resolver);
+ if (resolvedArtifacts == null) {
+ // We are missing some dependencies. We need to rerun this update later.
+ return null;
+ }
+
+ for (PathFragment execPath : unresolvedPaths) {
+ Artifact artifact = resolvedArtifacts.get(execPath);
+ // If PathFragment cannot be resolved into the artifact, ignore it. This could happen if the
+ // rule has changed and the action no longer depends on, e.g., an additional source file in a
+ // separate package and that package is no longer referenced anywhere else. It is safe to
+ // ignore such paths because dependency checker would identify changes in inputs (ignored path
+ // was used before) and will force action execution.
+ if (artifact != null) {
+ inputArtifacts.add(artifact);
+ }
+ }
+ return inputArtifacts;
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
index b1e87d3..6465f6c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
@@ -34,8 +34,6 @@
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.ExecutionInfoSpecifier;
import com.google.devtools.build.lib.actions.Executor;
-import com.google.devtools.build.lib.actions.PackageRootResolutionException;
-import com.google.devtools.build.lib.actions.PackageRootResolver;
import com.google.devtools.build.lib.actions.ResourceSet;
import com.google.devtools.build.lib.actions.extra.CppCompileInfo;
import com.google.devtools.build.lib.actions.extra.ExtraActionInfo;
@@ -1081,50 +1079,6 @@
return variableBuilder.build();
}
- // Keep in sync with {@link ObjcCompileAction#resolveInputsFromCache}
- @Override
- public Iterable<Artifact> resolveInputsFromCache(
- ArtifactResolver artifactResolver,
- PackageRootResolver resolver,
- Collection<PathFragment> inputPaths)
- throws PackageRootResolutionException, InterruptedException {
- // Note that this method may trigger a violation of the desirable invariant that getInputs()
- // is a superset of getMandatoryInputs(). See bug about an "action not in canonical form"
- // error message and the integration test test_crosstool_change_and_failure().
- Map<PathFragment, Artifact> allowedDerivedInputsMap = getAllowedDerivedInputsMap();
- List<Artifact> inputs = new ArrayList<>();
- List<PathFragment> unresolvedPaths = new ArrayList<>();
- for (PathFragment execPath : inputPaths) {
- Artifact artifact = allowedDerivedInputsMap.get(execPath);
- if (artifact != null) {
- inputs.add(artifact);
- } else {
- // Remember this execPath, we will try to resolve it as a source artifact.
- unresolvedPaths.add(execPath);
- }
- }
-
- Map<PathFragment, Artifact> resolvedArtifacts =
- artifactResolver.resolveSourceArtifacts(unresolvedPaths, resolver);
- if (resolvedArtifacts == null) {
- // We are missing some dependencies. We need to rerun this update later.
- return null;
- }
-
- for (PathFragment execPath : unresolvedPaths) {
- Artifact artifact = resolvedArtifacts.get(execPath);
- // If PathFragment cannot be resolved into the artifact - ignore it. This could happen if
- // rule definition has changed and action no longer depends on, e.g., additional source file
- // in the separate package and that package is no longer referenced anywhere else.
- // It is safe to ignore such paths because dependency checker would identify change in inputs
- // (ignored path was used before) and will force action execution.
- if (artifact != null) {
- inputs.add(artifact);
- }
- }
- return inputs;
- }
-
@Override protected void setInputs(Iterable<Artifact> inputs) {
super.setInputs(inputs);
}
@@ -1137,6 +1091,11 @@
}
}
+ @Override
+ public Iterable<Artifact> getAllowedDerivedInputs() {
+ return getAllowedDerivedInputsMap().values();
+ }
+
protected Map<PathFragment, Artifact> getAllowedDerivedInputsMap() {
Map<PathFragment, Artifact> allowedDerivedInputMap = new HashMap<>();
addToMap(allowedDerivedInputMap, mandatoryInputs);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LTOBackendAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LTOBackendAction.java
index 9e7b856..0b71041 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LTOBackendAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LTOBackendAction.java
@@ -22,9 +22,6 @@
import com.google.devtools.build.lib.actions.ActionExecutionException;
import com.google.devtools.build.lib.actions.ActionOwner;
import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.ArtifactResolver;
-import com.google.devtools.build.lib.actions.PackageRootResolutionException;
-import com.google.devtools.build.lib.actions.PackageRootResolver;
import com.google.devtools.build.lib.actions.ResourceSet;
import com.google.devtools.build.lib.actions.RunfilesSupplier;
import com.google.devtools.build.lib.analysis.actions.CommandLine;
@@ -175,15 +172,9 @@
inputsKnown = true;
}
- @Nullable
@Override
- public Iterable<Artifact> resolveInputsFromCache(
- ArtifactResolver artifactResolver,
- PackageRootResolver resolver,
- Collection<PathFragment> inputPaths)
- throws PackageRootResolutionException {
- Set<Artifact> bitcodeInputSet = computeBitcodeInputs(inputPaths);
- return createInputs(bitcodeInputSet, getMandatoryInputs());
+ public Iterable<Artifact> getAllowedDerivedInputs() {
+ return bitcodeFiles.values();
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraAction.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraAction.java
index f9e4616..866e45e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraAction.java
@@ -15,8 +15,6 @@
package com.google.devtools.build.lib.rules.extra;
import com.google.common.base.Function;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -25,11 +23,8 @@
import com.google.devtools.build.lib.actions.ActionExecutionContext;
import com.google.devtools.build.lib.actions.ActionExecutionException;
import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.ArtifactResolver;
import com.google.devtools.build.lib.actions.CompositeRunfilesSupplier;
import com.google.devtools.build.lib.actions.DelegateSpawn;
-import com.google.devtools.build.lib.actions.PackageRootResolutionException;
-import com.google.devtools.build.lib.actions.PackageRootResolver;
import com.google.devtools.build.lib.actions.RunfilesSupplier;
import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.actions.SpawnActionContext;
@@ -40,7 +35,6 @@
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
-import com.google.devtools.build.lib.vfs.PathFragment;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
@@ -159,18 +153,9 @@
inputsKnown = true;
}
- @Nullable
@Override
- public Iterable<Artifact> resolveInputsFromCache(
- ArtifactResolver artifactResolver,
- PackageRootResolver resolver,
- Collection<PathFragment> inputPaths)
- throws PackageRootResolutionException, InterruptedException {
- // We update the inputs directly from the shadowed action.
- Set<PathFragment> extraActionPathFragments =
- ImmutableSet.copyOf(Artifact.asPathFragments(extraActionInputs));
- return shadowedAction.resolveInputsFromCache(artifactResolver, resolver,
- Collections2.filter(inputPaths, Predicates.in(extraActionPathFragments)));
+ public Iterable<Artifact> getAllowedDerivedInputs() {
+ return shadowedAction.getAllowedDerivedInputs();
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCompileAction.java
index 49a741a..70509aa 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCompileAction.java
@@ -28,8 +28,6 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ArtifactResolver;
import com.google.devtools.build.lib.actions.Executor;
-import com.google.devtools.build.lib.actions.PackageRootResolutionException;
-import com.google.devtools.build.lib.actions.PackageRootResolver;
import com.google.devtools.build.lib.actions.ResourceSet;
import com.google.devtools.build.lib.actions.RunfilesSupplier;
import com.google.devtools.build.lib.actions.Spawn;
@@ -52,10 +50,7 @@
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import javax.annotation.concurrent.GuardedBy;
@@ -181,49 +176,6 @@
return filterHeaderFiles();
}
- // Keep in sync with {@link CppCompileAction#resolveInputsFromCache}
- @Override
- public Iterable<Artifact> resolveInputsFromCache(
- ArtifactResolver artifactResolver,
- PackageRootResolver resolver,
- Collection<PathFragment> inputPaths)
- throws PackageRootResolutionException, InterruptedException {
- // Note that this method may trigger a violation of the desirable invariant that getInputs()
- // is a superset of getMandatoryInputs().
- Map<PathFragment, Artifact> allowedDerivedInputsMap = getAllowedDerivedInputsMap();
- List<Artifact> inputs = new ArrayList<>();
- List<PathFragment> unresolvedPaths = new ArrayList<>();
- for (PathFragment execPath : inputPaths) {
- Artifact artifact = allowedDerivedInputsMap.get(execPath);
- if (artifact != null) {
- inputs.add(artifact);
- } else {
- // Remember this execPath, we will try to resolve it as a source artifact.
- unresolvedPaths.add(execPath);
- }
- }
-
- Map<PathFragment, Artifact> resolvedArtifacts =
- artifactResolver.resolveSourceArtifacts(unresolvedPaths, resolver);
- if (resolvedArtifacts == null) {
- // We are missing some dependencies. We need to rerun this update later.
- return null;
- }
-
- for (PathFragment execPath : unresolvedPaths) {
- Artifact artifact = resolvedArtifacts.get(execPath);
- // If PathFragment cannot be resolved into the artifact - ignore it. This could happen if
- // rule definition has changed and action no longer depends on, e.g., additional source file
- // in the separate package and that package is no longer referenced anywhere else.
- // It is safe to ignore such paths because dependency checker would identify change in inputs
- // (ignored path was used before) and will force action execution.
- if (artifact != null) {
- inputs.add(artifact);
- }
- }
- return inputs;
- }
-
@Override
public synchronized void updateInputs(Iterable<Artifact> inputs) {
inputsKnown = true;
@@ -289,6 +241,11 @@
}
}
+ @Override
+ public Iterable<Artifact> getAllowedDerivedInputs() {
+ return getAllowedDerivedInputsMap().values();
+ }
+
private Map<PathFragment, Artifact> getAllowedDerivedInputsMap() {
Map<PathFragment, Artifact> allowedDerivedInputMap = new HashMap<>();
addToMapIfSource(allowedDerivedInputMap, getInputs());