aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/google/devtools/build/skyframe/EagerInvalidator.java21
-rw-r--r--src/main/java/com/google/devtools/build/skyframe/InvalidatingNodeVisitor.java46
2 files changed, 56 insertions, 11 deletions
diff --git a/src/main/java/com/google/devtools/build/skyframe/EagerInvalidator.java b/src/main/java/com/google/devtools/build/skyframe/EagerInvalidator.java
index cb2a8ccf66..49bcfa0165 100644
--- a/src/main/java/com/google/devtools/build/skyframe/EagerInvalidator.java
+++ b/src/main/java/com/google/devtools/build/skyframe/EagerInvalidator.java
@@ -88,12 +88,18 @@ public final class EagerInvalidator {
EvaluationProgressReceiver invalidationReceiver,
InvalidationState state,
DirtyKeyTracker dirtyKeyTracker,
- ForkJoinPool forkJoinPool) {
+ ForkJoinPool forkJoinPool,
+ boolean supportInterruptions) {
state.update(diff);
return state.isEmpty()
? null
: new DirtyingNodeVisitor(
- graph, invalidationReceiver, state, dirtyKeyTracker, forkJoinPool);
+ graph,
+ invalidationReceiver,
+ state,
+ dirtyKeyTracker,
+ forkJoinPool,
+ supportInterruptions);
}
/**
@@ -126,11 +132,18 @@ public final class EagerInvalidator {
EvaluationProgressReceiver invalidationReceiver,
InvalidationState state,
DirtyKeyTracker dirtyKeyTracker,
- ForkJoinPool forkJoinPool)
+ ForkJoinPool forkJoinPool,
+ boolean supportInterruptions)
throws InterruptedException {
DirtyingNodeVisitor visitor =
createInvalidatingVisitorIfNeeded(
- graph, diff, invalidationReceiver, state, dirtyKeyTracker, forkJoinPool);
+ graph,
+ diff,
+ invalidationReceiver,
+ state,
+ dirtyKeyTracker,
+ forkJoinPool,
+ supportInterruptions);
if (visitor != null) {
visitor.run();
}
diff --git a/src/main/java/com/google/devtools/build/skyframe/InvalidatingNodeVisitor.java b/src/main/java/com/google/devtools/build/skyframe/InvalidatingNodeVisitor.java
index 3854e94fc3..2e012e90be 100644
--- a/src/main/java/com/google/devtools/build/skyframe/InvalidatingNodeVisitor.java
+++ b/src/main/java/com/google/devtools/build/skyframe/InvalidatingNodeVisitor.java
@@ -148,10 +148,14 @@ public abstract class InvalidatingNodeVisitor<TGraph extends ThinNodeQueryableGr
visit(ImmutableList.of(visitData.first), visitData.second, !MUST_EXIST);
}
executor.awaitQuiescence(/*interruptWorkers=*/ true);
- Preconditions.checkState(pendingVisitations.isEmpty(),
+
+ // Note: implementations that do not support interruption also do not update pendingVisitations.
+ Preconditions.checkState(!getSupportInterruptions() || pendingVisitations.isEmpty(),
"All dirty nodes should have been processed: %s", pendingVisitations);
}
+ protected abstract boolean getSupportInterruptions();
+
@VisibleForTesting
public CountDownLatch getInterruptionLatchForTestingOnly() {
return executor.getInterruptionLatchForTestingOnly();
@@ -250,6 +254,11 @@ public abstract class InvalidatingNodeVisitor<TGraph extends ThinNodeQueryableGr
}
@Override
+ protected boolean getSupportInterruptions() {
+ return true;
+ }
+
+ @Override
public void visit(Iterable<SkyKey> keys, InvalidationType invalidationType, boolean mustExist) {
Preconditions.checkState(invalidationType == InvalidationType.DELETED, keys);
Builder<SkyKey> unvisitedKeysBuilder = ImmutableList.builder();
@@ -335,6 +344,7 @@ public abstract class InvalidatingNodeVisitor<TGraph extends ThinNodeQueryableGr
Collections.newSetFromMap(
new ConcurrentHashMap<Pair<SkyKey, InvalidationType>, Boolean>(
EXPECTED_VISITED_SET_SIZE, .75f, DEFAULT_THREAD_COUNT));
+ private final boolean supportInterruptions;
protected DirtyingNodeVisitor(
ThinNodeQueryableGraph graph,
@@ -343,15 +353,22 @@ public abstract class InvalidatingNodeVisitor<TGraph extends ThinNodeQueryableGr
DirtyKeyTracker dirtyKeyTracker,
Function<ExecutorParams, ? extends ExecutorService> executorFactory) {
super(graph, invalidationReceiver, state, dirtyKeyTracker, executorFactory);
+ this.supportInterruptions = true;
}
+ /**
+ * Use cases that do not require support for interruptibility can avoid unnecessary work by
+ * passing {@code false} for {@param supportInterruptions}.
+ */
protected DirtyingNodeVisitor(
ThinNodeQueryableGraph graph,
EvaluationProgressReceiver invalidationReceiver,
InvalidationState state,
DirtyKeyTracker dirtyKeyTracker,
- ForkJoinPool forkJoinPool) {
+ ForkJoinPool forkJoinPool,
+ boolean supportInterruptions) {
super(graph, invalidationReceiver, state, dirtyKeyTracker, forkJoinPool);
+ this.supportInterruptions = supportInterruptions;
}
@Override
@@ -359,6 +376,11 @@ public abstract class InvalidatingNodeVisitor<TGraph extends ThinNodeQueryableGr
return visited.size();
}
+ @Override
+ protected boolean getSupportInterruptions() {
+ return supportInterruptions;
+ }
+
/**
* Queues a task to dirty the nodes named by {@param keys}. May be called from multiple threads.
* It is possible that the same node is enqueued many times. However, we require that a node
@@ -401,7 +423,9 @@ public abstract class InvalidatingNodeVisitor<TGraph extends ThinNodeQueryableGr
}
List<SkyKey> keysToGet =
Lists.transform(invalidationPairs, Pair.<SkyKey, InvalidationType>firstFunction());
- pendingVisitations.addAll(invalidationPairs);
+ if (supportInterruptions) {
+ pendingVisitations.addAll(invalidationPairs);
+ }
final Map<SkyKey, ? extends ThinNodeEntry> entries = graph.getBatch(keysToGet);
for (final Pair<SkyKey, InvalidationType> invalidationPair : invalidationPairs) {
executor.execute(
@@ -417,14 +441,18 @@ public abstract class InvalidatingNodeVisitor<TGraph extends ThinNodeQueryableGr
"%s does not exist in the graph but was enqueued for dirtying by another "
+ "node",
key);
- pendingVisitations.remove(invalidationPair);
+ if (supportInterruptions) {
+ pendingVisitations.remove(invalidationPair);
+ }
return;
}
if (entry.isChanged() || (!isChanged && entry.isDirty())) {
// If this node is already marked changed, or we are only marking this node
// dirty, and it already is, move along.
- pendingVisitations.remove(invalidationPair);
+ if (supportInterruptions) {
+ pendingVisitations.remove(invalidationPair);
+ }
return;
}
@@ -435,7 +463,9 @@ public abstract class InvalidatingNodeVisitor<TGraph extends ThinNodeQueryableGr
MarkedDirtyResult markedDirtyResult = entry.markDirty(isChanged);
if (markedDirtyResult == null) {
// Another thread has already dirtied this node. Don't do anything in this thread.
- pendingVisitations.remove(invalidationPair);
+ if (supportInterruptions) {
+ pendingVisitations.remove(invalidationPair);
+ }
return;
}
// Propagate dirtiness upwards and mark this node dirty/changed. Reverse deps should
@@ -446,7 +476,9 @@ public abstract class InvalidatingNodeVisitor<TGraph extends ThinNodeQueryableGr
informInvalidationReceiver(key, EvaluationProgressReceiver.InvalidationState.DIRTY);
dirtyKeyTracker.dirty(key);
// Remove the node from the set as the last operation.
- pendingVisitations.remove(invalidationPair);
+ if (supportInterruptions) {
+ pendingVisitations.remove(invalidationPair);
+ }
}
});
}