Add WalkableGraph#getValueAndRdeps that allows fetching both the rdeps and value in a single call

PiperOrigin-RevId: 253145392
diff --git a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
index 7b944d3..299d95f 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
@@ -878,6 +878,9 @@
 
   @Override
   public Map<Label, Target> getTargets(Iterable<Label> labels) throws InterruptedException {
+    if (Iterables.isEmpty(labels)) {
+      return ImmutableMap.of();
+    }
     Multimap<PackageIdentifier, Label> packageIdToLabelMap = ArrayListMultimap.create();
     labels.forEach(label -> packageIdToLabelMap.put(label.getPackageIdentifier(), label));
     Map<PackageIdentifier, Package> packageIdToPackageMap =
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 530cb2b..96bdb7e 100644
--- a/src/main/java/com/google/devtools/build/skyframe/DelegatingWalkableGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/DelegatingWalkableGraph.java
@@ -16,6 +16,7 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
+import com.google.devtools.build.lib.util.Pair;
 import com.google.devtools.build.skyframe.QueryableGraph.Reason;
 import java.util.HashMap;
 import java.util.Map;
@@ -44,7 +45,7 @@
     return entry == null ? null : entry.getValue();
   }
 
-  private static SkyValue getValue(NodeEntry entry) throws InterruptedException {
+  private static SkyValue getValueFromNodeEntry(NodeEntry entry) throws InterruptedException {
     return entry.isDone() ? entry.getValue() : null;
   }
 
@@ -54,7 +55,7 @@
     Map<SkyKey, ? extends NodeEntry> batchGet = getBatch(null, Reason.WALKABLE_GRAPH_VALUE, keys);
     Map<SkyKey, SkyValue> result = Maps.newHashMapWithExpectedSize(batchGet.size());
     for (Map.Entry<SkyKey, ? extends NodeEntry> entryPair : batchGet.entrySet()) {
-      SkyValue value = getValue(entryPair.getValue());
+      SkyValue value = getValueFromNodeEntry(entryPair.getValue());
       if (value != null) {
         result.put(entryPair.getKey(), value);
       }
@@ -140,4 +141,22 @@
       throws InterruptedException {
     return graph.getBatch(requestor, reason, keys);
   }
+
+  @Override
+  public Map<SkyKey, Pair<SkyValue, Iterable<SkyKey>>> getValueAndRdeps(Iterable<SkyKey> keys)
+      throws InterruptedException {
+    Map<SkyKey, ? extends NodeEntry> entries =
+        getBatch(null, Reason.WALKABLE_GRAPH_VALUE_AND_RDEPS, keys);
+    Map<SkyKey, Pair<SkyValue, Iterable<SkyKey>>> result =
+        Maps.newHashMapWithExpectedSize(entries.size());
+    for (Map.Entry<SkyKey, ? extends NodeEntry> entry : entries.entrySet()) {
+      Preconditions.checkState(entry.getValue().isDone(), entry);
+      result.put(
+          entry.getKey(),
+          Pair.of(
+              getValueFromNodeEntry(entry.getValue()),
+              entry.getValue().getReverseDepsForDoneEntry()));
+    }
+    return result;
+  }
 }
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 d3a0c43..e56787a 100644
--- a/src/main/java/com/google/devtools/build/skyframe/QueryableGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/QueryableGraph.java
@@ -162,13 +162,17 @@
     /** The node is being looked up to service {@link WalkableGraph#getReverseDeps}. */
     WALKABLE_GRAPH_RDEPS,
 
+    /** The node is being looked up to service {@link WalkableGraph#getValueAndRdeps}. */
+    WALKABLE_GRAPH_VALUE_AND_RDEPS,
+
     /** Some other reason than one of the above. */
     OTHER;
 
     public boolean isWalkable() {
       return this == WALKABLE_GRAPH_VALUE
           || this == WALKABLE_GRAPH_DEPS
-          || this == WALKABLE_GRAPH_RDEPS;
+          || this == WALKABLE_GRAPH_RDEPS
+          || this == WALKABLE_GRAPH_VALUE_AND_RDEPS;
     }
   }
 
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 016f4ac..a195836 100644
--- a/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.skyframe;
 
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.lib.util.Pair;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
@@ -92,6 +93,13 @@
    */
   Map<SkyKey, Iterable<SkyKey>> getReverseDeps(Iterable<SkyKey> keys) throws InterruptedException;
 
+  /**
+   * Returns a map giving the reverse dependencies of the nodes with the given keys as well as the
+   * value
+   */
+  Map<SkyKey, Pair<SkyValue, Iterable<SkyKey>>> getValueAndRdeps(Iterable<SkyKey> keys)
+      throws InterruptedException;
+
   /** Provides a WalkableGraph on demand after preparing it. */
   interface WalkableGraphFactory {
     EvaluationResult<SkyValue> prepareAndGet(Set<SkyKey> roots, EvaluationContext evaluationContext)