use of com.google.devtools.build.skyframe.InvalidatingNodeVisitor.InvalidationState in project bazel by bazelbuild.
the class EagerInvalidatorTest method interruptChild.
@Test
public void interruptChild() throws Exception {
graph = new InMemoryGraphImpl();
// More values than the invalidator has threads.
int numValues = 50;
final SkyKey[] family = new SkyKey[numValues];
final SkyKey child = GraphTester.skyKey("child");
final StringValue childValue = new StringValue("child");
tester.set(child, childValue);
family[0] = child;
for (int i = 1; i < numValues; i++) {
SkyKey member = skyKey(Integer.toString(i));
tester.getOrCreate(member).addDependency(family[i - 1]).setComputedValue(CONCATENATE);
family[i] = member;
}
SkyKey parent = GraphTester.skyKey("parent");
tester.getOrCreate(parent).addDependency(family[numValues - 1]).setComputedValue(CONCATENATE);
eval(/*keepGoing=*/
false, parent);
final Thread mainThread = Thread.currentThread();
final AtomicReference<SkyKey> badKey = new AtomicReference<>();
DirtyTrackingProgressReceiver receiver = new DirtyTrackingProgressReceiver(new EvaluationProgressReceiver() {
@Override
public void invalidated(SkyKey skyKey, InvalidationState state) {
if (skyKey.equals(child)) {
// Interrupt on the very first invalidate
mainThread.interrupt();
} else if (!skyKey.functionName().equals(NODE_TYPE)) {
// All other invalidations should have the GraphTester's key type.
// Exceptions thrown here may be silently dropped, so keep track of errors ourselves.
badKey.set(skyKey);
}
try {
assertTrue(visitor.get().getInterruptionLatchForTestingOnly().await(2, TimeUnit.HOURS));
} catch (InterruptedException e) {
// We may well have thrown here because by the time we try to await, the main
// thread is already interrupted.
}
}
@Override
public void enqueueing(SkyKey skyKey) {
throw new UnsupportedOperationException();
}
@Override
public void computed(SkyKey skyKey, long elapsedTimeNanos) {
throw new UnsupportedOperationException();
}
@Override
public void evaluated(SkyKey skyKey, Supplier<SkyValue> skyValueSupplier, EvaluationState state) {
throw new UnsupportedOperationException();
}
});
try {
invalidateWithoutError(receiver, child);
fail();
} catch (InterruptedException e) {
// Expected.
}
assertNull(badKey.get());
assertFalse(state.isEmpty());
final Set<SkyKey> invalidated = Sets.newConcurrentHashSet();
assertFalse(isInvalidated(parent));
assertNotNull(graph.get(null, Reason.OTHER, parent).getValue());
receiver = new DirtyTrackingProgressReceiver(new EvaluationProgressReceiver() {
@Override
public void invalidated(SkyKey skyKey, InvalidationState state) {
invalidated.add(skyKey);
}
@Override
public void enqueueing(SkyKey skyKey) {
throw new UnsupportedOperationException();
}
@Override
public void computed(SkyKey skyKey, long elapsedTimeNanos) {
throw new UnsupportedOperationException();
}
@Override
public void evaluated(SkyKey skyKey, Supplier<SkyValue> skyValueSupplier, EvaluationState state) {
throw new UnsupportedOperationException();
}
});
invalidateWithoutError(receiver);
assertTrue(invalidated.contains(parent));
assertThat(state.getInvalidationsForTesting()).isEmpty();
// Regression test coverage:
// "all pending values are marked changed on interrupt".
assertTrue(isInvalidated(child));
assertChanged(child);
for (int i = 1; i < numValues; i++) {
assertDirtyAndNotChanged(family[i]);
}
assertDirtyAndNotChanged(parent);
}
use of com.google.devtools.build.skyframe.InvalidatingNodeVisitor.InvalidationState in project bazel by bazelbuild.
the class EagerInvalidatorTest method interruptThreadInReceiver.
@Test
public void interruptThreadInReceiver() throws Exception {
Random random = new Random(TestUtils.getRandomSeed());
int graphSize = 1000;
int tries = 5;
graph = new InMemoryGraphImpl();
SkyKey[] values = constructLargeGraph(graphSize);
eval(/*keepGoing=*/
false, values);
final Thread mainThread = Thread.currentThread();
for (int run = 0; run < tries; run++) {
Set<Pair<SkyKey, InvalidationType>> valuesToInvalidate = getValuesToInvalidate(values);
// Find how many invalidations will actually be enqueued for invalidation in the first round,
// so that we can interrupt before all of them are done.
int validValuesToDo = Sets.difference(valuesToInvalidate, state.getInvalidationsForTesting()).size();
for (Pair<SkyKey, InvalidationType> pair : state.getInvalidationsForTesting()) {
if (!isInvalidated(pair.first)) {
validValuesToDo++;
}
}
int countDownStart = validValuesToDo > 0 ? random.nextInt(validValuesToDo) : 0;
final CountDownLatch countDownToInterrupt = new CountDownLatch(countDownStart);
final DirtyTrackingProgressReceiver receiver = new DirtyTrackingProgressReceiver(new EvaluationProgressReceiver() {
@Override
public void invalidated(SkyKey skyKey, InvalidationState state) {
countDownToInterrupt.countDown();
if (countDownToInterrupt.getCount() == 0) {
mainThread.interrupt();
// Wait for the main thread to be interrupted uninterruptibly, because the main
// thread is going to interrupt us, and we don't want to get into an interrupt
// fight. Only if we get interrupted without the main thread also being interrupted
// will this throw an InterruptedException.
TrackingAwaiter.INSTANCE.awaitLatchAndTrackExceptions(visitor.get().getInterruptionLatchForTestingOnly(), "Main thread was not interrupted");
}
}
@Override
public void enqueueing(SkyKey skyKey) {
throw new UnsupportedOperationException();
}
@Override
public void computed(SkyKey skyKey, long elapsedTimeNanos) {
throw new UnsupportedOperationException();
}
@Override
public void evaluated(SkyKey skyKey, Supplier<SkyValue> skyValueSupplier, EvaluationState state) {
throw new UnsupportedOperationException();
}
});
try {
invalidate(graph, receiver, Sets.newHashSet(Iterables.transform(valuesToInvalidate, Pair.<SkyKey, InvalidationType>firstFunction())).toArray(new SkyKey[0]));
assertThat(state.getInvalidationsForTesting()).isEmpty();
} catch (InterruptedException e) {
// Expected.
}
if (state.isEmpty()) {
// Ran out of values to invalidate.
break;
}
}
eval(/*keepGoing=*/
false, values);
}
Aggregations