Remove WalkableGraph#exists and allow WalkableGraph#getValue and WalkableGraph#getException to be given non-existent keys without crashing. Add WalkableGraph#isCycle to fill the gap in testing for the difference between non-existence and depending on a cycle.
--
PiperOrigin-RevId: 143205289
MOS_MIGRATED_REVID=143205289
diff --git a/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java b/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java
index 3d7796b..8f3dd04 100644
--- a/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java
@@ -30,17 +30,17 @@
*/
@ThreadSafe
public interface WalkableGraph {
-
- /**
- * Returns whether the given key exists as a done node in the graph. If there is a chance that the
- * given node does not exist, this method should be called before any others, since the others
- * throw a {@link RuntimeException} on failure to access a node.
- */
- boolean exists(SkyKey key) throws InterruptedException;
-
/**
* Returns the value of the given key, or {@code null} if it has no value due to an error during
- * its computation. A node with this key must exist in the graph.
+ * its computation or it is not done in the graph.
+ *
+ * <p>A node that is done in the graph must have either a non-null getValue, a non-null {@link
+ * #getException}, or a true {@link #isCycle}.
+ *
+ * <p>These three methods should all be reading the same {@link
+ * NodeEntry#getValueMaybeWithMetadata} value internally, so once that value is indirectly
+ * retrieved via one of these methods, the others can read it for free. This is relevant for graph
+ * implementations that may throw an {@link InterruptedException} on retrieving entries and value.
*/
@Nullable
SkyValue getValue(SkyKey key) throws InterruptedException;
@@ -63,21 +63,27 @@
/**
* Returns the exception thrown when computing the node with the given key, if any. If the node
- * was computed successfully, returns null. A node with this key must exist and be done in the
- * graph.
+ * was computed successfully, depends on a cycle without any other error, or is not done in the
+ * graph, returns null.
*/
@Nullable
Exception getException(SkyKey key) throws InterruptedException;
/**
+ * Returns true if the node with the given {@code key} depends on a cycle. Returns false if the
+ * node does not depend on a cycle, or is not done in the graph.
+ */
+ boolean isCycle(SkyKey key) throws InterruptedException;
+
+ /**
* Returns a map giving the direct dependencies of the nodes with the given keys. A node for each
- * given key must exist and be done in the graph.
+ * given key must be done in the graph if it exists.
*/
Map<SkyKey, Iterable<SkyKey>> getDirectDeps(Iterable<SkyKey> keys) throws InterruptedException;
/**
* Returns a map giving the reverse dependencies of the nodes with the given keys. A node for each
- * given key must exist and be done in the graph.
+ * given key must be done in the graph if it exists.
*/
Map<SkyKey, Iterable<SkyKey>> getReverseDeps(Iterable<SkyKey> keys) throws InterruptedException;