Remove actions from the action execution status reporter map after input discovery is done. If any of the newly discovered inputs are not present in Skyframe, this action will stop executing, and so its status message is misleading.
PiperOrigin-RevId: 251500809
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionStatusReporter.java b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionStatusReporter.java
index 55a5e63..3d4da2a 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionStatusReporter.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionStatusReporter.java
@@ -20,6 +20,7 @@
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
+import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.lib.clock.BlazeClock;
import com.google.devtools.build.lib.clock.Clock;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
@@ -104,11 +105,13 @@
actionStatus.put(action, Pair.of(message, clock.nanoTime()));
}
- /**
- * Remove action from the list of active actions.
- */
+ /** Remove action from the list of active actions. Action must be present. */
public void remove(Action action) {
- Preconditions.checkNotNull(actionStatus.remove(action), action);
+ Pair<String, Long> status = actionStatus.remove(action);
+ if (status == null) {
+ BugReport.sendBugReport(
+ new IllegalStateException("Action not present: " + action.prettyPrint()));
+ }
}
@Subscribe
@@ -139,6 +142,12 @@
setStatus(action, String.format("Running (%s)", event.getStrategy()));
}
+ @Subscribe
+ @AllowConcurrentEvents
+ public void updateStatus(StoppedScanningActionEvent event) {
+ remove(event.getAction());
+ }
+
public int getCount() {
return actionStatus.size();
}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/BUILD b/src/main/java/com/google/devtools/build/lib/actions/BUILD
index 4d6a0e9..0f73179 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/actions/BUILD
@@ -30,6 +30,7 @@
deps = [
":commandline_item",
":localhost_capacity",
+ "//src/main/java/com/google/devtools/build/lib:bug-report",
"//src/main/java/com/google/devtools/build/lib:command-utils",
"//src/main/java/com/google/devtools/build/lib:events",
"//src/main/java/com/google/devtools/build/lib:io",
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ScanningActionEvent.java b/src/main/java/com/google/devtools/build/lib/actions/ScanningActionEvent.java
index d008246..61b8a33 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ScanningActionEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ScanningActionEvent.java
@@ -17,11 +17,9 @@
import com.google.devtools.build.lib.events.ExtendedEventHandler.ProgressLike;
/**
- * Notifies that an in-flight action has started being analyzed.
+ * Notifies that an in-flight action has started being scanned for discovered inputs.
*
- * <p>This event is sent before a corresponding {@link ActionScanningCompletedEvent} or {@link
- * ActionStartedEvent}. When such an event is posted, this ends the scanning phase for the current
- * action.
+ * <p>This phase ends when an {@link StoppedScanningActionEvent} is posted for this action.
*/
public class ScanningActionEvent implements ProgressLike {
diff --git a/src/main/java/com/google/devtools/build/lib/actions/StoppedScanningActionEvent.java b/src/main/java/com/google/devtools/build/lib/actions/StoppedScanningActionEvent.java
new file mode 100644
index 0000000..90a718d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/actions/StoppedScanningActionEvent.java
@@ -0,0 +1,30 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.actions;
+
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
+
+/** Counterpart to {@link ScanningActionEvent}: indicates that scanning is over. */
+public class StoppedScanningActionEvent implements ExtendedEventHandler.ProgressLike {
+ private final Action action;
+
+ public StoppedScanningActionEvent(Action action) {
+ this.action = action;
+ }
+
+ public Action getAction() {
+ return action;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalEventHandler.java b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalEventHandler.java
index f990bf0..2d58308 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalEventHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalEventHandler.java
@@ -25,6 +25,7 @@
import com.google.devtools.build.lib.actions.RunningActionEvent;
import com.google.devtools.build.lib.actions.ScanningActionEvent;
import com.google.devtools.build.lib.actions.SchedulingActionEvent;
+import com.google.devtools.build.lib.actions.StoppedScanningActionEvent;
import com.google.devtools.build.lib.analysis.AnalysisPhaseCompleteEvent;
import com.google.devtools.build.lib.analysis.NoBuildEvent;
import com.google.devtools.build.lib.analysis.NoBuildRequestFinishedEvent;
@@ -777,6 +778,13 @@
@Subscribe
@AllowConcurrentEvents
+ public void stopScanningAction(StoppedScanningActionEvent event) {
+ stateTracker.stopScanningAction(event);
+ refresh();
+ }
+
+ @Subscribe
+ @AllowConcurrentEvents
public void schedulingAction(SchedulingActionEvent event) {
stateTracker.schedulingAction(event);
refresh();
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
index fe23053..32e572e 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
@@ -29,6 +29,7 @@
import com.google.devtools.build.lib.actions.RunningActionEvent;
import com.google.devtools.build.lib.actions.ScanningActionEvent;
import com.google.devtools.build.lib.actions.SchedulingActionEvent;
+import com.google.devtools.build.lib.actions.StoppedScanningActionEvent;
import com.google.devtools.build.lib.analysis.AnalysisPhaseCompleteEvent;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.buildeventstream.AnnounceBuildEventTransportsEvent;
@@ -236,6 +237,19 @@
}
/**
+ * Marks the action as no longer scanning.
+ *
+ * <p>Because we may receive events out of order, this does nothing if the action is already
+ * scheduled or running.
+ */
+ synchronized void setStopScanning(long nanoChangeTime) {
+ if (schedulingStrategiesBitmap == 0 && runningStrategiesBitmap == 0) {
+ scanning = false;
+ nanoStartTime = nanoChangeTime;
+ }
+ }
+
+ /**
* Marks the action as scheduling with the given strategy.
*
* <p>Because we may receive events out of order, this does nothing if the action is already
@@ -467,6 +481,13 @@
getActionState(action, actionId, now).setScanning(now);
}
+ void stopScanningAction(StoppedScanningActionEvent event) {
+ Action action = event.getAction();
+ Artifact actionId = action.getPrimaryOutput();
+ long now = clock.nanoTime();
+ getActionState(action, actionId, now).setStopScanning(now);
+ }
+
void schedulingAction(SchedulingActionEvent event) {
ActionExecutionMetadata action = event.getActionMetadata();
Artifact actionId = event.getActionMetadata().getPrimaryOutput();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
index 96c54a8..e3cc635 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
@@ -70,6 +70,7 @@
import com.google.devtools.build.lib.actions.NotifyOnActionCacheHit.ActionCachedContext;
import com.google.devtools.build.lib.actions.PackageRootResolver;
import com.google.devtools.build.lib.actions.ScanningActionEvent;
+import com.google.devtools.build.lib.actions.StoppedScanningActionEvent;
import com.google.devtools.build.lib.actions.TargetOutOfDateException;
import com.google.devtools.build.lib.actions.cache.MetadataHandler;
import com.google.devtools.build.lib.buildtool.BuildRequestOptions;
@@ -762,6 +763,8 @@
e,
actionExecutionContext.getFileOutErr(),
ErrorTiming.BEFORE_EXECUTION);
+ } finally {
+ actionExecutionContext.getEventHandler().post(new StoppedScanningActionEvent(action));
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index e79dac8..a8448c1 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -2606,6 +2606,11 @@
return directories;
}
+ @VisibleForTesting
+ ActionExecutionStatusReporter getActionExecutionStatusReporterForTesting() {
+ return statusReporterRef.get();
+ }
+
/**
* Initializes and syncs the graph with the given options, readying it for the next evaluation.
*/
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
index 08fd7de..def08cd 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
@@ -200,7 +200,7 @@
differencer = new SequencedRecordingDifferencer();
ActionExecutionStatusReporter statusReporter =
- ActionExecutionStatusReporter.create(new StoredEventHandler());
+ ActionExecutionStatusReporter.create(new StoredEventHandler(), eventBus);
final SkyframeActionExecutor skyframeActionExecutor =
new SkyframeActionExecutor(
actionKeyContext,
diff --git a/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java b/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java
index f99836b..7871b1b 100644
--- a/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java
+++ b/src/test/java/com/google/devtools/build/lib/testutil/MoreAsserts.java
@@ -321,6 +321,13 @@
fail(failureMessage);
}
+ public static void assertNotContainsEventRegex(
+ Iterable<Event> eventCollector, String unexpectedEventRegex) {
+ for (Event event : eventCollector) {
+ assertThat(event.toString()).doesNotMatch(unexpectedEventRegex);
+ }
+ }
+
/**
* If the specified EventCollector contains an event which has
* 'expectedEvent' as a substring, an informative assertion fails.