| // Copyright 2015 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 com.google.common.base.Preconditions; | |
| import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; | |
| /** | |
| * A node in the graph without the means to access its value. All operations on this class are | |
| * thread-safe (note, however, the warning on the return value of {@link #markDirty}). | |
| * | |
| * <p>This interface is public only for the benefit of alternative graph implementations outside of | |
| * the package. | |
| */ | |
| public interface ThinNodeEntry { | |
| /** Returns whether the entry has been built and is finished evaluating. */ | |
| @ThreadSafe | |
| boolean isDone(); | |
| /** | |
| * Returns true if the entry is marked dirty, meaning that at least one of its transitive | |
| * dependencies is marked changed. | |
| */ | |
| @ThreadSafe | |
| boolean isDirty(); | |
| /** | |
| * Returns true if the entry is marked changed, meaning that it must be re-evaluated even if its | |
| * dependencies' values have not changed. | |
| */ | |
| @ThreadSafe | |
| boolean isChanged(); | |
| /** | |
| * Marks this node dirty, or changed if {@code isChanged} is true. | |
| * | |
| * <p>A dirty node P is re-evaluated during the evaluation phase if it's requested and directly | |
| * depends on some node C whose value changed since the last evaluation of P. If it's requested | |
| * and there is no such node C, P is marked clean. | |
| * | |
| * <p>A changed node is re-evaluated during the evaluation phase if it's requested (regardless of | |
| * the state of its dependencies). | |
| * | |
| * @return a {@link MarkedDirtyResult} indicating whether the call was redundant and which may | |
| * include the node's reverse deps | |
| */ | |
| @ThreadSafe | |
| MarkedDirtyResult markDirty(boolean isChanged) throws InterruptedException; | |
| /** Returned by {@link #markDirty}. */ | |
| interface MarkedDirtyResult { | |
| /** Returns true iff the node was clean prior to the {@link #markDirty} call. */ | |
| boolean wasClean(); | |
| /** | |
| * Returns true iff the call to {@link #markDirty} was the same as some previous call to {@link | |
| * #markDirty} (i.e., sharing the same {@code isChanged} parameter value) since the last time | |
| * the node was clean. | |
| * | |
| * <p>More specifically, this returns true iff the call was {@code n.markDirty(b)} and prior to | |
| * the call {@code n.isDirty() && n.isChanged() == b}). | |
| */ | |
| boolean wasCallRedundant(); | |
| /** | |
| * If {@code wasClean()}, this returns an iterable of the node's reverse deps for efficiency, | |
| * because the {@link #markDirty} caller may be doing graph invalidation, and after dirtying a | |
| * node, the invalidation process may want to dirty the node's reverse deps. | |
| * | |
| * <p>If {@code !wasClean()}, this must not be called. It will throw {@link | |
| * IllegalStateException}. | |
| * | |
| * <p>Warning: the returned iterable may be a live view of the reverse deps collection of the | |
| * marked-dirty node. The consumer of this data must be careful only to iterate over and consume | |
| * its values while that collection is guaranteed not to change. This is true during | |
| * invalidation, because reverse deps don't change during invalidation. | |
| */ | |
| Iterable<SkyKey> getReverseDepsUnsafeIfWasClean(); | |
| } | |
| /** A {@link MarkedDirtyResult} returned when {@link #markDirty} is called on a clean node. */ | |
| class FromCleanMarkedDirtyResult implements MarkedDirtyResult { | |
| private final Iterable<SkyKey> reverseDepsUnsafe; | |
| public FromCleanMarkedDirtyResult(Iterable<SkyKey> reverseDepsUnsafe) { | |
| this.reverseDepsUnsafe = Preconditions.checkNotNull(reverseDepsUnsafe); | |
| } | |
| @Override | |
| public boolean wasClean() { | |
| return true; | |
| } | |
| @Override | |
| public boolean wasCallRedundant() { | |
| return false; | |
| } | |
| @Override | |
| public Iterable<SkyKey> getReverseDepsUnsafeIfWasClean() { | |
| return reverseDepsUnsafe; | |
| } | |
| } | |
| /** A {@link MarkedDirtyResult} returned when {@link #markDirty} is called on a dirty node. */ | |
| class FromDirtyMarkedDirtyResult implements MarkedDirtyResult { | |
| static final FromDirtyMarkedDirtyResult REDUNDANT = new FromDirtyMarkedDirtyResult(true); | |
| static final FromDirtyMarkedDirtyResult NOT_REDUNDANT = new FromDirtyMarkedDirtyResult(false); | |
| private final boolean redundant; | |
| private FromDirtyMarkedDirtyResult(boolean redundant) { | |
| this.redundant = redundant; | |
| } | |
| @Override | |
| public boolean wasClean() { | |
| return false; | |
| } | |
| @Override | |
| public boolean wasCallRedundant() { | |
| return redundant; | |
| } | |
| @Override | |
| public Iterable<SkyKey> getReverseDepsUnsafeIfWasClean() { | |
| throw new IllegalStateException(); | |
| } | |
| } | |
| } |