File report if rewinding fails and an action observes a lost input twice
RELNOTES: None.
PiperOrigin-RevId: 233454364
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index f0c00f4..c95360b 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -646,6 +646,7 @@
":transitive-info-provider",
],
deps = [
+ ":bug-report",
":build-request-options",
":command-utils",
":events",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionRewindStrategy.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionRewindStrategy.java
index fa1ec3a..bcca7c7 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionRewindStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionRewindStrategy.java
@@ -30,6 +30,7 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.LostInputsExecException;
import com.google.devtools.build.lib.actions.LostInputsExecException.LostInputsActionExecutionException;
+import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.skyframe.SkyFunction.Environment;
import com.google.devtools.build.skyframe.SkyFunction.Restart;
import com.google.devtools.build.skyframe.SkyKey;
@@ -137,24 +138,23 @@
throws ActionExecutionException {
ImmutableMap<String, ActionInput> lostInputsByDigest = lostInputsException.getLostInputs();
for (String digest : lostInputsByDigest.keySet()) {
+ // The same action losing the same input twice is unexpected. The action should have waited
+ // until the depended-on action which generates the lost input is (re)run before trying
+ // again.
+ //
+ // Note that we could enforce a stronger check: if action A, which depends on an input N
+ // previously detected as lost (by any action, not just A), discovers that N is still lost,
+ // and action A started after the re-evaluation of N's generating action, then something has
+ // gone wrong. Administering that check would be more complex (e.g., the start/completion
+ // times of actions would need tracking), so we punt on it for now.
if (!lostInputRecords.add(LostInputRecord.create(actionLookupData, digest))) {
- // The same action losing the same input twice is unexpected. The action should have waited
- // until the depended-on action which generates the lost input is (re)run before trying
- // again. We tolerate such a loss--by failing the build instead of crashing--in case some
- // kind of infrastructure failure results in an input being lost twice.
- //
- // Note that we could enforce a stronger check: if action A, which depends on an input I
- // previously detected as lost (by any action, not just A), discovers that I is still lost,
- // and action A started after the re-evaluation of I's generating action, then something has
- // gone wrong. Administering that check would be more complex (e.g., the start/completion
- // times of actions would need tracking), so we punt on it for now.
- logger.severe(
- String.format(
- "lost input twice for the same action.\nlostInput: %s\nlostInput digest: %s\n"
- + "failedAction: %s",
- lostInputsByDigest.get(digest), digest, failedAction));
- // Launder the LostInputs exception as a plain ActionExecutionException so that it may be
- // processed by SkyframeActionExecutor without short-circuiting.
+ BugReport.sendBugReport(
+ new IllegalStateException(
+ String.format(
+ "lost input twice for the same action. lostInput: %s, lostInput digest: %s, "
+ + "failedAction: %s",
+ lostInputsByDigest.get(digest), digest, failedAction)),
+ ImmutableList.of());
throw new ActionExecutionException(
lostInputsException, failedAction, /*catastrophe=*/ false);
}
@@ -173,7 +173,7 @@
// failure results in their apparent loss.
logger.info(
String.format(
- "lostArtifact unexpectedly source.\nlostArtifact: %s\nlostInputs for artifact: %s\n"
+ "lostArtifact unexpectedly source. lostArtifact: %s, lostInputs for artifact: %s, "
+ "failedAction: %s",
lostArtifact, associatedLostInputs, failedAction));
// Launder the LostInputs exception as a plain ActionExecutionException so that it may be
@@ -210,8 +210,8 @@
if (failedActionDeps.contains(lostInput)) {
Preconditions.checkState(
lostInput instanceof Artifact,
- "unexpected non-artifact lostInput which is a dep of the current action.\n"
- + "lostInput: %s\nfailedAction: %s",
+ "unexpected non-artifact lostInput which is a dep of the current action. "
+ + "lostInput: %s, failedAction: %s",
lostInput,
failedActionForLogging);
lostInputsByDepOwners.put((Artifact) lostInput, lostInput);
@@ -251,12 +251,13 @@
// case, reevaluating the failed action (and no other deps) may help, because doing so may
// rerun the generating spawn.
//
- // It may also happen because of a bug, so we log that this has occurred.
+ // In other cases, such as with bugs, the second time the action fails will cause a crash in
+ // checkIfActionLostInputTwice. We log that this has occurred.
logger.info(
String.format(
- "lostInput not a dep of the failed action, and can't be associated with such a dep.\n"
- + "lostInput: %s\nowner: %s\nrunfilesDepOwner: %s\nrunfilesDepTransitiveOwner: %s"
- + "\nfailedAction: %s",
+ "lostInput not a dep of the failed action, and can't be associated with such a dep. "
+ + "lostInput: %s, owner: %s, runfilesDepOwner: %s, runfilesDepTransitiveOwner: %s"
+ + ", failedAction: %s",
lostInput,
owner,
runfilesDepOwner,