Drop loading-phase values if --discard_analysis_cache is true and we're not keeping incremental state.

PiperOrigin-RevId: 151639711
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
index 61defac..e48991b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
@@ -63,6 +63,7 @@
 import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator;
 import com.google.devtools.build.skyframe.Injectable;
 import com.google.devtools.build.skyframe.MemoizingEvaluator.EvaluatorSupplier;
+import com.google.devtools.build.skyframe.NodeEntry;
 import com.google.devtools.build.skyframe.RecordingDifferencer;
 import com.google.devtools.build.skyframe.SequentialBuildDriver;
 import com.google.devtools.build.skyframe.SkyFunction;
@@ -75,6 +76,7 @@
 import java.util.Collection;
 import java.util.EnumSet;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -595,15 +597,26 @@
     recordingDiffer.invalidate(dirtyActionValues);
   }
 
+  private static ImmutableSet<SkyFunctionName> LOADING_TYPES =
+      ImmutableSet.of(
+          SkyFunctions.PACKAGE,
+          SkyFunctions.SKYLARK_IMPORTS_LOOKUP,
+          SkyFunctions.AST_FILE_LOOKUP,
+          SkyFunctions.GLOB);
+
   /**
    * Save memory by removing references to configured targets and aspects in Skyframe.
    *
-   * <p>These values must be recreated on subsequent builds. We do not clear the top-level target
-   * values, since their configured targets are needed for the target completion middleman values.
+   * <p>These nodes must be recreated on subsequent builds. We do not clear the top-level target
+   * nodes, since their configured targets are needed for the target completion middleman values.
    *
-   * <p>The values are not deleted during this method call, because they are needed for the
-   * execution phase. Instead, their data is cleared. The next build will delete the values (and
-   * recreate them if necessary).
+   * <p>The nodes are not deleted during this method call, because they are needed for the execution
+   * phase. Instead, their analysis-time data is cleared while preserving the generating action info
+   * needed for execution. The next build will delete the nodes (and recreate them if necessary).
+   *
+   * <p>If {@link #hasIncrementalState} is false, then also delete loading-phase nodes (as
+   * determined by {@link #LOADING_TYPES}) from the graph, since there will be no future builds to
+   * use them for.
    */
   private void discardAnalysisCache(
       Collection<ConfiguredTarget> topLevelTargets, Collection<AspectValue> topLevelAspects) {
@@ -611,16 +624,38 @@
     topLevelAspects = ImmutableSet.copyOf(topLevelAspects);
     try (AutoProfiler p = AutoProfiler.logged("discarding analysis cache", LOG)) {
       lastAnalysisDiscarded = true;
-      for (Map.Entry<SkyKey, SkyValue> entry : memoizingEvaluator.getValues().entrySet()) {
-        SkyFunctionName functionName = entry.getKey().functionName();
+      Iterator<? extends Map.Entry<SkyKey, ? extends NodeEntry>> it =
+          memoizingEvaluator.getGraphMap().entrySet().iterator();
+      while (it.hasNext()) {
+        Map.Entry<SkyKey, ? extends NodeEntry> keyAndEntry = it.next();
+        NodeEntry entry = keyAndEntry.getValue();
+        if (entry == null || !entry.isDone()) {
+          continue;
+        }
+        SkyKey key = keyAndEntry.getKey();
+        SkyFunctionName functionName = key.functionName();
+        if (!hasIncrementalState() && LOADING_TYPES.contains(functionName)) {
+          it.remove();
+          continue;
+        }
         if (functionName.equals(SkyFunctions.CONFIGURED_TARGET)) {
-          ConfiguredTargetValue ctValue = (ConfiguredTargetValue) entry.getValue();
+          ConfiguredTargetValue ctValue;
+          try {
+            ctValue = (ConfiguredTargetValue) entry.getValue();
+          } catch (InterruptedException e) {
+            throw new IllegalStateException("No interruption in sequenced evaluation", e);
+          }
           // ctValue may be null if target was not successfully analyzed.
           if (ctValue != null) {
             ctValue.clear(!topLevelTargets.contains(ctValue.getConfiguredTarget()));
           }
         } else if (functionName.equals(SkyFunctions.ASPECT)) {
-          AspectValue aspectValue = (AspectValue) entry.getValue();
+          AspectValue aspectValue;
+          try {
+            aspectValue = (AspectValue) entry.getValue();
+          } catch (InterruptedException e) {
+            throw new IllegalStateException("No interruption in sequenced evaluation", e);
+          }
           // value may be null if target was not successfully analyzed.
           if (aspectValue != null) {
             aspectValue.clear(!topLevelAspects.contains(aspectValue));
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 edb80f0..82ddb17 100644
--- a/src/main/java/com/google/devtools/build/skyframe/InMemoryGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/InMemoryGraph.java
@@ -44,4 +44,6 @@
 
   // Only for use by MemoizingEvaluator#delete
   Map<SkyKey, ? extends NodeEntry> getAllValues();
+
+  Map<SkyKey, ? extends NodeEntry> getAllValuesMutable();
 }
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 71c3ad3..d85ab00 100644
--- a/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java
+++ b/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java
@@ -120,6 +120,11 @@
     return Collections.unmodifiableMap(nodeMap);
   }
 
+  @Override
+  public Map<SkyKey, ? extends NodeEntry> getAllValuesMutable() {
+    return nodeMap;
+  }
+
   @VisibleForTesting
   protected ConcurrentMap<SkyKey, ? extends NodeEntry> getNodeMap() {
     return nodeMap;
diff --git a/src/main/java/com/google/devtools/build/skyframe/InMemoryMemoizingEvaluator.java b/src/main/java/com/google/devtools/build/skyframe/InMemoryMemoizingEvaluator.java
index 68998b3..4ebde56 100644
--- a/src/main/java/com/google/devtools/build/skyframe/InMemoryMemoizingEvaluator.java
+++ b/src/main/java/com/google/devtools/build/skyframe/InMemoryMemoizingEvaluator.java
@@ -258,6 +258,11 @@
   }
 
   @Override
+  public Map<SkyKey, ? extends NodeEntry> getGraphMap() {
+    return graph.getAllValuesMutable();
+  }
+
+  @Override
   public Map<SkyKey, SkyValue> getDoneValues() {
     return graph.getDoneValues();
   }
diff --git a/src/main/java/com/google/devtools/build/skyframe/MemoizingEvaluator.java b/src/main/java/com/google/devtools/build/skyframe/MemoizingEvaluator.java
index d690c4a..6bd01b5 100644
--- a/src/main/java/com/google/devtools/build/skyframe/MemoizingEvaluator.java
+++ b/src/main/java/com/google/devtools/build/skyframe/MemoizingEvaluator.java
@@ -91,6 +91,13 @@
   Map<SkyKey, SkyValue> getValues();
 
   /**
+   * Returns the node entries in the graph. Should only be called between evaluations. The returned
+   * map is mutable, but do not mutate it unless you know what you are doing! Naively deleting an
+   * entry will break graph invariants and cause a crash.
+   */
+  Map<SkyKey, ? extends NodeEntry> getGraphMap();
+
+  /**
    * Returns the done (without error) values in the graph.
    *
    * <p>The returned map may be a live view of the graph.