Search in sources :

Example 21 with ActionExecutionException

use of com.google.devtools.build.lib.actions.ActionExecutionException in project bazel by bazelbuild.

the class CompletionFunction method compute.

@Nullable
@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws CompletionFunctionException, InterruptedException {
    TValue value = completor.getValueFromSkyKey(skyKey, env);
    TopLevelArtifactContext topLevelContext = completor.getTopLevelArtifactContext(skyKey);
    if (env.valuesMissing()) {
        return null;
    }
    Map<SkyKey, ValueOrException2<MissingInputFileException, ActionExecutionException>> inputDeps = env.getValuesOrThrow(ArtifactSkyKey.mandatoryKeys(completor.getAllArtifactsToBuild(value, topLevelContext).getAllArtifacts()), MissingInputFileException.class, ActionExecutionException.class);
    int missingCount = 0;
    ActionExecutionException firstActionExecutionException = null;
    MissingInputFileException missingInputException = null;
    NestedSetBuilder<Cause> rootCausesBuilder = NestedSetBuilder.stableOrder();
    for (Map.Entry<SkyKey, ValueOrException2<MissingInputFileException, ActionExecutionException>> depsEntry : inputDeps.entrySet()) {
        Artifact input = ArtifactSkyKey.artifact(depsEntry.getKey());
        try {
            depsEntry.getValue().get();
        } catch (MissingInputFileException e) {
            missingCount++;
            final Label inputOwner = input.getOwner();
            if (inputOwner != null) {
                Cause cause = new LabelCause(inputOwner);
                rootCausesBuilder.add(cause);
                env.getListener().handle(completor.getRootCauseError(value, cause));
            }
        } catch (ActionExecutionException e) {
            rootCausesBuilder.addTransitive(e.getRootCauses());
            if (firstActionExecutionException == null) {
                firstActionExecutionException = e;
            }
        }
    }
    if (missingCount > 0) {
        missingInputException = completor.getMissingFilesException(value, missingCount);
    }
    NestedSet<Cause> rootCauses = rootCausesBuilder.build();
    if (!rootCauses.isEmpty()) {
        eventBusRef.get().post(completor.createFailed(value, rootCauses));
        if (firstActionExecutionException != null) {
            throw new CompletionFunctionException(firstActionExecutionException);
        } else {
            throw new CompletionFunctionException(missingInputException);
        }
    }
    return env.valuesMissing() ? null : completor.createResult(value);
}
Also used : SkyKey(com.google.devtools.build.skyframe.SkyKey) Label(com.google.devtools.build.lib.cmdline.Label) ValueOrException2(com.google.devtools.build.skyframe.ValueOrException2) Artifact(com.google.devtools.build.lib.actions.Artifact) Cause(com.google.devtools.build.lib.causes.Cause) LabelCause(com.google.devtools.build.lib.causes.LabelCause) LabelCause(com.google.devtools.build.lib.causes.LabelCause) TopLevelArtifactContext(com.google.devtools.build.lib.analysis.TopLevelArtifactContext) ActionExecutionException(com.google.devtools.build.lib.actions.ActionExecutionException) Map(java.util.Map) MissingInputFileException(com.google.devtools.build.lib.actions.MissingInputFileException) Nullable(javax.annotation.Nullable)

Example 22 with ActionExecutionException

use of com.google.devtools.build.lib.actions.ActionExecutionException in project bazel by bazelbuild.

the class ActionExecutionFunction method compute.

@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws ActionExecutionFunctionException, InterruptedException {
    Preconditions.checkArgument(skyKey.argument() instanceof Action);
    Action action = (Action) skyKey.argument();
    // BUILD_ID, forcing invalidation of upward transitive closure on each build.
    if ((action.isVolatile() && !(action instanceof SkyframeAwareAction)) || action instanceof NotifyOnActionCacheHit) {
        // Volatile build actions may need to execute even if none of their known inputs have changed.
        // Depending on the buildID ensure that these actions have a chance to execute.
        PrecomputedValue.BUILD_ID.get(env);
    }
    // Look up the parts of the environment that influence the action.
    Map<SkyKey, SkyValue> clientEnvLookup = env.getValues(Iterables.transform(action.getClientEnvironmentVariables(), VAR_TO_SKYKEY));
    if (env.valuesMissing()) {
        return null;
    }
    Map<String, String> clientEnv = new HashMap<>();
    for (Entry<SkyKey, SkyValue> entry : clientEnvLookup.entrySet()) {
        ClientEnvironmentValue envValue = (ClientEnvironmentValue) entry.getValue();
        if (envValue.getValue() != null) {
            clientEnv.put((String) entry.getKey().argument(), envValue.getValue());
        }
    }
    // For restarts of this ActionExecutionFunction we use a ContinuationState variable, below, to
    // avoid redoing work. However, if two actions are shared and the first one executes, when the
    // second one goes to execute, we should detect that and short-circuit, even without taking
    // ContinuationState into account.
    boolean sharedActionAlreadyRan = skyframeActionExecutor.probeActionExecution(action);
    ContinuationState state;
    if (action.discoversInputs()) {
        state = getState(action);
    } else {
        // Because this is a new state, all conditionals below about whether state has already done
        // something will return false, and so we will execute all necessary steps.
        state = new ContinuationState();
    }
    if (!state.hasCollectedInputs()) {
        state.allInputs = collectInputs(action, env);
        if (state.allInputs == null) {
            // Missing deps.
            return null;
        }
    } else if (state.allInputs.keysRequested != null) {
        // Preserve the invariant that we ask for the same deps each build.
        env.getValues(state.allInputs.keysRequested);
        Preconditions.checkState(!env.valuesMissing(), "%s %s", action, state);
    }
    Pair<Map<Artifact, FileArtifactValue>, Map<Artifact, Collection<Artifact>>> checkedInputs = null;
    try {
        // Declare deps on known inputs to action. We do this unconditionally to maintain our
        // invariant of asking for the same deps each build.
        Map<SkyKey, ValueOrException2<MissingInputFileException, ActionExecutionException>> inputDeps = env.getValuesOrThrow(toKeys(state.allInputs.getAllInputs(), action.discoversInputs() ? action.getMandatoryInputs() : null), MissingInputFileException.class, ActionExecutionException.class);
        if (!sharedActionAlreadyRan && !state.hasArtifactData()) {
            // Do we actually need to find our metadata?
            checkedInputs = checkInputs(env, action, inputDeps);
        }
    } catch (ActionExecutionException e) {
        // Remove action from state map in case it's there (won't be unless it discovers inputs).
        stateMap.remove(action);
        throw new ActionExecutionFunctionException(e);
    }
    if (env.valuesMissing()) {
        // of the action; see establishSkyframeDependencies why.
        return null;
    }
    try {
        establishSkyframeDependencies(env, action);
    } catch (ActionExecutionException e) {
        throw new ActionExecutionFunctionException(e);
    }
    if (env.valuesMissing()) {
        return null;
    }
    if (checkedInputs != null) {
        Preconditions.checkState(!state.hasArtifactData(), "%s %s", state, action);
        state.inputArtifactData = checkedInputs.first;
        state.expandedArtifacts = checkedInputs.second;
    }
    ActionExecutionValue result;
    try {
        result = checkCacheAndExecuteIfNeeded(action, state, env, clientEnv);
    } catch (ActionExecutionException e) {
        // Remove action from state map in case it's there (won't be unless it discovers inputs).
        stateMap.remove(action);
        // action. Label can be null in the case of, e.g., the SystemActionOwner (for build-info.txt).
        throw new ActionExecutionFunctionException(new AlreadyReportedActionExecutionException(e));
    }
    if (env.valuesMissing()) {
        Preconditions.checkState(stateMap.containsKey(action), action);
        return null;
    }
    // Remove action from state map in case it's there (won't be unless it discovers inputs).
    stateMap.remove(action);
    return result;
}
Also used : SkyKey(com.google.devtools.build.skyframe.SkyKey) Action(com.google.devtools.build.lib.actions.Action) HashMap(java.util.HashMap) NotifyOnActionCacheHit(com.google.devtools.build.lib.actions.NotifyOnActionCacheHit) ValueOrException2(com.google.devtools.build.skyframe.ValueOrException2) Artifact(com.google.devtools.build.lib.actions.Artifact) SkyValue(com.google.devtools.build.skyframe.SkyValue) AlreadyReportedActionExecutionException(com.google.devtools.build.lib.actions.AlreadyReportedActionExecutionException) ActionExecutionException(com.google.devtools.build.lib.actions.ActionExecutionException) HashMap(java.util.HashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) Map(java.util.Map) AlreadyReportedActionExecutionException(com.google.devtools.build.lib.actions.AlreadyReportedActionExecutionException)

Example 23 with ActionExecutionException

use of com.google.devtools.build.lib.actions.ActionExecutionException in project bazel by bazelbuild.

the class PopulateTreeArtifactActionTest method testInvalidManifestEntryPaths.

@Test
public void testInvalidManifestEntryPaths() throws Exception {
    Action action = createPopulateTreeArtifactAction();
    scratch.overwriteFile("archiveManifest.txt", "archive_members/1.class", "../invalid_relative_path/myfile.class");
    ActionExecutionContext executionContext = actionExecutionContext(new ArrayList<Artifact>());
    try {
        action.execute(executionContext);
        fail("Invalid manifest entry paths, expected exception");
    } catch (ActionExecutionException e) {
    // Expect ActionExecutionException
    }
}
Also used : Action(com.google.devtools.build.lib.actions.Action) ActionExecutionContext(com.google.devtools.build.lib.actions.ActionExecutionContext) ActionExecutionException(com.google.devtools.build.lib.actions.ActionExecutionException) SpecialArtifact(com.google.devtools.build.lib.actions.Artifact.SpecialArtifact) Artifact(com.google.devtools.build.lib.actions.Artifact) TreeFileArtifact(com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact) Test(org.junit.Test)

Example 24 with ActionExecutionException

use of com.google.devtools.build.lib.actions.ActionExecutionException in project bazel by bazelbuild.

the class SkyframeAwareActionTest method testRaceConditionBetweenInputAcquisitionAndSkyframeDeps.

/**
   * Regression test to avoid a potential race condition in {@link ActionExecutionFunction}.
   *
   * <p>The test ensures that when ActionExecutionFunction executes a Skyframe-aware action
   * (implementor of {@link SkyframeAwareAction}), ActionExecutionFunction first requests the inputs
   * of the action and ensures they are built before requesting any of its Skyframe dependencies.
   *
   * <p>This strict ordering is very important to avoid the race condition, which could arise if the
   * compute method were too eager to request all dependencies: request input files but even if some
   * are missing, request also the skyframe-dependencies. The race is described in this method's
   * body.
   */
@Test
public void testRaceConditionBetweenInputAcquisitionAndSkyframeDeps() throws Exception {
    // Sequence of events on threads A and B, showing SkyFunctions and requested SkyKeys, leading
    // to an InconsistentFilesystemException:
    //
    // _______________[Thread A]_________________|_______________[Thread B]_________________
    // ActionExecutionFunction(gen2_action:      | idle
    //   genfiles/gen1 -> genfiles/foo/bar/gen2) |
    // ARTIFACT:genfiles/gen1                    |
    // MOCK_VALUE:dummy_argument                 |
    // env.valuesMissing():yes ==> return        |
    //                                           |
    // ArtifactFunction(genfiles/gen1)           | MockFunction()
    // CONFIGURED_TARGET://foo:gen1              | FILE:genfiles/foo
    // ACTION_EXECUTION:gen1_action              | env.valuesMissing():yes ==> return
    // env.valuesMissing():yes ==> return        |
    //                                           | FileFunction(genfiles/foo)
    // ActionExecutionFunction(gen1_action)      | FILE:genfiles
    // ARTIFACT:genfiles/gen0                    | env.valuesMissing():yes ==> return
    // env.valuesMissing():yes ==> return        |
    //                                           | FileFunction(genfiles)
    // ArtifactFunction(genfiles/gen0)           | FILE_STATE:genfiles
    // CONFIGURED_TARGET://foo:gen0              | env.valuesMissing():yes ==> return
    // ACTION_EXECUTION:gen0_action              |
    // env.valuesMissing():yes ==> return        | FileStateFunction(genfiles)
    //                                           | stat genfiles
    // ActionExecutionFunction(gen0_action)      | return FileStateValue:non-existent
    // create output directory: genfiles         |
    // working                                   | FileFunction(genfiles/foo)
    //                                           | FILE:genfiles
    //                                           | FILE_STATE:genfiles/foo
    //                                           | env.valuesMissing():yes ==> return
    //                                           |
    //                                           | FileStateFunction(genfiles/foo)
    //                                           | stat genfiles/foo
    //                                           | return FileStateValue:non-existent
    //                                           |
    // done, created genfiles/gen0               | FileFunction(genfiles/foo)
    // return ActionExecutionValue(gen0_action)  | FILE:genfiles
    //                                           | FILE_STATE:genfiles/foo
    // ArtifactFunction(genfiles/gen0)           | return FileValue(genfiles/foo:non-existent)
    // CONFIGURED_TARGET://foo:gen0              |
    // ACTION_EXECUTION:gen0_action              | MockFunction()
    // return ArtifactSkyKey(genfiles/gen0)      | FILE:genfiles/foo
    //                                           | FILE:genfiles/foo/bar/gen1
    // ActionExecutionFunction(gen1_action)      | env.valuesMissing():yes ==> return
    // ARTIFACT:genfiles/gen0                    |
    // create output directory: genfiles/foo/bar | FileFunction(genfiles/foo/bar/gen1)
    // done, created genfiles/foo/bar/gen1       | FILE:genfiles/foo/bar
    // return ActionExecutionValue(gen1_action)  | env.valuesMissing():yes ==> return
    //                                           |
    // idle                                      | FileFunction(genfiles/foo/bar)
    //                                           | FILE:genfiles/foo
    //                                           | FILE_STATE:genfiles/foo/bar
    //                                           | env.valuesMissing():yes ==> return
    //                                           |
    //                                           | FileStateFunction(genfiles/foo/bar)
    //                                           | stat genfiles/foo/bar
    //                                           | return FileStateValue:directory
    //                                           |
    //                                           | FileFunction(genfiles/foo/bar)
    //                                           | FILE:genfiles/foo
    //                                           | FILE_STATE:genfiles/foo/bar
    //                                           | throw InconsistentFilesystemException:
    //                                           |     genfiles/foo doesn't exist but
    //                                           |     genfiles/foo/bar does!
    Artifact genFile1 = createDerivedArtifact("foo/bar/gen1.txt");
    Artifact genFile2 = createDerivedArtifact("gen2.txt");
    registerAction(new SingleOutputAction(null, genFile1) {

        @Override
        public void execute(ActionExecutionContext actionExecutionContext) throws ActionExecutionException, InterruptedException {
            writeOutput(null, "gen1");
        }
    });
    registerAction(new SingleOutputSkyframeAwareAction(genFile1, genFile2) {

        @Override
        public void establishSkyframeDependencies(Environment env) throws ExceptionBase {
            assertThat(env.valuesMissing()).isFalse();
        }

        @Override
        public void execute(ActionExecutionContext actionExecutionContext) throws ActionExecutionException, InterruptedException {
            writeOutput(readInput(), "gen2");
        }
    });
    builder.buildArtifacts(reporter, ImmutableSet.of(genFile2), null, null, null, null, executor, null, false, null, null);
}
Also used : ActionExecutionContext(com.google.devtools.build.lib.actions.ActionExecutionContext) Environment(com.google.devtools.build.skyframe.SkyFunction.Environment) ActionExecutionException(com.google.devtools.build.lib.actions.ActionExecutionException) Artifact(com.google.devtools.build.lib.actions.Artifact) Test(org.junit.Test)

Example 25 with ActionExecutionException

use of com.google.devtools.build.lib.actions.ActionExecutionException in project bazel by bazelbuild.

the class ParallelBuilderTest method assertNoNewJobsAreRunAfterFirstFailure.

// Regression test for bug #735765, "ParallelBuilder still issues new jobs
// after one has failed, without --keep-going."  The incorrect behaviour is
// that, when the first job fails, while no new jobs are added to the queue
// of runnable jobs, the queue may have lots of work in it, and the
// ParallelBuilder always completes these jobs before it returns.  The
// correct behaviour is to discard all the jobs in the queue after the first
// one fails.
public void assertNoNewJobsAreRunAfterFirstFailure(final boolean catastrophe, boolean keepGoing) throws Exception {
    // Strategy: Limit parallelism to 3.  Enqueue 10 runnable tasks that run
    // for an appreciable period (say 100ms).  Ensure that at most 3 of those
    // tasks completed.  This proves that all runnable tasks were dropped from
    // the queue after the first batch (which included errors) was finished.
    // It should be pretty robust even in the face of timing variations.
    final AtomicInteger completedTasks = new AtomicInteger(0);
    int numJobs = 50;
    Artifact[] artifacts = new Artifact[numJobs];
    for (int ii = 0; ii < numJobs; ++ii) {
        Artifact out = createDerivedArtifact(ii + ".out");
        List<Artifact> inputs = (catastrophe && ii > 10) ? ImmutableList.of(artifacts[0]) : Artifact.NO_ARTIFACTS;
        final int iCopy = ii;
        registerAction(new TestAction(new Callable<Void>() {

            @Override
            public Void call() throws Exception {
                // 100ms
                Thread.sleep(100);
                completedTasks.getAndIncrement();
                throw new IOException("task failed");
            }
        }, inputs, ImmutableList.of(out)) {

            @Override
            public void execute(ActionExecutionContext actionExecutionContext) throws ActionExecutionException {
                if (catastrophe && iCopy == 0) {
                    try {
                        // 300ms
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    completedTasks.getAndIncrement();
                    throw new ActionExecutionException("This is a catastrophe", this, true);
                }
                super.execute(actionExecutionContext);
            }
        });
        artifacts[ii] = out;
    }
    // Don't fail fast when we encounter the error
    reporter.removeHandler(failFastHandler);
    try {
        buildArtifacts(createBuilder(3, keepGoing), artifacts);
        fail();
    } catch (BuildFailedException e) {
        assertContainsEvent("task failed");
    }
    if (completedTasks.get() >= numJobs) {
        fail("Expected early termination due to failed task, but all tasks ran to completion.");
    }
}
Also used : IOException(java.io.IOException) Artifact(com.google.devtools.build.lib.actions.Artifact) Callable(java.util.concurrent.Callable) TestAction(com.google.devtools.build.lib.actions.util.TestAction) BuildFailedException(com.google.devtools.build.lib.actions.BuildFailedException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ActionExecutionContext(com.google.devtools.build.lib.actions.ActionExecutionContext) ActionExecutionException(com.google.devtools.build.lib.actions.ActionExecutionException)

Aggregations

ActionExecutionException (com.google.devtools.build.lib.actions.ActionExecutionException)26 Artifact (com.google.devtools.build.lib.actions.Artifact)15 IOException (java.io.IOException)14 ActionExecutionContext (com.google.devtools.build.lib.actions.ActionExecutionContext)6 AlreadyReportedActionExecutionException (com.google.devtools.build.lib.actions.AlreadyReportedActionExecutionException)6 Path (com.google.devtools.build.lib.vfs.Path)5 Map (java.util.Map)5 Test (org.junit.Test)5 Action (com.google.devtools.build.lib.actions.Action)4 BuildFailedException (com.google.devtools.build.lib.actions.BuildFailedException)4 Executor (com.google.devtools.build.lib.actions.Executor)4 MissingInputFileException (com.google.devtools.build.lib.actions.MissingInputFileException)4 SkyKey (com.google.devtools.build.skyframe.SkyKey)4 TreeFileArtifact (com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact)3 ExecException (com.google.devtools.build.lib.actions.ExecException)3 ThreadCompatible (com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible)3 ValueOrException2 (com.google.devtools.build.skyframe.ValueOrException2)3 VisibleForTesting (com.google.common.annotations.VisibleForTesting)2 SpecialArtifact (com.google.devtools.build.lib.actions.Artifact.SpecialArtifact)2 ArtifactPrefixConflictException (com.google.devtools.build.lib.actions.ArtifactPrefixConflictException)2