Add method getCurrentlyAvailableNodes to QueryableGraph and Walkable Graph

It allows all graph implementations to return the list of nodes which are
immediately available to be fetched. NOTE: Not-currently-available here does
not mean the nodes do not exist in the graph. It simply means they are not
ready to be fetched immediately yet.

--
MOS_MIGRATED_REVID=137701432
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 5c22a05..27475db 100644
--- a/src/main/java/com/google/devtools/build/skyframe/DelegatingWalkableGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/DelegatingWalkableGraph.java
@@ -126,4 +126,9 @@
     return result;
   }
 
+  @Override
+  public Iterable<SkyKey> getCurrentlyAvailableNodes(Iterable<SkyKey> keys, Reason reason) {
+    return graph.getCurrentlyAvailableNodes(keys, reason);
+  }
+
 }
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 77b1259..71c3ad3 100644
--- a/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java
+++ b/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java
@@ -17,6 +17,7 @@
 import com.google.common.base.Function;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.MapMaker;
 import com.google.common.collect.Maps;
 import java.util.Collections;
@@ -127,4 +128,15 @@
   boolean keepsEdges() {
     return keepEdges;
   }
+
+  @Override
+  public Iterable<SkyKey> getCurrentlyAvailableNodes(Iterable<SkyKey> keys, Reason reason) {
+    ImmutableSet.Builder<SkyKey> builder = ImmutableSet.builder();
+    for (SkyKey key : keys) {
+      if (get(null, reason, key) != null) {
+        builder.add(key);
+      }
+    }
+    return builder.build();
+  }
 }
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 0286844..7c4971e 100644
--- a/src/main/java/com/google/devtools/build/skyframe/QueryableGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/QueryableGraph.java
@@ -49,6 +49,17 @@
       @Nullable SkyKey requestor, Reason reason, Iterable<SkyKey> keys) throws InterruptedException;
 
   /**
+   * Examines all the given keys. Returns an iterable of keys whose corresponding nodes are
+   * currently available to be fetched.
+   *
+   * <p>Note: An unavailable node does not mean it is not in the graph. It only means it's not ready
+   * to be fetched immediately.
+   *
+   * @param reason the reason the nodes are being requested.
+   */
+  Iterable<SkyKey> getCurrentlyAvailableNodes(Iterable<SkyKey> keys, Reason reason);
+
+  /**
    * The reason that a node is being looked up in the Skyframe graph.
    *
    * <p>Alternate graph implementations may wish to make use of this information.
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 9f71f1f..240ea7c 100644
--- a/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java
@@ -15,6 +15,7 @@
 
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.skyframe.QueryableGraph.Reason;
 import java.util.Collection;
 import java.util.Map;
 import javax.annotation.Nullable;
@@ -80,6 +81,15 @@
    */
   Map<SkyKey, Iterable<SkyKey>> getReverseDeps(Iterable<SkyKey> keys) throws InterruptedException;
 
+  /**
+   * Examines all the given keys. Returns an iterable of keys whose corresponding nodes are
+   * currently available to be fetched.
+   *
+   * <p>Note: An unavailable node does not mean it is not in the graph. It only means it's not ready
+   * to be fetched immediately.
+   */
+  Iterable<SkyKey> getCurrentlyAvailableNodes(Iterable<SkyKey> keys, Reason reason);
+
   /** Provides a WalkableGraph on demand after preparing it. */
   interface WalkableGraphFactory {
     EvaluationResult<SkyValue> prepareAndGet(Collection<String> roots, String offset,
diff --git a/src/test/java/com/google/devtools/build/skyframe/GraphConcurrencyTest.java b/src/test/java/com/google/devtools/build/skyframe/GraphTest.java
similarity index 96%
rename from src/test/java/com/google/devtools/build/skyframe/GraphConcurrencyTest.java
rename to src/test/java/com/google/devtools/build/skyframe/GraphTest.java
index 6490835..0510523 100644
--- a/src/test/java/com/google/devtools/build/skyframe/GraphConcurrencyTest.java
+++ b/src/test/java/com/google/devtools/build/skyframe/GraphTest.java
@@ -43,8 +43,8 @@
 import org.junit.Before;
 import org.junit.Test;
 
-/** Base class for concurrency sanity tests on {@link EvaluableGraph} implementations. */
-public abstract class GraphConcurrencyTest {
+/** Base class for sanity tests on {@link EvaluableGraph} implementations. */
+public abstract class GraphTest {
 
   private static final SkyFunctionName SKY_FUNCTION_NAME = SkyFunctionName.FOR_TESTING;
   protected ProcessableGraph graph;
@@ -154,8 +154,9 @@
   @Test
   public void testAddRemoveRdeps() throws Exception {
     SkyKey key = key("foo");
-    final NodeEntry entry = Iterables.getOnlyElement(
-        graph.createIfAbsentBatch(null, Reason.OTHER, ImmutableList.of(key)).values());
+    final NodeEntry entry =
+        Iterables.getOnlyElement(
+            graph.createIfAbsentBatch(null, Reason.OTHER, ImmutableList.of(key)).values());
     // These numbers are arbitrary.
     int numThreads = 50;
     int numKeys = numThreads;
@@ -459,6 +460,19 @@
     }
   }
 
+  @Test
+  public void testGetCurrentlyAvailableNodes() throws Exception {
+    SkyKey foo = key("foo");
+    SkyKey bar = key("bar");
+    SkyKey foobar = key("foobar");
+    graph.createIfAbsentBatch(null, Reason.OTHER, ImmutableList.of(foo, bar));
+
+    Iterable<SkyKey> currentlyAvailable =
+        graph.getCurrentlyAvailableNodes(ImmutableList.of(foo, bar, foobar), Reason.OTHER);
+
+    assertThat(currentlyAvailable).containsExactly(foo, bar);
+  }
+
   private static DependencyState startEvaluation(NodeEntry entry) throws InterruptedException {
     return entry.addReverseDepAndCheckIfDone(null);
   }
diff --git a/src/test/java/com/google/devtools/build/skyframe/InMemoryGraphConcurrencyTest.java b/src/test/java/com/google/devtools/build/skyframe/InMemoryGraphTest.java
similarity index 90%
rename from src/test/java/com/google/devtools/build/skyframe/InMemoryGraphConcurrencyTest.java
rename to src/test/java/com/google/devtools/build/skyframe/InMemoryGraphTest.java
index 18d6875..0180391 100644
--- a/src/test/java/com/google/devtools/build/skyframe/InMemoryGraphConcurrencyTest.java
+++ b/src/test/java/com/google/devtools/build/skyframe/InMemoryGraphTest.java
@@ -14,13 +14,12 @@
 package com.google.devtools.build.skyframe;
 
 import com.google.devtools.build.lib.util.Preconditions;
-
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-/** Concurrency tests for {@link InMemoryGraphImpl}. */
+/** Tests for {@link InMemoryGraphImpl}. */
 @RunWith(JUnit4.class)
-public class InMemoryGraphConcurrencyTest extends GraphConcurrencyTest {
+public class InMemoryGraphTest extends GraphTest {
   private ProcessableGraph graph;
 
   @Override
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 6cde573..559b3cf 100644
--- a/src/test/java/com/google/devtools/build/skyframe/NotifyingHelper.java
+++ b/src/test/java/com/google/devtools/build/skyframe/NotifyingHelper.java
@@ -100,6 +100,11 @@
         throws InterruptedException {
       return notifyingHelper.wrapEntry(key, delegate.get(requestor, reason, key));
     }
+
+    @Override
+    public Iterable<SkyKey> getCurrentlyAvailableNodes(Iterable<SkyKey> keys, Reason reason) {
+      return delegate.getCurrentlyAvailableNodes(keys, reason);
+    }
   }
 
   static class NotifyingProcessableGraph