Consolidate key-caching logic in an abstract class.
This way all actions and action templates can share the same key-caching code.
RELNOTES: None.
PiperOrigin-RevId: 244866405
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 71250f6..379962f 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
@@ -36,7 +36,6 @@
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
-import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.lib.vfs.Symlinks;
@@ -53,7 +52,7 @@
*/
@Immutable
@ThreadSafe
-public abstract class AbstractAction implements Action, ActionApi {
+public abstract class AbstractAction extends ActionKeyCacher implements Action, ActionApi {
/**
* An arbitrary default resource set. We assume that a typical subprocess is single-threaded
* (i.e., uses one CPU core) and CPU-bound, and uses a small-ish amount of memory. In the past,
@@ -62,8 +61,7 @@
* amounts of memory), we suggest to use this default set.
*/
// TODO(ulfjack): Collect actual data to confirm that this is an acceptable approximation.
- public static final ResourceSet DEFAULT_RESOURCE_SET =
- ResourceSet.createWithRamCpu(250, 1);
+ public static final ResourceSet DEFAULT_RESOURCE_SET = ResourceSet.createWithRamCpu(250, 1);
/**
* The owner/inputs/outputs attributes below should never be directly accessed even within
@@ -103,8 +101,6 @@
private final RunfilesSupplier runfilesSupplier;
@VisibleForSerialization protected final ImmutableSet<Artifact> outputs;
- private String cachedKey;
-
/**
* Construct an abstract action with the specified inputs and outputs;
*/
@@ -280,37 +276,6 @@
@Override
public abstract String getMnemonic();
- /**
- * See the javadoc for {@link com.google.devtools.build.lib.actions.Action} and {@link
- * ActionExecutionMetadata#getKey(ActionKeyContext)} for the contract for {@link
- * #computeKey(ActionKeyContext, Fingerprint)}.
- */
- protected abstract void computeKey(ActionKeyContext actionKeyContext, Fingerprint fp)
- throws CommandLineExpansionException;
-
- @Override
- public final synchronized String getKey(ActionKeyContext actionKeyContext) {
- if (cachedKey == null) {
- try {
- Fingerprint fp = new Fingerprint();
- computeKey(actionKeyContext, fp);
-
- // Add a bool indicating whether the execution platform was set.
- fp.addBoolean(getExecutionPlatform() != null);
- if (getExecutionPlatform() != null) {
- // Add the execution platform information.
- getExecutionPlatform().addTo(fp);
- }
-
- // Compute the actual key and store it.
- cachedKey = fp.hexDigestAndReset();
- } catch (CommandLineExpansionException e) {
- cachedKey = KEY_ERROR;
- }
- }
- return cachedKey;
- }
-
@Override
public String describeKey() {
return null;
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionAnalysisMetadata.java b/src/main/java/com/google/devtools/build/lib/actions/ActionAnalysisMetadata.java
index e076912..736d229 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionAnalysisMetadata.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionAnalysisMetadata.java
@@ -14,12 +14,25 @@
package com.google.devtools.build.lib.actions;
import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
+import javax.annotation.Nullable;
/**
* An Analysis phase interface for an {@link Action} or Action-like object, containing only
* side-effect-free query methods for information needed during action analysis.
*/
public interface ActionAnalysisMetadata {
+
+ /**
+ * Return this key from {@link #getKey} to signify a failed key computation.
+ *
+ * <p>Actions that return this value should fail to execute.
+ *
+ * <p>Consumers must either gracefully handle multiple failed actions having the same key,
+ * (recommended), or check against this value explicitly.
+ */
+ String KEY_ERROR = "1ea50e01-0349-4552-80cf-76cf520e8592";
+
/**
* Returns the owner of this executable if this executable can supply verbose information. This is
* typically the rule that constructed it; see ActionOwner class comment for details. Returns
@@ -228,4 +241,11 @@
default boolean hasLooseHeaders() {
return false;
}
+
+ /**
+ * Returns the {@link PlatformInfo} platform this action should be executed on. If the execution
+ * platform is {@code null}, then the host platform is assumed.
+ */
+ @Nullable
+ PlatformInfo getExecutionPlatform();
}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionMetadata.java b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionMetadata.java
index 255074f..0b2b6af 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionMetadata.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionMetadata.java
@@ -13,7 +13,6 @@
// limitations under the License.
package com.google.devtools.build.lib.actions;
-import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import javax.annotation.Nullable;
@@ -27,16 +26,6 @@
public interface ActionExecutionMetadata extends ActionAnalysisMetadata {
/**
- * Return this key to signify a failed key computation.
- *
- * <p>Actions that return this value should fail to execute.
- *
- * <p>Consumers must either gracefully handle multiple failed actions having the same key,
- * (recommended), or check against this value explicitly.
- */
- String KEY_ERROR = "1ea50e01-0349-4552-80cf-76cf520e8592";
-
- /**
* If this executable can supply verbose information, returns a string that can be used as a
* progress message while this executable is running. A return value of {@code null} indicates no
* message should be reported.
@@ -115,11 +104,4 @@
default boolean mayInsensitivelyPropagateInputs() {
return false;
}
-
- /**
- * Returns the {@link PlatformInfo} platform this action should be executed on. If the execution
- * platform is {@code null}, then the host platform is assumed.
- */
- @Nullable
- PlatformInfo getExecutionPlatform();
}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionKeyCacher.java b/src/main/java/com/google/devtools/build/lib/actions/ActionKeyCacher.java
new file mode 100644
index 0000000..e325f06
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionKeyCacher.java
@@ -0,0 +1,56 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.actions;
+
+import com.google.devtools.build.lib.util.Fingerprint;
+import javax.annotation.Nullable;
+
+/**
+ * An implementation of {@link ActionAnalysisMetadata} that caches its {@linkplain #getKey key} so
+ * that it is only computed once.
+ */
+public abstract class ActionKeyCacher implements ActionAnalysisMetadata {
+
+ @Nullable private String cachedKey = null;
+
+ @Override
+ public final synchronized String getKey(ActionKeyContext actionKeyContext) {
+ if (cachedKey == null) {
+ try {
+ Fingerprint fp = new Fingerprint();
+ computeKey(actionKeyContext, fp);
+
+ // Add a bool indicating whether the execution platform was set.
+ fp.addBoolean(getExecutionPlatform() != null);
+ if (getExecutionPlatform() != null) {
+ // Add the execution platform information.
+ getExecutionPlatform().addTo(fp);
+ }
+
+ // Compute the actual key and store it.
+ cachedKey = fp.hexDigestAndReset();
+ } catch (CommandLineExpansionException e) {
+ cachedKey = KEY_ERROR;
+ }
+ }
+ return cachedKey;
+ }
+
+ /**
+ * See the javadoc for {@link Action} and {@link ActionAnalysisMetadata#getKey} for the contract
+ * of this method.
+ */
+ protected abstract void computeKey(ActionKeyContext actionKeyContext, Fingerprint fp)
+ throws CommandLineExpansionException;
+}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionTemplate.java b/src/main/java/com/google/devtools/build/lib/actions/ActionTemplate.java
index 2a68628..335b5d4 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionTemplate.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionTemplate.java
@@ -14,6 +14,8 @@
package com.google.devtools.build.lib.actions;
import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
+import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
+import javax.annotation.Nullable;
/**
* A placeholder action that, at execution time, expands into a list of {@link Action}s to be
@@ -84,4 +86,10 @@
/** Returns the output TreeArtifact. */
Artifact getOutputTreeArtifact();
+
+ @Override
+ @Nullable
+ default PlatformInfo getExecutionPlatform() {
+ return null;
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java
index c3716e1..4ae6ca2 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java
@@ -19,6 +19,7 @@
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.ActionExecutionContext;
import com.google.devtools.build.lib.actions.ActionInputHelper;
+import com.google.devtools.build.lib.actions.ActionKeyCacher;
import com.google.devtools.build.lib.actions.ActionKeyContext;
import com.google.devtools.build.lib.actions.ActionOwner;
import com.google.devtools.build.lib.actions.ActionTemplate;
@@ -27,16 +28,17 @@
import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
import com.google.devtools.build.lib.actions.ArtifactOwner;
import com.google.devtools.build.lib.actions.CommandLine;
+import com.google.devtools.build.lib.actions.CommandLineExpansionException;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.Map;
-/**
- * An {@link ActionTemplate} that expands into {@link SpawnAction}s at execution time.
- */
-public final class SpawnActionTemplate implements ActionTemplate<SpawnAction> {
+/** An {@link ActionTemplate} that expands into {@link SpawnAction}s at execution time. */
+public final class SpawnActionTemplate extends ActionKeyCacher
+ implements ActionTemplate<SpawnAction> {
private final SpecialArtifact inputTreeArtifact;
private final SpecialArtifact outputTreeArtifact;
private final NestedSet<Artifact> commonInputs;
@@ -47,7 +49,6 @@
private final OutputPathMapper outputPathMapper;
private final SpawnAction.Builder spawnActionBuilder;
private final CustomCommandLine commandLineTemplate;
- private String cachedKey;
/**
* Interface providing mapping between expanded input files under the input TreeArtifact and
@@ -115,18 +116,15 @@
}
@Override
- public synchronized String getKey(ActionKeyContext actionKeyContext) {
- if (cachedKey != null) {
- return cachedKey;
- }
+ protected void computeKey(ActionKeyContext actionKeyContext, Fingerprint fp)
+ throws CommandLineExpansionException {
TreeFileArtifact inputTreeFileArtifact =
ActionInputHelper.treeFileArtifact(inputTreeArtifact, "dummy_for_key");
TreeFileArtifact outputTreeFileArtifact =
ActionInputHelper.treeFileArtifact(
outputTreeArtifact, outputPathMapper.parentRelativeOutputPath(inputTreeFileArtifact));
SpawnAction dummyAction = createAction(inputTreeFileArtifact, outputTreeFileArtifact);
- cachedKey = dummyAction.getKey(actionKeyContext);
- return cachedKey;
+ dummyAction.computeKey(actionKeyContext, fp);
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionTemplate.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionTemplate.java
index 3ce146e..353f70a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionTemplate.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionTemplate.java
@@ -20,6 +20,7 @@
import com.google.devtools.build.lib.actions.ActionExecutionContext;
import com.google.devtools.build.lib.actions.ActionExecutionException;
import com.google.devtools.build.lib.actions.ActionInputHelper;
+import com.google.devtools.build.lib.actions.ActionKeyCacher;
import com.google.devtools.build.lib.actions.ActionKeyContext;
import com.google.devtools.build.lib.actions.ActionOwner;
import com.google.devtools.build.lib.actions.ActionTemplate;
@@ -37,10 +38,9 @@
import java.util.ArrayList;
import java.util.List;
-/**
- * An {@link ActionTemplate} that expands into {@link CppCompileAction}s at execution time.
- */
-public final class CppCompileActionTemplate implements ActionTemplate<CppCompileAction> {
+/** An {@link ActionTemplate} that expands into {@link CppCompileAction}s at execution time. */
+public final class CppCompileActionTemplate extends ActionKeyCacher
+ implements ActionTemplate<CppCompileAction> {
private final CppCompileActionBuilder cppCompileActionBuilder;
private final Artifact sourceTreeArtifact;
private final Artifact outputTreeArtifact;
@@ -50,7 +50,6 @@
private final ActionOwner actionOwner;
private final NestedSet<Artifact> mandatoryInputs;
private final NestedSet<Artifact> allInputs;
- private String cachedKey;
/**
* Creates an CppCompileActionTemplate.
@@ -143,10 +142,8 @@
}
@Override
- public synchronized String getKey(ActionKeyContext actionKeyContext) {
- if (cachedKey != null) {
- return cachedKey;
- }
+ protected void computeKey(ActionKeyContext actionKeyContext, Fingerprint fp)
+ throws CommandLineExpansionException {
CompileCommandLine commandLine =
CppCompileAction.buildCommandLine(
sourceTreeArtifact,
@@ -155,28 +152,21 @@
dotdTreeArtifact,
cppCompileActionBuilder.getFeatureConfiguration(),
cppCompileActionBuilder.getVariables());
- Fingerprint fp = new Fingerprint();
- try {
- CppCompileAction.computeKey(
- actionKeyContext,
- fp,
- cppCompileActionBuilder.getActionClassId(),
- cppCompileActionBuilder.getActionEnvironment(),
- commandLine.getEnvironment(),
- cppCompileActionBuilder.getExecutionInfo(),
- CppCompileAction.computeCommandLineKey(
- commandLine.getCompilerOptions(/*overwrittenVariables=*/ null)),
- cppCompileActionBuilder.getCcCompilationContext().getDeclaredIncludeSrcs(),
- cppCompileActionBuilder.buildMandatoryInputs(),
- cppCompileActionBuilder.buildPrunableHeaders(),
- cppCompileActionBuilder.getCcCompilationContext().getDeclaredIncludeDirs(),
- cppCompileActionBuilder.getBuiltinIncludeDirectories(),
- cppCompileActionBuilder.buildInputsForInvalidation());
- cachedKey = fp.hexDigestAndReset();
- } catch (CommandLineExpansionException e) {
- cachedKey = CppCompileAction.KEY_ERROR;
- }
- return cachedKey;
+ CppCompileAction.computeKey(
+ actionKeyContext,
+ fp,
+ cppCompileActionBuilder.getActionClassId(),
+ cppCompileActionBuilder.getActionEnvironment(),
+ commandLine.getEnvironment(),
+ cppCompileActionBuilder.getExecutionInfo(),
+ CppCompileAction.computeCommandLineKey(
+ commandLine.getCompilerOptions(/*overwrittenVariables=*/ null)),
+ cppCompileActionBuilder.getCcCompilationContext().getDeclaredIncludeSrcs(),
+ cppCompileActionBuilder.buildMandatoryInputs(),
+ cppCompileActionBuilder.buildPrunableHeaders(),
+ cppCompileActionBuilder.getCcCompilationContext().getDeclaredIncludeDirs(),
+ cppCompileActionBuilder.getBuiltinIncludeDirectories(),
+ cppCompileActionBuilder.buildInputsForInvalidation());
}
private boolean shouldCompileHeaders() {