aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Janak Ramakrishnan <janakr@google.com>2016-07-08 18:43:37 +0000
committerGravatar Kristina Chodorow <kchodorow@google.com>2016-07-11 09:39:26 +0000
commit2553c84a436b091fa58d3e599078fbe9ea8f26b2 (patch)
treef7dbe0c075471a2fec3c833a4ef0205a3150903f
parent9551686e94e7344ce08fbee5b9c7b4a47d01e872 (diff)
Replace QueryableGraph#getBatch with #getBatchWithFieldHints. This allows alternate graph implementations to optimize how they construct node entries.
-- MOS_MIGRATED_REVID=126932020
-rw-r--r--src/main/java/com/google/devtools/build/skyframe/DelegatingWalkableGraph.java54
-rw-r--r--src/main/java/com/google/devtools/build/skyframe/EvaluableGraph.java5
-rw-r--r--src/main/java/com/google/devtools/build/skyframe/InMemoryGraph.java3
-rw-r--r--src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java7
-rw-r--r--src/main/java/com/google/devtools/build/skyframe/NodeEntryField.java41
-rw-r--r--src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java72
-rw-r--r--src/main/java/com/google/devtools/build/skyframe/QueryableGraph.java13
-rw-r--r--src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java3
-rw-r--r--src/test/java/com/google/devtools/build/skyframe/DeterministicHelper.java6
-rw-r--r--src/test/java/com/google/devtools/build/skyframe/DeterministicInMemoryGraph.java5
-rw-r--r--src/test/java/com/google/devtools/build/skyframe/GraphConcurrencyTest.java12
-rw-r--r--src/test/java/com/google/devtools/build/skyframe/NotifyingHelper.java7
-rw-r--r--src/test/java/com/google/devtools/build/skyframe/NotifyingInMemoryGraph.java5
13 files changed, 159 insertions, 74 deletions
diff --git a/src/main/java/com/google/devtools/build/skyframe/DelegatingWalkableGraph.java b/src/main/java/com/google/devtools/build/skyframe/DelegatingWalkableGraph.java
index c99bc32285..7a584ecd1f 100644
--- a/src/main/java/com/google/devtools/build/skyframe/DelegatingWalkableGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/DelegatingWalkableGraph.java
@@ -15,9 +15,11 @@ package com.google.devtools.build.skyframe;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.devtools.build.lib.util.Preconditions;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@@ -28,46 +30,25 @@ import javax.annotation.Nullable;
* {@link WalkableGraph} that looks nodes up in a {@link QueryableGraph}.
*/
public class DelegatingWalkableGraph implements WalkableGraph {
-
- private final QueryableGraph fullGraph;
- private final QueryableGraph thinGraph;
+ private final QueryableGraph graph;
public DelegatingWalkableGraph(QueryableGraph graph) {
- this(graph, graph);
- }
-
- /**
- * Use this constructor when you want to differentiate reads that require the node value vs reads
- * that only traverse dependencies.
- */
- public DelegatingWalkableGraph(QueryableGraph fullGraph, QueryableGraph thinGraph) {
- this.fullGraph = fullGraph;
- this.thinGraph = thinGraph;
+ this.graph = graph;
}
private NodeEntry getEntry(SkyKey key) {
- NodeEntry entry = Preconditions.checkNotNull(fullGraph.get(key), key);
+ NodeEntry entry =
+ Preconditions.checkNotNull(
+ graph.getBatchWithFieldHints(ImmutableList.of(key), NodeEntryField.VALUE_ONLY).get(key),
+ key);
Preconditions.checkState(entry.isDone(), "%s %s", key, entry);
return entry;
}
- /**
- * Returns a map giving the {@link NodeEntry} corresponding to the given {@code keys}. If there is
- * no node in the graph corresponding to a {@link SkyKey} in {@code keys}, it is silently ignored
- * and will not be present in the returned map. This tolerance allows callers to avoid
- * pre-filtering their keys by checking for existence, which can be expensive.
- */
- private static Map<SkyKey, NodeEntry> getEntries(Iterable<SkyKey> keys, QueryableGraph graph) {
- Map<SkyKey, NodeEntry> result = graph.getBatch(keys);
- for (Map.Entry<SkyKey, NodeEntry> entry : result.entrySet()) {
- Preconditions.checkState(entry.getValue().isDone(), entry);
- }
- return result;
- }
-
@Override
public boolean exists(SkyKey key) {
- NodeEntry entry = thinGraph.get(key);
+ NodeEntry entry =
+ graph.getBatchWithFieldHints(ImmutableList.of(key), NodeEntryField.NO_FIELDS).get(key);
return entry != null && entry.isDone();
}
@@ -88,14 +69,17 @@ public class DelegatingWalkableGraph implements WalkableGraph {
@Override
public Map<SkyKey, SkyValue> getSuccessfulValues(Iterable<SkyKey> keys) {
- return Maps.filterValues(Maps.transformValues(fullGraph.getBatch(keys), GET_SKY_VALUE_FUNCTION),
+ return Maps.filterValues(
+ Maps.transformValues(
+ graph.getBatchWithFieldHints(keys, NodeEntryField.VALUE_ONLY), GET_SKY_VALUE_FUNCTION),
Predicates.notNull());
}
@Override
public Map<SkyKey, Exception> getMissingAndExceptions(Iterable<SkyKey> keys) {
Map<SkyKey, Exception> result = new HashMap<>();
- Map<SkyKey, NodeEntry> graphResult = fullGraph.getBatch(keys);
+ Map<SkyKey, NodeEntry> graphResult =
+ graph.getBatchWithFieldHints(keys, NodeEntryField.VALUE_ONLY);
for (SkyKey key : keys) {
NodeEntry nodeEntry = graphResult.get(key);
if (nodeEntry == null || !nodeEntry.isDone()) {
@@ -119,9 +103,11 @@ public class DelegatingWalkableGraph implements WalkableGraph {
@Override
public Map<SkyKey, Iterable<SkyKey>> getDirectDeps(Iterable<SkyKey> keys) {
- Map<SkyKey, NodeEntry> entries = getEntries(keys, thinGraph);
+ Map<SkyKey, NodeEntry> entries =
+ graph.getBatchWithFieldHints(keys, EnumSet.of(NodeEntryField.DIRECT_DEPS));
Map<SkyKey, Iterable<SkyKey>> result = new HashMap<>(entries.size());
for (Entry<SkyKey, NodeEntry> entry : entries.entrySet()) {
+ Preconditions.checkState(entry.getValue().isDone(), entry);
result.put(entry.getKey(), entry.getValue().getDirectDeps());
}
return result;
@@ -129,9 +115,11 @@ public class DelegatingWalkableGraph implements WalkableGraph {
@Override
public Map<SkyKey, Iterable<SkyKey>> getReverseDeps(Iterable<SkyKey> keys) {
- Map<SkyKey, NodeEntry> entries = getEntries(keys, thinGraph);
+ Map<SkyKey, NodeEntry> entries =
+ graph.getBatchWithFieldHints(keys, EnumSet.of(NodeEntryField.REVERSE_DEPS));
Map<SkyKey, Iterable<SkyKey>> result = new HashMap<>(entries.size());
for (Entry<SkyKey, NodeEntry> entry : entries.entrySet()) {
+ Preconditions.checkState(entry.getValue().isDone(), entry);
result.put(entry.getKey(), entry.getValue().getReverseDeps());
}
return result;
diff --git a/src/main/java/com/google/devtools/build/skyframe/EvaluableGraph.java b/src/main/java/com/google/devtools/build/skyframe/EvaluableGraph.java
index b3d8bd0ac2..a9c067d6fd 100644
--- a/src/main/java/com/google/devtools/build/skyframe/EvaluableGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/EvaluableGraph.java
@@ -24,8 +24,9 @@ import java.util.Map;
@ThreadSafe
interface EvaluableGraph extends QueryableGraph, DeletableGraph {
/**
- * Like {@link QueryableGraph#getBatch}, except it creates a new node for each key not already
- * present in the graph. Thus, the returned map will have an entry for each key in {@code keys}.
+ * Like {@link QueryableGraph#getBatchWithFieldHints}, except it creates a new node for each key
+ * not already present in the graph. Thus, the returned map will have an entry for each key in
+ * {@code keys}.
*/
Map<SkyKey, NodeEntry> createIfAbsentBatch(Iterable<SkyKey> keys);
}
diff --git a/src/main/java/com/google/devtools/build/skyframe/InMemoryGraph.java b/src/main/java/com/google/devtools/build/skyframe/InMemoryGraph.java
index 5d508a9eb1..6f25093e41 100644
--- a/src/main/java/com/google/devtools/build/skyframe/InMemoryGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/InMemoryGraph.java
@@ -17,6 +17,9 @@ import java.util.Map;
/** {@link ProcessableGraph} that exposes the contents of the entire graph. */
interface InMemoryGraph extends ProcessableGraph, InvalidatableGraph {
+ @Override
+ Map<SkyKey, NodeEntry> getBatch(Iterable<SkyKey> keys);
+
/**
* Returns a read-only live view of the nodes in the graph. All node are included. Dirty values
* include their Node value. Values in error have a null value.
diff --git a/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java b/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java
index 3679d6266f..ef6e24b1a6 100644
--- a/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java
+++ b/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java
@@ -21,6 +21,7 @@ import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
import java.util.Collections;
+import java.util.EnumSet;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
@@ -66,6 +67,12 @@ public class InMemoryGraphImpl implements InMemoryGraph {
return builder.build();
}
+ @Override
+ public Map<SkyKey, NodeEntry> getBatchWithFieldHints(
+ Iterable<SkyKey> keys, EnumSet<NodeEntryField> fields) {
+ return getBatch(keys);
+ }
+
protected NodeEntry createIfAbsent(SkyKey key) {
NodeEntry newval = keepEdges ? new InMemoryNodeEntry() : new EdgelessInMemoryNodeEntry();
NodeEntry oldval = nodeMap.putIfAbsent(key, newval);
diff --git a/src/main/java/com/google/devtools/build/skyframe/NodeEntryField.java b/src/main/java/com/google/devtools/build/skyframe/NodeEntryField.java
new file mode 100644
index 0000000000..97c1dfd87c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skyframe/NodeEntryField.java
@@ -0,0 +1,41 @@
+// Copyright 2016 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.skyframe;
+
+import java.util.EnumSet;
+
+/**
+ * Fields of a {@link NodeEntry} that clients of a {@link QueryableGraph} may need. Clients may
+ * specify these fields in {@link QueryableGraph#getBatchWithFieldHints} to help particular {@link
+ * QueryableGraph} implementations decide how lazily to construct the returned node entries.
+ */
+public enum NodeEntryField {
+ /** The value ({@link NodeEntry#getValueMaybeWithMetadata}) will be needed. */
+ VALUE,
+ /** The direct deps ({@link NodeEntry#getDirectDeps}) will be needed. */
+ DIRECT_DEPS,
+ /** The reverse deps ({@link NodeEntry#getReverseDeps}) will be needed. */
+ REVERSE_DEPS,
+ /**
+ * The reverse deps as a whole will not be needed, but we may need to check the presence of a
+ * reverse dep or add/delete one.
+ */
+ INDIVIDUAL_REVERSE_DEPS;
+
+ public static final EnumSet<NodeEntryField> NO_FIELDS = EnumSet.noneOf(NodeEntryField.class);
+ public static final EnumSet<NodeEntryField> VALUE_ONLY = EnumSet.of(VALUE);
+ public static final EnumSet<NodeEntryField> NO_VALUE = EnumSet.of(DIRECT_DEPS, REVERSE_DEPS);
+ public static final EnumSet<NodeEntryField> ALL_FIELDS =
+ EnumSet.of(VALUE, DIRECT_DEPS, REVERSE_DEPS);
+}
diff --git a/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java b/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java
index 1254dbce93..e7674cd622 100644
--- a/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java
+++ b/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java
@@ -56,6 +56,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -221,9 +222,11 @@ public final class ParallelEvaluator implements Evaluator {
this.errorHandler = errorHandler;
}
- /**
- * Receives the events from the NestedSet and delegates to the reporter.
- */
+ private Map<SkyKey, NodeEntry> getBatchValues(Iterable<SkyKey> keys) {
+ return graph.getBatchWithFieldHints(keys, NodeEntryField.VALUE_ONLY);
+ }
+
+ /** Receives the events from the NestedSet and delegates to the reporter. */
private static class NestedSetEventReceiver implements NestedSetVisitor.Receiver<TaggedEvents> {
private final EventHandler reporter;
@@ -329,7 +332,7 @@ public final class ParallelEvaluator implements Evaluator {
keysToPrefetchBuilder.addAll(depKeysAsIterable).addAll(oldDeps);
keysToPrefetch = keysToPrefetchBuilder.build();
}
- Map<SkyKey, NodeEntry> batchMap = graph.getBatch(keysToPrefetch);
+ Map<SkyKey, NodeEntry> batchMap = getBatchValues(keysToPrefetch);
if (PREFETCH_OLD_DEPS) {
batchMap = ImmutableMap.copyOf(
Maps.filterKeys(batchMap, Predicates.in(ImmutableSet.copyOf(depKeysAsIterable))));
@@ -464,7 +467,7 @@ public final class ParallelEvaluator implements Evaluator {
missingKeys.add(key);
}
}
- Map<SkyKey, NodeEntry> missingEntries = graph.getBatch(missingKeys);
+ Map<SkyKey, NodeEntry> missingEntries = getBatchValues(missingKeys);
for (SkyKey key : missingKeys) {
builder.put(key, maybeGetValueFromError(key, missingEntries.get(key), bubbleErrorInfo));
}
@@ -660,7 +663,11 @@ public final class ParallelEvaluator implements Evaluator {
// Remove the rdep on this entry for each of its old deps that is no longer a direct dep.
Set<SkyKey> depsToRemove =
Sets.difference(oldDeps, primaryEntry.getTemporaryDirectDeps().toSet());
- for (NodeEntry oldDepEntry : graph.getBatch(depsToRemove).values()) {
+ for (NodeEntry oldDepEntry :
+ graph
+ .getBatchWithFieldHints(
+ depsToRemove, EnumSet.of(NodeEntryField.INDIVIDUAL_REVERSE_DEPS))
+ .values()) {
oldDepEntry.removeReverseDep(skyKey);
}
}
@@ -916,7 +923,10 @@ public final class ParallelEvaluator implements Evaluator {
// is done, then it is the parent's responsibility to notice that, which we do here.
// We check the deps for errors so that we don't continue building this node if it has
// a child error.
- Map<SkyKey, NodeEntry> entriesToCheck = graph.getBatch(directDepsToCheck);
+ Map<SkyKey, NodeEntry> entriesToCheck =
+ graph.getBatchWithFieldHints(
+ directDepsToCheck,
+ EnumSet.of(NodeEntryField.VALUE, NodeEntryField.INDIVIDUAL_REVERSE_DEPS));
for (Map.Entry<SkyKey, NodeEntry> entry : entriesToCheck.entrySet()) {
if (entry.getValue().isDone() && entry.getValue().getErrorInfo() != null) {
// If any child has an error, we arbitrarily add a dep on the first one (needed
@@ -1021,7 +1031,7 @@ public final class ParallelEvaluator implements Evaluator {
}
}
- Map<SkyKey, NodeEntry> newlyRequestedDeps = graph.getBatch(env.newlyRequestedDeps);
+ Map<SkyKey, NodeEntry> newlyRequestedDeps = getBatchValues(env.newlyRequestedDeps);
boolean isTransitivelyTransient = reifiedBuilderException.isTransient();
for (NodeEntry depEntry
: Iterables.concat(env.directDeps.values(), newlyRequestedDeps.values())) {
@@ -1075,7 +1085,12 @@ public final class ParallelEvaluator implements Evaluator {
skyKey, newDirectDeps, state);
env.setValue(value);
registerNewlyDiscoveredDepsForDoneEntry(
- skyKey, state, graph.getBatch(env.newlyRequestedDeps), oldDeps, env);
+ skyKey,
+ state,
+ graph.getBatchWithFieldHints(
+ env.newlyRequestedDeps, EnumSet.of(NodeEntryField.INDIVIDUAL_REVERSE_DEPS)),
+ oldDeps,
+ env);
env.commit(/*enqueueParents=*/true);
return;
}
@@ -1190,7 +1205,10 @@ public final class ParallelEvaluator implements Evaluator {
*/
private void signalValuesAndEnqueueIfReady(
@Nullable ValueVisitor visitor, Iterable<SkyKey> keys, Version version) {
- Map<SkyKey, NodeEntry> batch = graph.getBatch(keys);
+ // No fields of the entry are needed here, since we're just enqueuing for evaluation, but more
+ // importantly, these hints are not respected for not-done nodes. If they are, we may need to
+ // alter this hint.
+ Map<SkyKey, NodeEntry> batch = graph.getBatchWithFieldHints(keys, NodeEntryField.NO_FIELDS);
if (visitor != null) {
for (SkyKey key : keys) {
NodeEntry entry = Preconditions.checkNotNull(batch.get(key), key);
@@ -1224,13 +1242,13 @@ public final class ParallelEvaluator implements Evaluator {
/**
* Add any additional deps that were registered during the run of a builder that finished by
- * creating a node or throwing an error. Builders may throw errors even if all their deps were
- * not provided -- we trust that a SkyFunction may be know it should throw an error even if not
- * all of its requested deps are done. However, that means we're assuming the SkyFunction would
- * throw that same error if all of its requested deps were done. Unfortunately, there is no way to
+ * creating a node or throwing an error. Builders may throw errors even if all their deps were not
+ * provided -- we trust that a SkyFunction may be know it should throw an error even if not all of
+ * its requested deps are done. However, that means we're assuming the SkyFunction would throw
+ * that same error if all of its requested deps were done. Unfortunately, there is no way to
* enforce that condition.
*/
- private void registerNewlyDiscoveredDepsForDoneEntry(
+ private static void registerNewlyDiscoveredDepsForDoneEntry(
SkyKey skyKey,
NodeEntry entry,
Map<SkyKey, NodeEntry> newlyRequestedDepMap,
@@ -1288,7 +1306,7 @@ public final class ParallelEvaluator implements Evaluator {
// directly without launching the heavy machinery, spawning threads, etc.
// Inform progressReceiver that these nodes are done to be consistent with the main code path.
boolean allAreDone = true;
- Map<SkyKey, NodeEntry> batch = graph.getBatch(skyKeySet);
+ Map<SkyKey, NodeEntry> batch = getBatchValues(skyKeySet);
for (SkyKey key : skyKeySet) {
if (!isDoneForBuild(batch.get(key))) {
allAreDone = false;
@@ -1871,8 +1889,12 @@ public final class ParallelEvaluator implements Evaluator {
continue;
}
// Prefetch all children, in case our graph performs better with a primed cache. No need to
- // recurse into done nodes.
- Map<SkyKey, NodeEntry> childrenNodes = graph.getBatch(children);
+ // recurse into done nodes. The fields of done nodes aren't necessary, since we'll filter them
+ // out.
+ // TODO(janakr): If graph implementations start using these hints for not-done nodes, we may
+ // have to change this.
+ Map<SkyKey, NodeEntry> childrenNodes =
+ graph.getBatchWithFieldHints(children, NodeEntryField.NO_FIELDS);
Preconditions.checkState(childrenNodes.size() == Iterables.size(children), childrenNodes);
children = Maps.filterValues(childrenNodes, new Predicate<NodeEntry>() {
@Override
@@ -1930,7 +1952,7 @@ public final class ParallelEvaluator implements Evaluator {
*/
private List<ErrorInfo> getChildrenErrors(Iterable<SkyKey> children, SkyKey unfinishedChild) {
List<ErrorInfo> allErrors = new ArrayList<>();
- for (Entry<SkyKey, NodeEntry> childMapEntry : graph.getBatch(children).entrySet()) {
+ for (Entry<SkyKey, NodeEntry> childMapEntry : getBatchValues(children).entrySet()) {
SkyKey childKey = childMapEntry.getKey();
NodeEntry childNodeEntry = childMapEntry.getValue();
ErrorInfo errorInfo = getErrorMaybe(childKey, childNodeEntry,
@@ -2033,7 +2055,7 @@ public final class ParallelEvaluator implements Evaluator {
}
private Map<SkyKey, NodeEntry> getAndCheckDoneBatch(Iterable<SkyKey> keys) {
- Map<SkyKey, NodeEntry> nodes = graph.getBatch(keys);
+ Map<SkyKey, NodeEntry> nodes = getBatchValues(keys);
for (Map.Entry<SkyKey, NodeEntry> nodeEntryMapEntry : nodes.entrySet()) {
checkDone(nodeEntryMapEntry.getKey(), nodeEntryMapEntry.getValue());
}
@@ -2042,7 +2064,7 @@ public final class ParallelEvaluator implements Evaluator {
private static final SkyValue NULL_MARKER = new SkyValue() {};
- private SkyValue maybeGetValueFromError(
+ private static SkyValue maybeGetValueFromError(
SkyKey key,
@Nullable NodeEntry entry,
@Nullable Map<SkyKey, ValueWithMetadata> bubbleErrorInfo) {
@@ -2056,11 +2078,11 @@ public final class ParallelEvaluator implements Evaluator {
}
/**
- * Return true if the entry does not need to be re-evaluated this build. The entry will need to
- * be re-evaluated if it is not done, but also if it was not completely evaluated last build and
- * this build is keepGoing.
+ * Return true if the entry does not need to be re-evaluated this build. The entry will need to be
+ * re-evaluated if it is not done, but also if it was not completely evaluated last build and this
+ * build is keepGoing.
*/
- private boolean isDoneForBuild(@Nullable NodeEntry entry) {
+ private static boolean isDoneForBuild(@Nullable NodeEntry entry) {
return entry != null && entry.isDone();
}
diff --git a/src/main/java/com/google/devtools/build/skyframe/QueryableGraph.java b/src/main/java/com/google/devtools/build/skyframe/QueryableGraph.java
index 04198286d8..27038021fe 100644
--- a/src/main/java/com/google/devtools/build/skyframe/QueryableGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/QueryableGraph.java
@@ -15,6 +15,7 @@ package com.google.devtools.build.skyframe;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import java.util.EnumSet;
import java.util.Map;
import javax.annotation.Nullable;
@@ -27,9 +28,13 @@ public interface QueryableGraph {
NodeEntry get(SkyKey key);
/**
- * Fetches all the given nodes. Returns a map {@code m} such that, for all {@code k} in
- * {@code keys}, {@code m.get(k).equals(e)} iff {@code get(k) == e} and {@code e != null}, and
- * {@code !m.containsKey(k)} iff {@code get(k) == null}.
+ * Fetches all the given nodes. Returns a map {@code m} such that, for all {@code k} in {@code
+ * keys}, {@code m.get(k).equals(e)} iff {@code get(k) == e} and {@code e != null}, and {@code
+ * !m.containsKey(k)} iff {@code get(k) == null}. The {@code fields} parameter is a hint to the
+ * QueryableGraph implementation that allows it to possibly construct certain fields of the
+ * returned node entries more lazily. Hints may only be applied to nodes in a certain state, like
+ * done nodes.
*/
- Map<SkyKey, NodeEntry> getBatch(Iterable<SkyKey> keys);
+ Map<SkyKey, NodeEntry> getBatchWithFieldHints(
+ Iterable<SkyKey> keys, EnumSet<NodeEntryField> fields);
}
diff --git a/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java b/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java
index c9d33a4867..ed38be387e 100644
--- a/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java
+++ b/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java
@@ -70,7 +70,8 @@ public class QueryableGraphBackedSkyFunctionEnvironment extends AbstractSkyFunct
@Override
protected Map<SkyKey, ValueOrUntypedException> getValueOrUntypedExceptions(Set<SkyKey> depKeys) {
- Map<SkyKey, NodeEntry> resultMap = queryableGraph.getBatch(depKeys);
+ Map<SkyKey, NodeEntry> resultMap =
+ queryableGraph.getBatchWithFieldHints(depKeys, NodeEntryField.VALUE_ONLY);
Map<SkyKey, NodeEntry> resultWithMissingKeys = new HashMap<>(resultMap);
for (SkyKey missingDep : Sets.difference(depKeys, resultMap.keySet())) {
resultWithMissingKeys.put(missingDep, null);
diff --git a/src/test/java/com/google/devtools/build/skyframe/DeterministicHelper.java b/src/test/java/com/google/devtools/build/skyframe/DeterministicHelper.java
index 655333af08..50bd380ed7 100644
--- a/src/test/java/com/google/devtools/build/skyframe/DeterministicHelper.java
+++ b/src/test/java/com/google/devtools/build/skyframe/DeterministicHelper.java
@@ -17,6 +17,7 @@ import com.google.common.collect.Iterables;
import java.util.Collection;
import java.util.Comparator;
+import java.util.EnumSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
@@ -115,8 +116,9 @@ public class DeterministicHelper extends NotifyingHelper {
}
@Override
- public Map<SkyKey, NodeEntry> getBatch(Iterable<SkyKey> keys) {
- return makeDeterministic(super.getBatch(keys));
+ public Map<SkyKey, NodeEntry> getBatchWithFieldHints(
+ Iterable<SkyKey> keys, EnumSet<NodeEntryField> fields) {
+ return makeDeterministic(super.getBatchWithFieldHints(keys, fields));
}
}
diff --git a/src/test/java/com/google/devtools/build/skyframe/DeterministicInMemoryGraph.java b/src/test/java/com/google/devtools/build/skyframe/DeterministicInMemoryGraph.java
index a0233838ec..bb61d0f202 100644
--- a/src/test/java/com/google/devtools/build/skyframe/DeterministicInMemoryGraph.java
+++ b/src/test/java/com/google/devtools/build/skyframe/DeterministicInMemoryGraph.java
@@ -27,6 +27,11 @@ class DeterministicInMemoryGraph extends DeterministicHelper.DeterministicProces
}
@Override
+ public Map<SkyKey, NodeEntry> getBatch(Iterable<SkyKey> keys) {
+ return getBatchWithFieldHints(keys, NodeEntryField.ALL_FIELDS);
+ }
+
+ @Override
public Map<SkyKey, SkyValue> getValues() {
return ((InMemoryGraph) delegate).getValues();
}
diff --git a/src/test/java/com/google/devtools/build/skyframe/GraphConcurrencyTest.java b/src/test/java/com/google/devtools/build/skyframe/GraphConcurrencyTest.java
index a0580e2479..73e42ea4d7 100644
--- a/src/test/java/com/google/devtools/build/skyframe/GraphConcurrencyTest.java
+++ b/src/test/java/com/google/devtools/build/skyframe/GraphConcurrencyTest.java
@@ -275,8 +275,9 @@ public abstract class GraphConcurrencyTest {
}
/**
- * Initially calling {@link NodeEntry#setValue} and then making sure concurrent calls to
- * {@link QueryableGraph#get} and {@link QueryableGraph#getBatch} do not interfere with the node.
+ * Initially calling {@link NodeEntry#setValue} and then making sure concurrent calls to {@link
+ * QueryableGraph#get} and {@link QueryableGraph#getBatchWithFieldHints} do not interfere with the
+ * node.
*/
@Test
public void testDoneToDirty() throws Exception {
@@ -377,15 +378,16 @@ public abstract class GraphConcurrencyTest {
} catch (InterruptedException e) {
throw new AssertionError(e);
}
- Map<SkyKey, NodeEntry> batchMap = graph.getBatch(batch);
+ Map<SkyKey, NodeEntry> batchMap =
+ graph.getBatchWithFieldHints(batch, NodeEntryField.NO_FIELDS);
getBatchCountDownLatch.countDown();
assertThat(batchMap).hasSize(batch.size());
for (NodeEntry entry : batchMap.values()) {
// Batch requests are made at the same time that the version increments from the
// base. Check that there is no problem in requesting the version and that the
// number is sane.
- assertThat(entry.getVersion()).isAnyOf(startingVersion,
- getNextVersion(startingVersion));
+ assertThat(entry.getVersion())
+ .isAnyOf(startingVersion, getNextVersion(startingVersion));
}
}
};
diff --git a/src/test/java/com/google/devtools/build/skyframe/NotifyingHelper.java b/src/test/java/com/google/devtools/build/skyframe/NotifyingHelper.java
index 2f973b5bcd..711e9e7b2d 100644
--- a/src/test/java/com/google/devtools/build/skyframe/NotifyingHelper.java
+++ b/src/test/java/com/google/devtools/build/skyframe/NotifyingHelper.java
@@ -20,6 +20,7 @@ import com.google.common.collect.Maps.EntryTransformer;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.util.GroupedList;
+import java.util.EnumSet;
import java.util.Map;
import java.util.Set;
@@ -121,8 +122,10 @@ public class NotifyingHelper {
}
@Override
- public Map<SkyKey, NodeEntry> getBatch(Iterable<SkyKey> keys) {
- return Maps.transformEntries(delegate.getBatch(keys), notifyingHelper.wrapEntry);
+ public Map<SkyKey, NodeEntry> getBatchWithFieldHints(
+ Iterable<SkyKey> keys, EnumSet<NodeEntryField> fields) {
+ return Maps.transformEntries(
+ delegate.getBatchWithFieldHints(keys, fields), notifyingHelper.wrapEntry);
}
@Nullable
diff --git a/src/test/java/com/google/devtools/build/skyframe/NotifyingInMemoryGraph.java b/src/test/java/com/google/devtools/build/skyframe/NotifyingInMemoryGraph.java
index 752dac7001..1689440b79 100644
--- a/src/test/java/com/google/devtools/build/skyframe/NotifyingInMemoryGraph.java
+++ b/src/test/java/com/google/devtools/build/skyframe/NotifyingInMemoryGraph.java
@@ -23,6 +23,11 @@ class NotifyingInMemoryGraph extends NotifyingHelper.NotifyingProcessableGraph
}
@Override
+ public Map<SkyKey, NodeEntry> getBatch(Iterable<SkyKey> keys) {
+ return getBatchWithFieldHints(keys, NodeEntryField.ALL_FIELDS);
+ }
+
+ @Override
public Map<SkyKey, SkyValue> getValues() {
return ((InMemoryGraph) delegate).getValues();
}