Search in sources :

Example 16 with Environment

use of com.google.devtools.build.skyframe.SkyFunction.Environment in project bazel by bazelbuild.

the class MemoizingEvaluatorTest method valueInErrorWithGroups.

/**
   * Regression test -- if value top requests {depA, depB}, depC, with depA and depC there and depB
   * absent, and then throws an exception, the stored deps should be depA, depC (in different
   * groups), not {depA, depC} (same group).
   */
@Test
public void valueInErrorWithGroups() throws Exception {
    initializeTester();
    SkyKey topKey = GraphTester.toSkyKey("top");
    final SkyKey groupDepA = GraphTester.toSkyKey("groupDepA");
    final SkyKey groupDepB = GraphTester.toSkyKey("groupDepB");
    SkyKey depC = GraphTester.toSkyKey("depC");
    tester.set(groupDepA, new StringValue("depC"));
    tester.set(groupDepB, new StringValue(""));
    tester.getOrCreate(depC).setHasError(true);
    tester.getOrCreate(topKey).setBuilder(new NoExtractorFunction() {

        @Override
        public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException, InterruptedException {
            StringValue val = ((StringValue) env.getValues(ImmutableList.of(groupDepA, groupDepB)).get(groupDepA));
            if (env.valuesMissing()) {
                return null;
            }
            String nextDep = val.getValue();
            try {
                env.getValueOrThrow(GraphTester.toSkyKey(nextDep), SomeErrorException.class);
            } catch (SomeErrorException e) {
                throw new GenericFunctionException(e, Transience.PERSISTENT);
            }
            return env.valuesMissing() ? null : new StringValue("top");
        }
    });
    EvaluationResult<StringValue> evaluationResult = tester.eval(/*keepGoing=*/
    true, groupDepA, depC);
    assertTrue(evaluationResult.hasError());
    assertEquals("depC", evaluationResult.get(groupDepA).getValue());
    assertThat(evaluationResult.getError(depC).getRootCauses()).containsExactly(depC).inOrder();
    evaluationResult = tester.eval(/*keepGoing=*/
    false, topKey);
    assertTrue(evaluationResult.hasError());
    assertThat(evaluationResult.getError(topKey).getRootCauses()).containsExactly(topKey).inOrder();
    tester.set(groupDepA, new StringValue("groupDepB"));
    tester.getOrCreate(depC, /*markAsModified=*/
    true);
    tester.invalidate();
    evaluationResult = tester.eval(/*keepGoing=*/
    false, topKey);
    assertFalse(evaluationResult.toString(), evaluationResult.hasError());
    assertEquals("top", evaluationResult.get(topKey).getValue());
}
Also used : Environment(com.google.devtools.build.skyframe.SkyFunction.Environment) NotComparableStringValue(com.google.devtools.build.skyframe.GraphTester.NotComparableStringValue) StringValue(com.google.devtools.build.skyframe.GraphTester.StringValue) Test(org.junit.Test)

Example 17 with Environment

use of com.google.devtools.build.skyframe.SkyFunction.Environment in project bazel by bazelbuild.

the class MemoizingEvaluatorTest method cachedChildErrorDepWithSiblingDepOnNoKeepGoingEval.

@Test
public void cachedChildErrorDepWithSiblingDepOnNoKeepGoingEval() throws Exception {
    SkyKey parent1Key = GraphTester.toSkyKey("parent1");
    SkyKey parent2Key = GraphTester.toSkyKey("parent2");
    final SkyKey errorKey = GraphTester.toSkyKey("error");
    final SkyKey otherKey = GraphTester.toSkyKey("other");
    SkyFunction parentBuilder = new SkyFunction() {

        @Override
        public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedException {
            env.getValue(errorKey);
            env.getValue(otherKey);
            if (env.valuesMissing()) {
                return null;
            }
            return new StringValue("parent");
        }

        @Override
        public String extractTag(SkyKey skyKey) {
            return null;
        }
    };
    tester.getOrCreate(parent1Key).setBuilder(parentBuilder);
    tester.getOrCreate(parent2Key).setBuilder(parentBuilder);
    tester.getOrCreate(errorKey).setConstantValue(new StringValue("no error yet"));
    tester.getOrCreate(otherKey).setConstantValue(new StringValue("other"));
    tester.eval(/*keepGoing=*/
    true, parent1Key);
    tester.eval(/*keepGoing=*/
    false, parent2Key);
    tester.getOrCreate(errorKey, /*markAsModified=*/
    true).setHasError(true);
    tester.invalidate();
    tester.eval(/*keepGoing=*/
    true, parent1Key);
    tester.eval(/*keepGoing=*/
    false, parent2Key);
}
Also used : Environment(com.google.devtools.build.skyframe.SkyFunction.Environment) NotComparableStringValue(com.google.devtools.build.skyframe.GraphTester.NotComparableStringValue) StringValue(com.google.devtools.build.skyframe.GraphTester.StringValue) Test(org.junit.Test)

Example 18 with Environment

use of com.google.devtools.build.skyframe.SkyFunction.Environment in project bazel by bazelbuild.

the class MemoizingEvaluatorTest method cycleAndErrorAndReady.

/**
   * Regression test: IllegalStateException in BuildingState.isReady(). The ParallelEvaluator used
   * to assume during cycle-checking that all values had been built as fully as possible -- that
   * evaluation had not been interrupted. However, we also do cycle-checking in nokeep-going mode
   * when a value throws an error (possibly prematurely shutting down evaluation) but that error
   * then bubbles up into a cycle.
   *
   * <p>We want to achieve the following state: we are checking for a cycle; the value we examine
   * has not yet finished checking its children to see if they are dirty; but all children checked
   * so far have been unchanged. This value is "otherTop". We first build otherTop, then mark its
   * first child changed (without actually changing it), and then do a second build. On the second
   * build, we also build "top", which requests a cycle that depends on an error. We wait to signal
   * otherTop that its first child is done until the error throws and shuts down evaluation. The
   * error then bubbles up to the cycle, and so the bubbling is aborted. Finally, cycle checking
   * happens, and otherTop is examined, as desired.
   */
@Test
public void cycleAndErrorAndReady() throws Exception {
    // This value will not have finished building on the second build when the error is thrown.
    final SkyKey otherTop = GraphTester.toSkyKey("otherTop");
    final SkyKey errorKey = GraphTester.toSkyKey("error");
    // Is the graph state all set up and ready for the error to be thrown? The three values are
    // exceptionMarker, cycle2Key, and dep1 (via signaling otherTop).
    final CountDownLatch valuesReady = new CountDownLatch(3);
    // Is evaluation being shut down? This is counted down by the exceptionMarker's builder, after
    // it has waited for the threadpool's exception latch to be released.
    final CountDownLatch errorThrown = new CountDownLatch(1);
    // We don't do anything on the first build.
    final AtomicBoolean secondBuild = new AtomicBoolean(false);
    injectGraphListenerForTesting(new Listener() {

        @Override
        public void accept(SkyKey key, EventType type, Order order, Object context) {
            if (!secondBuild.get()) {
                return;
            }
            if (key.equals(otherTop) && type == EventType.SIGNAL) {
                // otherTop is being signaled that dep1 is done. Tell the error value that it is
                // ready, then wait until the error is thrown, so that otherTop's builder is not
                // re-entered.
                valuesReady.countDown();
                TrackingAwaiter.INSTANCE.awaitLatchAndTrackExceptions(errorThrown, "error not thrown");
                return;
            }
        }
    }, /*deterministic=*/
    true);
    final SkyKey dep1 = GraphTester.toSkyKey("dep1");
    tester.set(dep1, new StringValue("dep1"));
    final SkyKey dep2 = GraphTester.toSkyKey("dep2");
    tester.set(dep2, new StringValue("dep2"));
    // otherTop should request the deps one at a time, so that it can be in the CHECK_DEPENDENCIES
    // state even after one dep is re-evaluated.
    tester.getOrCreate(otherTop).setBuilder(new NoExtractorFunction() {

        @Override
        public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedException {
            env.getValue(dep1);
            if (env.valuesMissing()) {
                return null;
            }
            env.getValue(dep2);
            return env.valuesMissing() ? null : new StringValue("otherTop");
        }
    });
    // Prime the graph with otherTop, so we can dirty it next build.
    assertEquals(new StringValue("otherTop"), tester.evalAndGet(/*keepGoing=*/
    false, otherTop));
    // Mark dep1 changed, so otherTop will be dirty and request re-evaluation of dep1.
    tester.getOrCreate(dep1, /*markAsModified=*/
    true);
    SkyKey topKey = GraphTester.toSkyKey("top");
    // Note that since DeterministicHelper alphabetizes reverse deps, it is important that
    // "cycle2" comes before "top".
    final SkyKey cycle1Key = GraphTester.toSkyKey("cycle1");
    final SkyKey cycle2Key = GraphTester.toSkyKey("cycle2");
    tester.getOrCreate(topKey).addDependency(cycle1Key).setComputedValue(CONCATENATE);
    tester.getOrCreate(cycle1Key).addDependency(errorKey).addDependency(cycle2Key).setComputedValue(CONCATENATE);
    tester.getOrCreate(errorKey).setBuilder(new ChainedFunction(/*notifyStart=*/
    null, /*waitToFinish=*/
    valuesReady, /*notifyFinish=*/
    null, /*waitForException=*/
    false, /*value=*/
    null, ImmutableList.<SkyKey>of()));
    // Make sure cycle2Key has declared its dependence on cycle1Key before error throws.
    tester.getOrCreate(cycle2Key).setBuilder(new ChainedFunction(/*notifyStart=*/
    valuesReady, null, null, false, new StringValue("never returned"), ImmutableList.<SkyKey>of(cycle1Key)));
    // Value that waits until an exception is thrown to finish building. We use it just to be
    // informed when the threadpool is shutting down.
    final SkyKey exceptionMarker = GraphTester.toSkyKey("exceptionMarker");
    tester.getOrCreate(exceptionMarker).setBuilder(new ChainedFunction(/*notifyStart=*/
    valuesReady, /*waitToFinish=*/
    new CountDownLatch(0), /*notifyFinish=*/
    errorThrown, /*waitForException=*/
    true, new StringValue("exception marker"), ImmutableList.<SkyKey>of()));
    tester.invalidate();
    secondBuild.set(true);
    // otherTop must be first, since we check top-level values for cycles in the order in which
    // they appear here.
    EvaluationResult<StringValue> result = tester.eval(/*keepGoing=*/
    false, otherTop, topKey, exceptionMarker);
    Iterable<CycleInfo> cycleInfos = result.getError(topKey).getCycleInfo();
    assertWithMessage(result.toString()).that(cycleInfos).isNotEmpty();
    CycleInfo cycleInfo = Iterables.getOnlyElement(cycleInfos);
    if (cyclesDetected()) {
        assertThat(result.errorMap().keySet()).containsExactly(topKey);
        assertThat(cycleInfo.getPathToCycle()).containsExactly(topKey);
        assertThat(cycleInfo.getCycle()).containsExactly(cycle1Key, cycle2Key);
    }
}
Also used : Order(com.google.devtools.build.skyframe.NotifyingHelper.Order) Listener(com.google.devtools.build.skyframe.NotifyingHelper.Listener) EventType(com.google.devtools.build.skyframe.NotifyingHelper.EventType) CountDownLatch(java.util.concurrent.CountDownLatch) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Environment(com.google.devtools.build.skyframe.SkyFunction.Environment) NotComparableStringValue(com.google.devtools.build.skyframe.GraphTester.NotComparableStringValue) StringValue(com.google.devtools.build.skyframe.GraphTester.StringValue) Test(org.junit.Test)

Example 19 with Environment

use of com.google.devtools.build.skyframe.SkyFunction.Environment in project bazel by bazelbuild.

the class MemoizingEvaluatorTest method changePruningFromOtherNodeAfterParentPrunes.

@Test
public void changePruningFromOtherNodeAfterParentPrunes() throws Exception {
    initializeTester();
    final SkyKey leaf = GraphTester.toSkyKey("leaf");
    final SkyKey other = GraphTester.toSkyKey("other");
    SkyKey top = GraphTester.toSkyKey("top");
    tester.set(leaf, new StringValue("leafy"));
    tester.set(other, new StringValue("other"));
    // When top depends on leaf and other, but always returns the same value,
    final StringValue fixedTopValue = new StringValue("top");
    final AtomicBoolean topEvaluated = new AtomicBoolean(false);
    tester.getOrCreate(top).setBuilder(new SkyFunction() {

        @Override
        public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedException {
            topEvaluated.set(true);
            return env.getValue(other) == null || env.getValue(leaf) == null ? null : fixedTopValue;
        }

        @Nullable
        @Override
        public String extractTag(SkyKey skyKey) {
            return null;
        }
    });
    // And top is evaluated,
    StringValue topValue = (StringValue) tester.evalAndGet("top");
    // Then top's value is as expected,
    assertEquals(fixedTopValue, topValue);
    // And top was actually evaluated.
    assertThat(topEvaluated.get()).isTrue();
    // When leaf is changed,
    tester.set(leaf, new StringValue("crunchy"));
    tester.invalidate();
    topEvaluated.set(false);
    // And top is evaluated,
    StringValue topValue2 = (StringValue) tester.evalAndGet("top");
    // Then top's value is as expected,
    assertEquals(fixedTopValue, topValue2);
    // And top was actually evaluated.
    assertThat(topEvaluated.get()).isTrue();
    // When other is invalidated but not actually changed,
    tester.getOrCreate(other, /*markAsModified=*/
    true);
    tester.invalidate();
    topEvaluated.set(false);
    // And top is evaluated,
    StringValue topValue3 = (StringValue) tester.evalAndGet("top");
    // Then top's value is as expected,
    assertEquals(fixedTopValue, topValue3);
    // And top was *not* actually evaluated, because change pruning cut off evaluation.
    assertThat(topEvaluated.get()).isFalse();
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Environment(com.google.devtools.build.skyframe.SkyFunction.Environment) NotComparableStringValue(com.google.devtools.build.skyframe.GraphTester.NotComparableStringValue) StringValue(com.google.devtools.build.skyframe.GraphTester.StringValue) Nullable(javax.annotation.Nullable) Test(org.junit.Test)

Example 20 with Environment

use of com.google.devtools.build.skyframe.SkyFunction.Environment in project bazel by bazelbuild.

the class MemoizingEvaluatorTest method dirtyWithRecoveryErrorDependsOnErrorTurningGood.

@Test
public void dirtyWithRecoveryErrorDependsOnErrorTurningGood() throws Exception {
    initializeTester();
    final SkyKey error = GraphTester.toSkyKey("error");
    tester.getOrCreate(error).setHasError(true);
    SkyKey topKey = GraphTester.toSkyKey("top");
    SkyFunction recoveryErrorFunction = new SkyFunction() {

        @Override
        public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException, InterruptedException {
            try {
                env.getValueOrThrow(error, SomeErrorException.class);
            } catch (SomeErrorException e) {
                throw new GenericFunctionException(e, Transience.PERSISTENT);
            }
            return null;
        }

        @Override
        public String extractTag(SkyKey skyKey) {
            throw new UnsupportedOperationException();
        }
    };
    tester.getOrCreate(topKey).setBuilder(recoveryErrorFunction);
    EvaluationResult<StringValue> result = tester.eval(/*keepGoing=*/
    false, topKey);
    assertThat(result.getError(topKey).getRootCauses()).containsExactly(topKey);
    tester.getOrCreate(error).setHasError(false);
    StringValue reformed = new StringValue("reformed");
    tester.set(error, reformed);
    tester.getOrCreate(topKey).setBuilder(null).addDependency(error).setComputedValue(COPY);
    tester.invalidate();
    result = tester.eval(/*keepGoing=*/
    false, topKey);
    assertEquals(reformed, result.get(topKey));
    assertFalse(result.hasError());
}
Also used : Environment(com.google.devtools.build.skyframe.SkyFunction.Environment) NotComparableStringValue(com.google.devtools.build.skyframe.GraphTester.NotComparableStringValue) StringValue(com.google.devtools.build.skyframe.GraphTester.StringValue) Test(org.junit.Test)

Aggregations

Environment (com.google.devtools.build.skyframe.SkyFunction.Environment)21 NotComparableStringValue (com.google.devtools.build.skyframe.GraphTester.NotComparableStringValue)19 StringValue (com.google.devtools.build.skyframe.GraphTester.StringValue)19 Test (org.junit.Test)19 Nullable (javax.annotation.Nullable)9 CountDownLatch (java.util.concurrent.CountDownLatch)8 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)6 EventType (com.google.devtools.build.skyframe.NotifyingHelper.EventType)5 Listener (com.google.devtools.build.skyframe.NotifyingHelper.Listener)5 Order (com.google.devtools.build.skyframe.NotifyingHelper.Order)5 ImmutableMap (com.google.common.collect.ImmutableMap)2 TestThread (com.google.devtools.build.lib.testutil.TestThread)2 ArrayList (java.util.ArrayList)2 Map (java.util.Map)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 ActionExecutionContext (com.google.devtools.build.lib.actions.ActionExecutionContext)1 ActionExecutionException (com.google.devtools.build.lib.actions.ActionExecutionException)1 Artifact (com.google.devtools.build.lib.actions.Artifact)1 ErrorInfoSubjectFactory.assertThatErrorInfo (com.google.devtools.build.skyframe.ErrorInfoSubjectFactory.assertThatErrorInfo)1 ValueComputer (com.google.devtools.build.skyframe.GraphTester.ValueComputer)1