blob: e2a9526d150e754dd41d07f937bffefbda2466ca [file] [log] [blame]
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.skyframe;
import static com.google.common.base.Preconditions.checkNotNull;
import com.github.benmanes.caffeine.cache.Cache;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.collect.nestedset.NestedSetVisitor;
import com.google.devtools.build.lib.concurrent.QuiescingExecutor;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.events.Reportable;
import com.google.devtools.build.skyframe.QueryableGraph.Reason;
import com.google.devtools.build.skyframe.SkyFunction.Environment.SkyKeyComputeState;
import java.util.Set;
import java.util.function.Predicate;
/**
* Context object holding sufficient information for {@link SkyFunctionEnvironment} to perform its
* duties. Shared among all {@link SkyFunctionEnvironment} instances, which should regard this
* object as a read-only collection of data.
*
* <p>Also used during cycle detection.
*/
class ParallelEvaluatorContext {
private final QueryableGraph graph;
private final Version graphVersion;
private final Version minimalVersion;
private final ImmutableMap<SkyFunctionName, SkyFunction> skyFunctions;
private final ExtendedEventHandler reporter;
private final EmittedEventState emittedEventState;
private final NestedSetVisitor<Reportable> replayingNestedSetEventVisitor;
private final Predicate<SkyKey> keepGoing;
private final InflightTrackingProgressReceiver progressReceiver;
private final EventFilter storedEventFilter;
private final ErrorInfoManager errorInfoManager;
private final GraphInconsistencyReceiver graphInconsistencyReceiver;
private final QuiescingExecutor executor;
private final Cache<SkyKey, SkyKeyComputeState> stateCache;
/**
* The visitor managing the thread pool. Used to enqueue parents when an entry is finished, and,
* during testing, to block until an exception is thrown if a node builder requests that.
* Initialized after construction to avoid the overhead of the caller's creating a threadpool in
* cases where it is not needed.
*/
private final Supplier<NodeEntryVisitor> visitorSupplier;
/** * Returns a {@link Runnable} given a {@code key} to evaluate. */
interface RunnableMaker {
Runnable make(SkyKey key);
}
public ParallelEvaluatorContext(
QueryableGraph graph,
Version graphVersion,
Version minimalVersion,
ImmutableMap<SkyFunctionName, SkyFunction> skyFunctions,
ExtendedEventHandler reporter,
EmittedEventState emittedEventState,
InflightTrackingProgressReceiver progressReceiver,
EventFilter storedEventFilter,
ErrorInfoManager errorInfoManager,
GraphInconsistencyReceiver graphInconsistencyReceiver,
QuiescingExecutor executor,
Supplier<NodeEntryVisitor> visitorSupplier,
Cache<SkyKey, SkyKeyComputeState> stateCache,
Predicate<SkyKey> keepGoing) {
this.graph = graph;
this.graphVersion = graphVersion;
this.minimalVersion = minimalVersion;
this.skyFunctions = skyFunctions;
this.reporter = reporter;
this.graphInconsistencyReceiver = graphInconsistencyReceiver;
this.emittedEventState = emittedEventState;
this.replayingNestedSetEventVisitor =
new NestedSetVisitor<>(new NestedSetEventReceiver(reporter), emittedEventState);
this.progressReceiver = checkNotNull(progressReceiver);
this.storedEventFilter = storedEventFilter;
this.errorInfoManager = errorInfoManager;
this.executor = executor;
this.visitorSupplier = Suppliers.memoize(visitorSupplier);
this.stateCache = stateCache;
this.keepGoing = keepGoing;
}
/**
* Signals all parents that this node is finished.
*
* <p>Calling this method indicates that we are building this node after the main build aborted,
* so skips signalling any parents that are already done (that can happen with cycles).
*/
void signalParentsOnAbort(SkyKey skyKey, Set<SkyKey> parents, Version version)
throws InterruptedException {
NodeBatch batch = graph.getBatch(skyKey, Reason.SIGNAL_DEP, parents);
for (SkyKey parent : parents) {
NodeEntry entry = checkNotNull(batch.get(parent), parent);
if (!entry.isDone()) { // In cycles, we can have parents that are already done.
entry.signalDep(version, skyKey);
}
}
}
/** Signals all parents that this node is finished and enqueues any parents that are ready. */
void signalParentsAndEnqueueIfReady(SkyKey skyKey, Set<SkyKey> parents, Version version)
throws InterruptedException {
NodeBatch batch = graph.getBatch(skyKey, Reason.SIGNAL_DEP, parents);
for (SkyKey parent : parents) {
NodeEntry entry = checkNotNull(batch.get(parent), parent);
boolean evaluationRequired = entry.signalDep(version, skyKey);
if (evaluationRequired || parent.supportsPartialReevaluation()) {
getVisitor().enqueueEvaluation(parent, skyKey);
}
}
}
QueryableGraph getGraph() {
return graph;
}
Version getGraphVersion() {
return graphVersion;
}
Version getMinimalVersion() {
return minimalVersion;
}
boolean keepGoing(SkyKey key) {
return keepGoing.test(key);
}
NodeEntryVisitor getVisitor() {
return visitorSupplier.get();
}
InflightTrackingProgressReceiver getProgressReceiver() {
return progressReceiver;
}
GraphInconsistencyReceiver getGraphInconsistencyReceiver() {
return graphInconsistencyReceiver;
}
EmittedEventState getEmittedEventState() {
return emittedEventState;
}
NestedSetVisitor<Reportable> getReplayingNestedSetEventVisitor() {
return replayingNestedSetEventVisitor;
}
ExtendedEventHandler getReporter() {
return reporter;
}
ImmutableMap<SkyFunctionName, SkyFunction> getSkyFunctions() {
return skyFunctions;
}
EventFilter getStoredEventFilter() {
return storedEventFilter;
}
ErrorInfoManager getErrorInfoManager() {
return errorInfoManager;
}
QuiescingExecutor getExecutor() {
return executor;
}
Cache<SkyKey, SkyKeyComputeState> stateCache() {
return stateCache;
}
/** Receives the events from the NestedSet and delegates to the reporter. */
private static final class NestedSetEventReceiver
implements NestedSetVisitor.Receiver<Reportable> {
private final ExtendedEventHandler reporter;
NestedSetEventReceiver(ExtendedEventHandler reporter) {
this.reporter = reporter;
}
@Override
public void accept(Reportable event) {
event.reportTo(reporter);
}
}
}