Clean up `createRecursiveTraversalKeys` with pre-sizing, immutability and SkyKey Type. Then merge `createRecursiveTraversalKeys` into `traverseChildren` to be clearer.

PiperOrigin-RevId: 436882926
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
index 972c15a..143931f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -1999,6 +1999,7 @@
         ":action_execution_value",
         ":detailed_exceptions",
         ":directory_listing_value",
+        ":dirents",
         ":package_lookup_value",
         ":sky_functions",
         ":tree_artifact_value",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
index ed943ef..b723829 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
@@ -20,6 +20,7 @@
 import com.google.common.base.Verify;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
 import com.google.devtools.build.lib.actions.FileArtifactValue;
@@ -64,7 +65,6 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import javax.annotation.Nullable;
@@ -230,12 +230,8 @@
       }
 
       // We are free to traverse this directory.
-      Collection<SkyKey> dependentKeys = createRecursiveTraversalKeys(env, traversal);
-      if (dependentKeys == null) {
-        return null;
-      }
       Collection<RecursiveFilesystemTraversalValue> subdirTraversals =
-          traverseChildren(env, dependentKeys, /*inline=*/ traversal.isRootGenerated);
+          traverseChildren(env, traversal);
       if (subdirTraversals == null) {
         return null;
       }
@@ -563,55 +559,13 @@
   }
 
   /**
-   * List the directory and create {@code SkyKey}s to request contents of its children recursively.
-   *
-   * <p>The returned keys are of type {@link SkyFunctions#RECURSIVE_FILESYSTEM_TRAVERSAL}.
-   */
-  @Nullable
-  private static Collection<SkyKey> createRecursiveTraversalKeys(
-      Environment env, TraversalRequest traversal) throws InterruptedException, IOException {
-    // Use the traversal's path, even if it's a symlink. The contents of the directory, as listed
-    // in the result, must be relative to it.
-    Iterable<Dirent> dirents;
-    if (traversal.isRootGenerated) {
-      // If we're dealing with an output file, read the directory directly instead of creating
-      // filesystem nodes under the output tree.
-      List<Dirent> direntsCollection =
-          new ArrayList<>(
-              traversal.root.asRootedPath().asPath().readdir(Symlinks.FOLLOW));
-      Collections.sort(direntsCollection);
-      dirents = direntsCollection;
-    } else {
-      DirectoryListingValue dirListingValue =
-          (DirectoryListingValue)
-              env.getValueOrThrow(
-                  DirectoryListingValue.key(traversal.root.asRootedPath()), IOException.class);
-      if (dirListingValue == null) {
-        return null;
-      }
-      dirents = dirListingValue.getDirents();
-    }
-
-    List<SkyKey> result = new ArrayList<>();
-    for (Dirent dirent : dirents) {
-      RootedPath childPath =
-          RootedPath.toRootedPath(
-              traversal.root.asRootedPath().getRoot(),
-              traversal.root.asRootedPath().getRootRelativePath().getRelative(dirent.getName()));
-      TraversalRequest childTraversal = traversal.forChildEntry(childPath);
-      result.add(childTraversal);
-    }
-    return result;
-  }
-
-  /**
    * Creates result for a dangling symlink.
    *
    * @param linkName path to the symbolic link
    * @param info the {@link FileInfo} associated with the link file
    */
-  private static RecursiveFilesystemTraversalValue resultForDanglingSymlink(RootedPath linkName,
-      FileInfo info) {
+  private static RecursiveFilesystemTraversalValue resultForDanglingSymlink(
+      RootedPath linkName, FileInfo info) {
     Preconditions.checkState(info.type.isSymlink() && !info.type.exists(), "{%s} {%s}", linkName,
         info.type);
     return RecursiveFilesystemTraversalValue.of(
@@ -638,8 +592,10 @@
     }
   }
 
-  private static RecursiveFilesystemTraversalValue resultForDirectory(TraversalRequest traversal,
-      FileInfo rootInfo, Collection<RecursiveFilesystemTraversalValue> subdirTraversals) {
+  private static RecursiveFilesystemTraversalValue resultForDirectory(
+      TraversalRequest traversal,
+      FileInfo rootInfo,
+      Collection<RecursiveFilesystemTraversalValue> subdirTraversals) {
     // Collect transitive closure of files in subdirectories.
     NestedSetBuilder<ResolvedFile> paths = NestedSetBuilder.stableOrder();
     for (RecursiveFilesystemTraversalValue child : subdirTraversals) {
@@ -677,22 +633,56 @@
     return new HasDigest.ByteStringDigest(result);
   }
 
-  /**
-   * Requests Skyframe to compute the dependent values and returns them.
-   *
-   * <p>The keys must all be {@link SkyFunctions#RECURSIVE_FILESYSTEM_TRAVERSAL} keys.
-   */
+  /** Requests Skyframe to compute the dependent values and returns them. */
   @Nullable
   private Collection<RecursiveFilesystemTraversalValue> traverseChildren(
-      Environment env, Iterable<SkyKey> keys, boolean inline)
-      throws InterruptedException, RecursiveFilesystemTraversalFunctionException {
-    Map<SkyKey, SkyValue> values;
-    if (inline) {
+      Environment env, TraversalRequest traversal)
+      throws InterruptedException, RecursiveFilesystemTraversalFunctionException, IOException {
+    // Use the traversal's path, even if it's a symlink. The contents of the directory, as listed
+    // in the result, must be relative to it.
+    Iterable<Dirent> direntsIterable;
+    int direntsSize;
+    if (traversal.isRootGenerated) {
+      // If we're dealing with an output file, read the directory directly instead of creating
+      // filesystem nodes under the output tree.
+      List<Dirent> direntsCollection =
+          new ArrayList<>(traversal.root.asRootedPath().asPath().readdir(Symlinks.FOLLOW));
+      Collections.sort(direntsCollection);
+      direntsIterable = direntsCollection;
+      direntsSize = direntsCollection.size();
+    } else {
+      DirectoryListingValue dirListingValue =
+          (DirectoryListingValue)
+              env.getValueOrThrow(
+                  DirectoryListingValue.key(traversal.root.asRootedPath()), IOException.class);
+      if (dirListingValue == null) {
+        return null;
+      }
+      Dirents dirents = dirListingValue.getDirents();
+      direntsSize = dirents.size();
+      direntsIterable = dirents;
+    }
+
+    ImmutableList.Builder<TraversalRequest> keysBuilder =
+        ImmutableList.builderWithExpectedSize(direntsSize);
+    for (Dirent dirent : direntsIterable) {
+      RootedPath childPath =
+          RootedPath.toRootedPath(
+              traversal.root.asRootedPath().getRoot(),
+              traversal.root.asRootedPath().getRootRelativePath().getRelative(dirent.getName()));
+      TraversalRequest childTraversal = traversal.forChildEntry(childPath);
+      keysBuilder.add(childTraversal);
+    }
+    ImmutableList<TraversalRequest> keys = keysBuilder.build();
+    if (keys == null) {
+      return null;
+    }
+    Map<SkyKey, SkyValue> values = Maps.newHashMapWithExpectedSize(keys.size());
+    if (traversal.isRootGenerated) {
       // Don't create Skyframe nodes for a recursive traversal over the output tree.
       // Instead, inline the recursion in the top-level request.
-      values = new HashMap<>();
-      for (SkyKey depKey : keys) {
-        values.put(depKey, compute(depKey, env));
+      for (TraversalRequest traversalRequest : keys) {
+        values.put(traversalRequest, compute(traversalRequest, env));
       }
     } else {
       values = env.getValues(keys);