blob: 5cea4eb406f45eee8c3030eae6af413029510adb [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Nathan Harmatab408f9e2015-02-10 02:13:05 +00002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.skyframe;
15
Googler2c19a572015-07-16 08:38:49 +000016import com.google.common.base.MoreObjects;
tomlua155b532017-11-08 20:12:47 +010017import com.google.common.base.Preconditions;
Nathan Harmatab408f9e2015-02-10 02:13:05 +000018import com.google.common.collect.ImmutableList;
19import com.google.common.collect.ImmutableSet;
20import com.google.devtools.build.lib.util.GroupedList;
21import com.google.devtools.build.lib.util.GroupedList.GroupedListHelper;
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +000022import com.google.devtools.build.skyframe.KeyToConsolidate.Op;
23import com.google.devtools.build.skyframe.KeyToConsolidate.OpToStoreBare;
janakra2d4d3d2018-12-10 18:30:08 -080024import java.math.BigInteger;
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +000025import java.util.ArrayList;
Janak Ramakrishnan441dcb12015-10-09 22:44:31 +000026import java.util.List;
Nathan Harmatab408f9e2015-02-10 02:13:05 +000027import java.util.Set;
Nathan Harmatab408f9e2015-02-10 02:13:05 +000028import javax.annotation.Nullable;
29
30/**
31 * In-memory implementation of {@link NodeEntry}. All operations on this class are thread-safe.
32 *
33 * <p>Care was taken to provide certain compound operations to avoid certain check-then-act races.
34 * That means this class is somewhat closely tied to the exact Evaluator implementation.
35 *
36 * <p>Consider the example with two threads working on two nodes, where one depends on the other,
37 * say b depends on a. If a completes first, it's done. If it completes second, it needs to signal
38 * b, and potentially re-schedule it. If b completes first, it must exit, because it will be
39 * signaled (and re-scheduled) by a. If it completes second, it must signal (and re-schedule)
Janak Ramakrishnanab10f472017-03-24 17:08:24 +000040 * itself. However, if the Evaluator supported re-entrancy for a node, then this wouldn't have to be
41 * so strict, because duplicate scheduling would be less problematic.
Nathan Harmatab408f9e2015-02-10 02:13:05 +000042 *
Janak Ramakrishnanab10f472017-03-24 17:08:24 +000043 * <p>During its life, a node can go through states as follows:
44 *
45 * <ol>
46 * <li>Non-existent
ulfjack9beabe02019-02-13 23:41:59 -080047 * <li>Just created or marked as affected ({@link #isDone} is false; {@link #isDirty} is false)
48 * <li>Evaluating ({@link #isDone} is false; {@link #isDirty} is true)
49 * <li>Done ({@link #isDone} is true; {@link #isDirty} is false)
Janak Ramakrishnanab10f472017-03-24 17:08:24 +000050 * </ol>
51 *
52 * <p>The "just created" state is there to allow the {@link EvaluableGraph#createIfAbsentBatch} and
53 * {@link NodeEntry#addReverseDepAndCheckIfDone} methods to be separate. All callers have to call
54 * both methods in that order if they want to create a node. The second method transitions the
55 * current node to the "evaluating" state and returns true only the first time it was called. A
56 * caller that gets "true" back from that call must start the evaluation of this node, while any
57 * subsequent callers must not.
58 *
59 * <p>An entry is set to "evaluating" as soon as it is scheduled for evaluation. Thus, even a node
60 * that is never actually built (for instance, a dirty node that is verified as clean) is in the
61 * "evaluating" state until it is done.
Nathan Harmatac533acd2015-03-07 03:06:22 +000062 *
ulfjack9beabe02019-02-13 23:41:59 -080063 * <p>From the "Done" state, the node can go back to the "marked as affected" state.
64 *
Nathan Harmatab408f9e2015-02-10 02:13:05 +000065 * <p>This class is public only for the benefit of alternative graph implementations outside of the
66 * package.
67 */
Nathan Harmatac533acd2015-03-07 03:06:22 +000068public class InMemoryNodeEntry implements NodeEntry {
Nathan Harmatab408f9e2015-02-10 02:13:05 +000069
70 /** Actual data stored in this entry when it is done. */
janakrbf316f72018-11-28 14:38:44 -080071 protected volatile SkyValue value = null;
Nathan Harmatab408f9e2015-02-10 02:13:05 +000072
73 /**
Janak Ramakrishnan058c4ab2016-02-08 21:30:36 +000074 * The last version of the graph at which this node's value was changed. In {@link #setValue} it
75 * may be determined that the value being written to the graph at a given version is the same as
76 * the already-stored value. In that case, the version will remain the same. The version can be
77 * thought of as the latest timestamp at which this value was changed.
Nathan Harmatab408f9e2015-02-10 02:13:05 +000078 */
janakrbf316f72018-11-28 14:38:44 -080079 protected volatile Version lastChangedVersion = MinimalVersion.INSTANCE;
Janak Ramakrishnan1d22d4c2015-11-18 19:28:45 +000080
81 /**
82 * Returns the last version this entry was evaluated at, even if it re-evaluated to the same
Googler159a42a2018-10-31 13:19:51 -070083 * value. When a child signals this entry with the last version it was changed at in {@link
84 * #signalDep}, this entry need not re-evaluate if the child's version is at most this version,
85 * even if the {@link #lastChangedVersion} is less than this one.
Janak Ramakrishnan1d22d4c2015-11-18 19:28:45 +000086 *
Googler159a42a2018-10-31 13:19:51 -070087 * @see #signalDep(Version, SkyKey)
Janak Ramakrishnan1d22d4c2015-11-18 19:28:45 +000088 */
89 protected Version lastEvaluatedVersion = MinimalVersion.INSTANCE;
Nathan Harmatab408f9e2015-02-10 02:13:05 +000090
91 /**
Janak Ramakrishnan50934992016-07-06 17:09:51 +000092 * This object represents the direct deps of the node, in groups if the {@code SkyFunction}
janakr1cde8722017-10-10 03:22:21 +020093 * requested them that way. It contains either the in-progress direct deps, stored as a {@code
94 * GroupedList<SkyKey>} before the node is finished building, or the full direct deps, compressed
95 * in a memory-efficient way (via {@link GroupedList#compress}, after the node is done.
Janak Ramakrishnan50934992016-07-06 17:09:51 +000096 *
97 * <p>It is initialized lazily in getTemporaryDirectDeps() to save a little bit more memory.
Nathan Harmatab408f9e2015-02-10 02:13:05 +000098 */
janakr1cde8722017-10-10 03:22:21 +020099 protected Object directDeps = null;
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000100
101 /**
102 * This list stores the reverse dependencies of this node that have been declared so far.
103 *
104 * <p>In case of a single object we store the object unwrapped, without the list, for
105 * memory-efficiency.
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000106 *
107 * <p>When an entry is being re-evaluated, this object stores the reverse deps from the previous
108 * evaluation. At the end of evaluation, the changed reverse dep operations from {@link
109 * #reverseDepsDataToConsolidate} are merged in here.
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000110 */
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000111 protected Object reverseDeps = ImmutableList.of();
112
113 /**
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000114 * This list stores objects returned by {@link KeyToConsolidate#create}. Morally they are {@link
115 * KeyToConsolidate} objects, but since some operations are stored bare, we can only declare that
116 * this list holds {@link Object} references. Created lazily to save memory.
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000117 *
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000118 * <p>This list serves double duty. For a done node, when a reverse dep is removed, checked for
119 * presence, or possibly added, we store the mutation in this object instead of immediately doing
120 * the operation. That is because removals/checks in reverseDeps are O(N). Originally reverseDeps
121 * was a HashSet, but because of memory consumption we switched to a list.
122 *
123 * <p>Internally, {@link ReverseDepsUtility} consolidates this data periodically, and when the set
124 * of reverse deps is requested. While this operation is not free, it can be done more effectively
Janak Ramakrishnan4f487f42015-11-23 18:51:55 +0000125 * than trying to remove/check each dirty reverse dependency individually (O(N) each time).
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000126 *
127 * <p>When the node entry is evaluating, this list serves to declare the reverse dep operations
128 * that have taken place on it during this evaluation. When evaluation finishes, this list will be
129 * merged into the existing reverse deps if any, but furthermore, this list will also be used to
130 * calculate the set of reverse deps to signal when this entry finishes evaluation. That is done
131 * by {@link ReverseDepsUtility#consolidateDataAndReturnNewElements}.
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000132 */
Janak Ramakrishnan441dcb12015-10-09 22:44:31 +0000133 private List<Object> reverseDepsDataToConsolidate = null;
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000134
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000135 /**
Janak Ramakrishnanab10f472017-03-24 17:08:24 +0000136 * Object encapsulating dirty state of the object between when it is marked dirty and
137 * re-evaluated.
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000138 */
janakr5b4f2372019-01-08 17:12:03 -0800139 @Nullable protected volatile DirtyBuildingState dirtyBuildingState = null;
Janak Ramakrishnanab10f472017-03-24 17:08:24 +0000140
Googlerbaefeab2019-04-30 17:12:55 -0700141 /** Construct a InMemoryNodeEntry. Use ONLY in Skyframe evaluation and graph implementations. */
142 public InMemoryNodeEntry() {}
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000143
janakr4f7be0f2017-10-18 11:45:48 -0400144 // Public only for use in alternate graph implementations.
janakr1cde8722017-10-10 03:22:21 +0200145 public KeepEdgesPolicy keepEdges() {
146 return KeepEdgesPolicy.ALL;
147 }
148
149 private boolean keepReverseDeps() {
150 return keepEdges() == KeepEdgesPolicy.ALL;
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000151 }
152
ulfjack9beabe02019-02-13 23:41:59 -0800153 private boolean isEvaluating() {
154 return dirtyBuildingState != null;
155 }
156
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000157 @Override
Shreya Bhattaraicc1b9b32017-01-06 18:19:25 +0000158 public boolean isDone() {
ulfjack9beabe02019-02-13 23:41:59 -0800159 return value != null && dirtyBuildingState == null;
160 }
161
162 @Override
163 public synchronized boolean isReady() {
164 Preconditions.checkState(!isDone(), "can't be ready if done: %s", this);
165 Preconditions.checkState(isEvaluating(), this);
166 return dirtyBuildingState.isReady(getNumTemporaryDirectDeps());
167 }
168
169 @Override
170 public synchronized boolean isDirty() {
171 return !isDone() && dirtyBuildingState != null;
172 }
173
174 @Override
175 public synchronized boolean isChanged() {
176 return !isDone() && dirtyBuildingState != null && dirtyBuildingState.isChanged();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000177 }
178
179 @Override
janakr19e03d72018-01-10 13:13:00 -0800180 public SkyValue getValue() {
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000181 Preconditions.checkState(isDone(), "no value until done. ValueEntry: %s", this);
182 return ValueWithMetadata.justValue(value);
183 }
184
185 @Override
mschallera8926b72018-06-28 11:53:36 -0700186 @Nullable
janakr19e03d72018-01-10 13:13:00 -0800187 public SkyValue getValueMaybeWithMetadata() {
Janak Ramakrishnan0afd4532015-08-24 17:27:48 +0000188 return value;
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000189 }
190
191 @Override
janakr19e03d72018-01-10 13:13:00 -0800192 public SkyValue toValue() {
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000193 if (isDone()) {
194 return getErrorInfo() == null ? getValue() : null;
195 } else if (isChanged() || isDirty()) {
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000196 SkyValue lastBuildValue = null;
197 try {
ulfjack9beabe02019-02-13 23:41:59 -0800198 lastBuildValue = dirtyBuildingState.getLastBuildValue();
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000199 } catch (InterruptedException e) {
200 throw new IllegalStateException("Interruption unexpected: " + this, e);
201 }
202 return (lastBuildValue == null) ? null : ValueWithMetadata.justValue(lastBuildValue);
Janak Ramakrishnan54111292015-09-09 21:44:07 +0000203 } else {
204 // Value has not finished evaluating. It's probably about to be cleaned from the graph.
205 return null;
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000206 }
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000207 }
208
209 @Override
Googlerb808db42019-05-14 16:32:30 -0700210 public Iterable<SkyKey> getDirectDeps() {
janakr4d6c0ab2019-04-29 14:46:53 -0700211 return GroupedList.compressedToIterable(getCompressedDirectDepsForDoneEntry());
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000212 }
213
Googlerb808db42019-05-14 16:32:30 -0700214 @Override
215 public int getNumberOfDirectDepGroups() {
216 return GroupedList.numGroups(getCompressedDirectDepsForDoneEntry());
217 }
218
janakr4d6c0ab2019-04-29 14:46:53 -0700219 /** Returns the compressed {@link GroupedList} of direct deps. Can only be called when done. */
Googlerb808db42019-05-14 16:32:30 -0700220 public final synchronized @GroupedList.Compressed Object getCompressedDirectDepsForDoneEntry() {
janakr1cde8722017-10-10 03:22:21 +0200221 assertKeepDeps();
Janak Ramakrishnan50934992016-07-06 17:09:51 +0000222 Preconditions.checkState(isDone(), "no deps until done. NodeEntry: %s", this);
Googlerbaefeab2019-04-30 17:12:55 -0700223 Preconditions.checkNotNull(directDeps, "deps can't be null: %s", this);
224 return GroupedList.castAsCompressed(directDeps);
Nathan Harmatadf22aaf2015-03-06 20:44:46 +0000225 }
226
shreyax5d634362017-11-29 11:31:49 -0800227 public int getNumDirectDeps() {
Googlerbaefeab2019-04-30 17:12:55 -0700228 return GroupedList.numElements(getCompressedDirectDepsForDoneEntry());
shreyax5d634362017-11-29 11:31:49 -0800229 }
230
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000231 @Override
232 @Nullable
233 public synchronized ErrorInfo getErrorInfo() {
Janak Ramakrishnan50934992016-07-06 17:09:51 +0000234 Preconditions.checkState(isDone(), "no errors until done. NodeEntry: %s", this);
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000235 return ValueWithMetadata.getMaybeErrorInfo(value);
236 }
237
Janak Ramakrishnan4f487f42015-11-23 18:51:55 +0000238 /**
Janak Ramakrishnan772b5bb2016-06-29 00:20:36 +0000239 * Puts entry in "done" state, as checked by {@link #isDone}. Subclasses that override one may
240 * need to override the other.
Janak Ramakrishnan4f487f42015-11-23 18:51:55 +0000241 */
242 protected void markDone() {
Janak Ramakrishnanab10f472017-03-24 17:08:24 +0000243 dirtyBuildingState = null;
Janak Ramakrishnan4f487f42015-11-23 18:51:55 +0000244 }
245
ulfjack20eeaad2019-02-18 02:51:55 -0800246 @Override
247 public synchronized void addExternalDep() {
248 Preconditions.checkNotNull(dirtyBuildingState, this);
249 dirtyBuildingState.addExternalDep();
250 }
251
janakr1cde8722017-10-10 03:22:21 +0200252 protected final synchronized Set<SkyKey> setStateFinishedAndReturnReverseDepsToSignal() {
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000253 Set<SkyKey> reverseDepsToSignal =
254 ReverseDepsUtility.consolidateDataAndReturnNewElements(this, getOpToStoreBare());
Janak Ramakrishnan50934992016-07-06 17:09:51 +0000255 this.directDeps = getTemporaryDirectDeps().compress();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000256
Janak Ramakrishnan4f487f42015-11-23 18:51:55 +0000257 markDone();
janakr1cde8722017-10-10 03:22:21 +0200258 postProcessAfterDone();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000259 return reverseDepsToSignal;
260 }
261
janakr1cde8722017-10-10 03:22:21 +0200262 protected void postProcessAfterDone() {}
263
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000264 @Override
265 public synchronized Set<SkyKey> getInProgressReverseDeps() {
266 Preconditions.checkState(!isDone(), this);
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000267 return ReverseDepsUtility.returnNewElements(this, getOpToStoreBare());
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000268 }
269
Googler1c121702018-11-01 14:04:09 -0700270 // In this method it is critical that this.lastChangedVersion is set prior to this.value because
271 // although this method itself is synchronized, there are unsynchronized consumers of the version
272 // and the value.
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000273 @Override
janakra2d4d3d2018-12-10 18:30:08 -0800274 public synchronized Set<SkyKey> setValue(
275 SkyValue value, Version version, DepFingerprintList depFingerprintList)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000276 throws InterruptedException {
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000277 Preconditions.checkState(isReady(), "%s %s", this, value);
janakra2d4d3d2018-12-10 18:30:08 -0800278 if (depFingerprintList != null) {
279 logError(
280 new IllegalStateException(
281 String.format(
282 "Expect no depFingerprintList here: %s %s %s %s",
283 this, depFingerprintList, value, version)));
284 }
janakr54691392018-10-03 14:05:45 -0700285 assertVersionCompatibleWhenSettingValue(version, value);
Janak Ramakrishnan1d22d4c2015-11-18 19:28:45 +0000286 this.lastEvaluatedVersion = version;
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000287
janakra2d4d3d2018-12-10 18:30:08 -0800288 if (!isEligibleForChangePruningOnUnchangedValue()) {
Googler159a42a2018-10-31 13:19:51 -0700289 this.lastChangedVersion = version;
290 this.value = value;
ulfjack9beabe02019-02-13 23:41:59 -0800291 } else if (dirtyBuildingState.unchangedFromLastBuild(value)) {
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000292 // If the value is the same as before, just use the old value. Note that we don't use the new
293 // value, because preserving == equality is even better than .equals() equality.
ulfjack9beabe02019-02-13 23:41:59 -0800294 this.value = dirtyBuildingState.getLastBuildValue();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000295 } else {
ulfjack9beabe02019-02-13 23:41:59 -0800296 boolean forcedRebuild = dirtyBuildingState.getDirtyState() == DirtyState.FORCED_REBUILDING;
shahand4a6ca02018-10-03 11:41:28 -0700297 if (!forcedRebuild && this.lastChangedVersion.equals(version)) {
Googler1c121702018-11-01 14:04:09 -0700298 logError(
299 new ChangedValueAtSameVersionException(this.lastChangedVersion, version, value, this));
shahand4a6ca02018-10-03 11:41:28 -0700300 }
301 // If this is a new value, or it has changed since the last build, set the version to the
302 // current graph version.
Janak Ramakrishnan1d22d4c2015-11-18 19:28:45 +0000303 this.lastChangedVersion = version;
Googler1c121702018-11-01 14:04:09 -0700304 this.value = value;
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000305 }
Janak Ramakrishnan772b5bb2016-06-29 00:20:36 +0000306 return setStateFinishedAndReturnReverseDepsToSignal();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000307 }
308
Googler159a42a2018-10-31 13:19:51 -0700309 /**
janakra2d4d3d2018-12-10 18:30:08 -0800310 * Returns {@code true} if this node is eligible to be change pruned when its value has not
Googler159a42a2018-10-31 13:19:51 -0700311 * changed from the last build.
312 *
janakra2d4d3d2018-12-10 18:30:08 -0800313 * <p>Implementations need not check whether the value has changed - this will only be called if
314 * the value has not changed.
Googler159a42a2018-10-31 13:19:51 -0700315 */
Googler3e145b32019-01-07 09:48:20 -0800316 public boolean isEligibleForChangePruningOnUnchangedValue() {
Googler159a42a2018-10-31 13:19:51 -0700317 return true;
318 }
319
janakr54691392018-10-03 14:05:45 -0700320 protected void assertVersionCompatibleWhenSettingValue(
321 Version version, SkyValue valueForDebugging) {
322 if (!this.lastChangedVersion.atMost(version)) {
323 logError(
324 new IllegalStateException("Bad ch: " + this + ", " + version + ", " + valueForDebugging));
325 }
326 if (!this.lastEvaluatedVersion.atMost(version)) {
327 logError(
328 new IllegalStateException("Bad ev: " + this + ", " + version + ", " + valueForDebugging));
329 }
330 }
331
Googler0eedeba2018-10-31 14:27:31 -0700332 /** An exception indicating that the node's value changed but its version did not. */
333 public static final class ChangedValueAtSameVersionException extends IllegalStateException {
Googlercdb1d122018-11-05 15:38:17 -0800334 private final SkyValue newValue;
335
Googler0eedeba2018-10-31 14:27:31 -0700336 private ChangedValueAtSameVersionException(
Googler1c121702018-11-01 14:04:09 -0700337 Version lastChangedVersion,
338 Version newVersion,
339 SkyValue newValue,
340 InMemoryNodeEntry nodeEntry) {
Googler0eedeba2018-10-31 14:27:31 -0700341 super(
342 String.format(
Googler1c121702018-11-01 14:04:09 -0700343 "Changed value but with the same version? "
344 + "lastChangedVersion: %s, newVersion: %s newValue: %s, nodeEntry: %s",
345 lastChangedVersion, newVersion, newValue, nodeEntry));
Googlercdb1d122018-11-05 15:38:17 -0800346 this.newValue = newValue;
347 }
348
349 /** Returns the value that this node changed to. */
350 public SkyValue getNewValue() {
351 return newValue;
Googler0eedeba2018-10-31 14:27:31 -0700352 }
353 }
354
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000355 @Override
356 public synchronized DependencyState addReverseDepAndCheckIfDone(SkyKey reverseDep) {
ulfjack9beabe02019-02-13 23:41:59 -0800357 boolean done = isDone();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000358 if (reverseDep != null) {
ulfjack9beabe02019-02-13 23:41:59 -0800359 if (done) {
janakr1cde8722017-10-10 03:22:21 +0200360 if (keepReverseDeps()) {
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000361 ReverseDepsUtility.addReverseDeps(this, ImmutableList.of(reverseDep));
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000362 }
363 } else {
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000364 appendToReverseDepOperations(reverseDep, Op.ADD);
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000365 }
366 }
ulfjack9beabe02019-02-13 23:41:59 -0800367 if (done) {
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000368 return DependencyState.DONE;
369 }
ulfjack9beabe02019-02-13 23:41:59 -0800370 if (dirtyBuildingState == null) {
371 dirtyBuildingState = DirtyBuildingState.createNew();
372 }
mschallerac6d4fd2019-02-27 14:01:44 -0800373 boolean wasEvaluating = dirtyBuildingState.isEvaluating();
374 if (!wasEvaluating) {
ulfjack9beabe02019-02-13 23:41:59 -0800375 dirtyBuildingState.startEvaluating();
Janak Ramakrishnanab10f472017-03-24 17:08:24 +0000376 }
mschallerac6d4fd2019-02-27 14:01:44 -0800377 return wasEvaluating ? DependencyState.ALREADY_EVALUATING : DependencyState.NEEDS_SCHEDULING;
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000378 }
379
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000380 /** Sets {@link #reverseDeps}. Does not alter {@link #reverseDepsDataToConsolidate}. */
381 synchronized void setSingleReverseDepForReverseDepsUtil(SkyKey reverseDep) {
382 this.reverseDeps = reverseDep;
383 }
384
385 /** Sets {@link #reverseDeps}. Does not alter {@link #reverseDepsDataToConsolidate}. */
386 synchronized void setReverseDepsForReverseDepsUtil(List<SkyKey> reverseDeps) {
387 this.reverseDeps = reverseDeps;
388 }
389
390 /** Sets {@link #reverseDepsDataToConsolidate}. Does not alter {@link #reverseDeps}. */
391 synchronized void setReverseDepsDataToConsolidateForReverseDepsUtil(
392 List<Object> dataToConsolidate) {
393 this.reverseDepsDataToConsolidate = dataToConsolidate;
394 }
395
396 synchronized Object getReverseDepsRawForReverseDepsUtil() {
397 return this.reverseDeps;
398 }
399
400 synchronized List<Object> getReverseDepsDataToConsolidateForReverseDepsUtil() {
401 return this.reverseDepsDataToConsolidate;
402 }
403
404 private synchronized void appendToReverseDepOperations(SkyKey reverseDep, Op op) {
405 Preconditions.checkState(!isDone(), "Don't append to done %s %s %s", this, reverseDep, op);
406 if (reverseDepsDataToConsolidate == null) {
407 reverseDepsDataToConsolidate = new ArrayList<>();
408 }
409 Preconditions.checkState(
410 isDirty() || op != Op.CHECK, "Not dirty check %s %s", this, reverseDep);
411 reverseDepsDataToConsolidate.add(KeyToConsolidate.create(reverseDep, op, getOpToStoreBare()));
412 }
413
ulfjack9beabe02019-02-13 23:41:59 -0800414 /**
415 * In order to reduce memory consumption, we want to store reverse deps 'bare', i.e., without
416 * wrapping them in a KeyToConsolidate object. To that end, we define a bare op that is used for
417 * both storing and retrieving the deps. This method returns said op, and may adjust it depending
418 * on whether this is a new node entry (where all deps must be new) or an existing node entry
419 * (which most likely checks deps rather than adding new deps).
420 */
janakr3b5b55b2017-11-21 07:35:05 -0800421 protected OpToStoreBare getOpToStoreBare() {
ulfjack9beabe02019-02-13 23:41:59 -0800422 return isDirty() && dirtyBuildingState.isDirty() ? OpToStoreBare.CHECK : OpToStoreBare.ADD;
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000423 }
424
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000425 @Override
426 public synchronized DependencyState checkIfDoneForDirtyReverseDep(SkyKey reverseDep) {
427 Preconditions.checkNotNull(reverseDep, this);
janakr1cde8722017-10-10 03:22:21 +0200428 // Note that implementations of InMemoryNodeEntry that have
429 // #keepEdges == KeepEdgesPolicy.JUST_DEPS may override this entire method.
430 Preconditions.checkState(
431 keepEdges() == KeepEdgesPolicy.ALL,
432 "Incremental means keeping edges %s %s",
433 reverseDep,
434 this);
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000435 if (isDone()) {
436 ReverseDepsUtility.checkReverseDep(this, reverseDep);
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000437 } else {
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000438 appendToReverseDepOperations(reverseDep, Op.CHECK);
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000439 }
440 return addReverseDepAndCheckIfDone(null);
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000441 }
442
443 @Override
444 public synchronized void removeReverseDep(SkyKey reverseDep) {
janakr1cde8722017-10-10 03:22:21 +0200445 if (!keepReverseDeps()) {
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000446 return;
447 }
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000448 if (isDone()) {
449 ReverseDepsUtility.removeReverseDep(this, reverseDep);
450 } else {
451 // Removing a reverse dep from an in-flight node is rare -- it should only happen when this
452 // node is about to be cleaned from the graph.
453 appendToReverseDepOperations(reverseDep, Op.REMOVE_OLD);
454 }
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000455 }
456
457 @Override
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000458 public synchronized void removeInProgressReverseDep(SkyKey reverseDep) {
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000459 appendToReverseDepOperations(reverseDep, Op.REMOVE);
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000460 }
461
462 @Override
shreyax446f0ba2017-09-19 21:08:08 +0200463 public synchronized Set<SkyKey> getReverseDepsForDoneEntry() {
janakr1cde8722017-10-10 03:22:21 +0200464 assertKeepRdeps();
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000465 Preconditions.checkState(isDone(), "Called on not done %s", this);
466 return ReverseDepsUtility.getReverseDeps(this);
467 }
468
469 @Override
shreyax446f0ba2017-09-19 21:08:08 +0200470 public synchronized Set<SkyKey> getAllReverseDepsForNodeBeingDeleted() {
janakr1cde8722017-10-10 03:22:21 +0200471 assertKeepRdeps();
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000472 if (!isDone()) {
473 // This consolidation loses information about pending reverse deps to signal, but that is
474 // unimportant since this node is being deleted.
475 ReverseDepsUtility.consolidateDataAndReturnNewElements(this, getOpToStoreBare());
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000476 }
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000477 return ReverseDepsUtility.getReverseDeps(this);
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000478 }
479
480 @Override
shahan44666dc2018-10-05 17:47:11 -0700481 public synchronized boolean signalDep(Version childVersion, @Nullable SkyKey childForDebugging) {
482 Preconditions.checkState(
483 !isDone(), "Value must not be done in signalDep %s child=%s", this, childForDebugging);
ulfjack9beabe02019-02-13 23:41:59 -0800484 Preconditions.checkNotNull(dirtyBuildingState, "%s %s", this, childForDebugging);
485 Preconditions.checkState(dirtyBuildingState.isEvaluating(), "%s %s", this, childForDebugging);
486 dirtyBuildingState.signalDep();
487 dirtyBuildingState.signalDepPostProcess(
488 childCausesReevaluation(lastEvaluatedVersion, childVersion, childForDebugging),
489 getNumTemporaryDirectDeps());
Janak Ramakrishnanab10f472017-03-24 17:08:24 +0000490 return isReady();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000491 }
492
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000493 /** Checks that a caller is not trying to access not-stored graph edges. */
janakr1cde8722017-10-10 03:22:21 +0200494 private void assertKeepDeps() {
495 Preconditions.checkState(keepEdges() != KeepEdgesPolicy.NONE, "Not keeping deps: %s", this);
496 }
497
498 /** Checks that a caller is not trying to access not-stored graph edges. */
499 private void assertKeepRdeps() {
500 Preconditions.checkState(keepEdges() == KeepEdgesPolicy.ALL, "Not keeping rdeps: %s", this);
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000501 }
502
503 @Override
mschaller7138b072018-09-28 10:14:11 -0700504 public synchronized MarkedDirtyResult markDirty(DirtyType dirtyType) {
janakr1cde8722017-10-10 03:22:21 +0200505 // Can't process a dirty node without its deps.
506 assertKeepDeps();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000507 if (isDone()) {
Janak Ramakrishnanab10f472017-03-24 17:08:24 +0000508 dirtyBuildingState =
Googlerbaefeab2019-04-30 17:12:55 -0700509 DirtyBuildingState.create(
510 dirtyType, GroupedList.create(getCompressedDirectDepsForDoneEntry()), value);
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000511 value = null;
Janak Ramakrishnan50934992016-07-06 17:09:51 +0000512 directDeps = null;
mschaller7138b072018-09-28 10:14:11 -0700513 return new MarkedDirtyResult(ReverseDepsUtility.getReverseDeps(this));
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000514 }
mschaller7138b072018-09-28 10:14:11 -0700515 if (dirtyType.equals(DirtyType.FORCE_REBUILD)) {
mschaller0d7c71a2019-03-05 08:50:21 -0800516 if (dirtyBuildingState != null) {
517 dirtyBuildingState.markForceRebuild();
518 }
mschaller7138b072018-09-28 10:14:11 -0700519 return null;
520 }
521 // The caller may be simultaneously trying to mark this node dirty and changed, and the dirty
522 // thread may have lost the race, but it is the caller's responsibility not to try to mark
523 // this node changed twice. The end result of racing markers must be a changed node, since one
524 // of the markers is trying to mark the node changed.
525 Preconditions.checkState(
526 dirtyType.equals(DirtyType.CHANGE) != isChanged(),
527 "Cannot mark node dirty twice or changed twice: %s",
528 this);
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000529 Preconditions.checkState(value == null, "Value should have been reset already %s", this);
mschaller7138b072018-09-28 10:14:11 -0700530 if (dirtyType.equals(DirtyType.CHANGE)) {
ulfjack9beabe02019-02-13 23:41:59 -0800531 Preconditions.checkNotNull(dirtyBuildingState);
mschaller7138b072018-09-28 10:14:11 -0700532 // If the changed marker lost the race, we just need to mark changed in this method -- all
533 // other work was done by the dirty marker.
ulfjack9beabe02019-02-13 23:41:59 -0800534 dirtyBuildingState.markChanged();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000535 }
mschaller7138b072018-09-28 10:14:11 -0700536 return null;
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000537 }
538
539 @Override
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000540 public synchronized Set<SkyKey> markClean() throws InterruptedException {
ulfjack9beabe02019-02-13 23:41:59 -0800541 Preconditions.checkNotNull(dirtyBuildingState, this);
542 this.value = Preconditions.checkNotNull(dirtyBuildingState.getLastBuildValue());
Janak Ramakrishnan50934992016-07-06 17:09:51 +0000543 Preconditions.checkState(isReady(), "Should be ready when clean: %s", this);
544 Preconditions.checkState(
ulfjack9beabe02019-02-13 23:41:59 -0800545 dirtyBuildingState.depsUnchangedFromLastBuild(getTemporaryDirectDeps()),
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000546 "Direct deps must be the same as those found last build for node to be marked clean: %s",
547 this);
548 Preconditions.checkState(isDirty(), this);
Janak Ramakrishnanab10f472017-03-24 17:08:24 +0000549 Preconditions.checkState(!dirtyBuildingState.isChanged(), "shouldn't be changed: %s", this);
Janak Ramakrishnan772b5bb2016-06-29 00:20:36 +0000550 return setStateFinishedAndReturnReverseDepsToSignal();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000551 }
552
553 @Override
554 public synchronized void forceRebuild() {
ulfjack9beabe02019-02-13 23:41:59 -0800555 Preconditions.checkNotNull(dirtyBuildingState, this);
556 Preconditions.checkState(isEvaluating(), this);
557 dirtyBuildingState.forceRebuild(getNumTemporaryDirectDeps());
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000558 }
559
560 @Override
Googlerc5a2f812018-08-21 14:08:59 -0700561 public Version getVersion() {
Janak Ramakrishnan1d22d4c2015-11-18 19:28:45 +0000562 return lastChangedVersion;
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000563 }
564
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000565 @Override
566 public synchronized NodeEntry.DirtyState getDirtyState() {
ulfjack9beabe02019-02-13 23:41:59 -0800567 Preconditions.checkNotNull(dirtyBuildingState, this);
568 return dirtyBuildingState.getDirtyState();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000569 }
570
Janak Ramakrishnan5dddb002016-07-06 20:07:23 +0000571 /** @see DirtyBuildingState#getNextDirtyDirectDeps() */
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000572 @Override
janakrad1c2e42019-02-08 14:00:03 -0800573 public synchronized List<SkyKey> getNextDirtyDirectDeps() throws InterruptedException {
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000574 Preconditions.checkState(isReady(), this);
ulfjack9beabe02019-02-13 23:41:59 -0800575 Preconditions.checkNotNull(dirtyBuildingState, this);
576 Preconditions.checkState(
577 dirtyBuildingState.isEvaluating(), "Not evaluating during getNextDirty? %s", this);
578 return dirtyBuildingState.getNextDirtyDirectDeps();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000579 }
580
581 @Override
Googler8d2311d2017-01-31 22:52:26 +0000582 public synchronized Iterable<SkyKey> getAllDirectDepsForIncompleteNode()
583 throws InterruptedException {
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000584 Preconditions.checkState(!isDone(), this);
585 if (!isDirty()) {
shreyaxa6679ae2018-03-02 15:59:46 -0800586 return getTemporaryDirectDeps().getAllElementsAsIterable();
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000587 } else {
Janak Ramakrishnanf76c9592016-05-17 21:42:50 +0000588 // There may be duplicates here. Make sure everything is unique.
589 ImmutableSet.Builder<SkyKey> result = ImmutableSet.builder();
590 for (Iterable<SkyKey> group : getTemporaryDirectDeps()) {
591 result.addAll(group);
592 }
ulfjack9beabe02019-02-13 23:41:59 -0800593 result.addAll(dirtyBuildingState.getAllRemainingDirtyDirectDeps(/*preservePosition=*/ false));
Janak Ramakrishnanf76c9592016-05-17 21:42:50 +0000594 return result.build();
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000595 }
596 }
597
598 @Override
janakr3cb0c392019-03-29 20:08:41 -0700599 public synchronized ImmutableSet<SkyKey> getAllRemainingDirtyDirectDeps()
600 throws InterruptedException {
ulfjack9beabe02019-02-13 23:41:59 -0800601 Preconditions.checkNotNull(dirtyBuildingState, this);
602 Preconditions.checkState(
603 dirtyBuildingState.isEvaluating(), "Not evaluating for remaining dirty? %s", this);
Janak Ramakrishnanf76c9592016-05-17 21:42:50 +0000604 if (isDirty()) {
ulfjack9beabe02019-02-13 23:41:59 -0800605 DirtyState dirtyState = dirtyBuildingState.getDirtyState();
Janak Ramakrishnan5dddb002016-07-06 20:07:23 +0000606 Preconditions.checkState(
janakre54491e2018-07-11 16:29:13 -0700607 dirtyState == DirtyState.REBUILDING || dirtyState == DirtyState.FORCED_REBUILDING, this);
ulfjack9beabe02019-02-13 23:41:59 -0800608 return dirtyBuildingState.getAllRemainingDirtyDirectDeps(/*preservePosition=*/ true);
Janak Ramakrishnanf76c9592016-05-17 21:42:50 +0000609 } else {
Janak Ramakrishnanf76c9592016-05-17 21:42:50 +0000610 return ImmutableSet.of();
611 }
612 }
613
614 @Override
janakra2d4d3d2018-12-10 18:30:08 -0800615 public boolean canPruneDepsByFingerprint() {
616 return false;
617 }
618
619 @Nullable
620 @Override
621 public Iterable<SkyKey> getLastDirectDepsGroupWhenPruningDepsByFingerprint()
622 throws InterruptedException {
623 throw new UnsupportedOperationException(this.toString());
624 }
625
626 @Override
627 public boolean unmarkNeedsRebuildingIfGroupUnchangedUsingFingerprint(
628 BigInteger groupFingerprint) {
629 throw new UnsupportedOperationException(this.toString());
630 }
631
632 /**
633 * If this entry {@link #canPruneDepsByFingerprint} and has that data, returns a list of dep group
634 * fingerprints. Otherwise returns null.
635 */
636 @Nullable
637 public DepFingerprintList getDepFingerprintList() {
638 Preconditions.checkState(isDone(), this);
639 return null;
640 }
641
642 @Override
Janak Ramakrishnanf76c9592016-05-17 21:42:50 +0000643 public synchronized void markRebuilding() {
ulfjack9beabe02019-02-13 23:41:59 -0800644 Preconditions.checkNotNull(dirtyBuildingState, this);
645 dirtyBuildingState.markRebuilding(isEligibleForChangePruningOnUnchangedValue());
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000646 }
647
Janak Ramakrishnan50934992016-07-06 17:09:51 +0000648 @SuppressWarnings("unchecked")
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000649 @Override
Janak Ramakrishnan3b5d5d22016-05-13 21:14:56 +0000650 public synchronized GroupedList<SkyKey> getTemporaryDirectDeps() {
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000651 Preconditions.checkState(!isDone(), "temporary shouldn't be done: %s", this);
Janak Ramakrishnan50934992016-07-06 17:09:51 +0000652 if (directDeps == null) {
653 // Initialize lazily, to save a little bit of memory.
654 directDeps = new GroupedList<SkyKey>();
655 }
656 return (GroupedList<SkyKey>) directDeps;
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000657 }
658
felly44eb9642018-03-27 12:41:13 -0700659 private synchronized int getNumTemporaryDirectDeps() {
660 return directDeps == null ? 0 : getTemporaryDirectDeps().numElements();
661 }
662
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000663 @Override
664 public synchronized boolean noDepsLastBuild() {
ulfjack9beabe02019-02-13 23:41:59 -0800665 Preconditions.checkState(isEvaluating(), this);
666 return dirtyBuildingState.noDepsLastBuild();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000667 }
668
Janak Ramakrishnan50934992016-07-06 17:09:51 +0000669 /**
670 * {@inheritDoc}
671 *
672 * <p>This is complicated by the need to maintain the group data. If we remove a dep that ended a
673 * group, then its predecessor's group data must be changed to indicate that it now ends the
674 * group.
675 */
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000676 @Override
677 public synchronized void removeUnfinishedDeps(Set<SkyKey> unfinishedDeps) {
Janak Ramakrishnan50934992016-07-06 17:09:51 +0000678 getTemporaryDirectDeps().remove(unfinishedDeps);
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000679 }
680
681 @Override
janakr46706ae2018-04-30 16:18:50 -0700682 public synchronized void resetForRestartFromScratch() {
mschalleraf4493c2019-05-08 12:04:47 -0700683 Preconditions.checkState(isReady(), this);
janakr46706ae2018-04-30 16:18:50 -0700684 directDeps = null;
ulfjack9beabe02019-02-13 23:41:59 -0800685 dirtyBuildingState.resetForRestartFromScratch();
janakr46706ae2018-04-30 16:18:50 -0700686 }
687
688 @Override
Janak Ramakrishnan2b8a3a42016-10-14 11:41:27 +0000689 public synchronized Set<SkyKey> addTemporaryDirectDeps(GroupedListHelper<SkyKey> helper) {
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000690 Preconditions.checkState(!isDone(), "add temp shouldn't be done: %s %s", helper, this);
Janak Ramakrishnan2b8a3a42016-10-14 11:41:27 +0000691 return getTemporaryDirectDeps().append(helper);
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000692 }
693
694 @Override
janakrad1c2e42019-02-08 14:00:03 -0800695 public synchronized void addTemporaryDirectDepsGroupToDirtyEntry(List<SkyKey> group) {
Mark Schallerd1cd14b2015-12-09 16:23:22 +0000696 Preconditions.checkState(!isDone(), "add group temp shouldn't be done: %s %s", group, this);
Janak Ramakrishnan50934992016-07-06 17:09:51 +0000697 getTemporaryDirectDeps().appendGroup(group);
Mark Schallerd1cd14b2015-12-09 16:23:22 +0000698 }
699
janakr8d98d922018-10-03 15:55:28 -0700700 /** True if the child should cause re-evaluation of this node. */
shahan44666dc2018-10-05 17:47:11 -0700701 protected boolean childCausesReevaluation(
702 Version lastEvaluatedVersion,
703 Version childVersion,
704 @Nullable SkyKey unusedChildForDebugging) {
shahand4a6ca02018-10-03 11:41:28 -0700705 // childVersion > lastEvaluatedVersion
706 return !childVersion.atMost(lastEvaluatedVersion);
707 }
708
shahand4a6ca02018-10-03 11:41:28 -0700709 protected void logError(RuntimeException error) {
710 throw error;
711 }
712
janakra2d4d3d2018-12-10 18:30:08 -0800713 protected synchronized MoreObjects.ToStringHelper toStringHelper() {
Googler2c19a572015-07-16 08:38:49 +0000714 return MoreObjects.toStringHelper(this)
Janak Ramakrishnan5877b8b2015-09-22 17:37:10 +0000715 .add("identity", System.identityHashCode(this))
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000716 .add("value", value)
Janak Ramakrishnan1d22d4c2015-11-18 19:28:45 +0000717 .add("lastChangedVersion", lastChangedVersion)
718 .add("lastEvaluatedVersion", lastEvaluatedVersion)
janakrdd4c47f2019-02-08 17:03:19 -0800719 .add(
720 "directDeps",
721 isDone() && keepEdges() != KeepEdgesPolicy.NONE
Googlerbaefeab2019-04-30 17:12:55 -0700722 ? GroupedList.create(getCompressedDirectDepsForDoneEntry())
janakrdd4c47f2019-02-08 17:03:19 -0800723 : directDeps)
Janak Ramakrishnancb8a97d2017-03-23 20:50:08 +0000724 .add("reverseDeps", ReverseDepsUtility.toString(this))
janakra2d4d3d2018-12-10 18:30:08 -0800725 .add("dirtyBuildingState", dirtyBuildingState);
726 }
727
728 @Override
729 public final synchronized String toString() {
730 return toStringHelper().toString();
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000731 }
732
janakr1cde8722017-10-10 03:22:21 +0200733 protected synchronized InMemoryNodeEntry cloneNodeEntry(InMemoryNodeEntry newEntry) {
734 // As this is temporary, for now let's limit to done nodes.
735 Preconditions.checkState(isDone(), "Only done nodes can be copied: %s", this);
736 newEntry.value = value;
737 newEntry.lastChangedVersion = this.lastChangedVersion;
738 newEntry.lastEvaluatedVersion = this.lastEvaluatedVersion;
739 ReverseDepsUtility.addReverseDeps(newEntry, ReverseDepsUtility.getReverseDeps(this));
740 newEntry.directDeps = directDeps;
741 newEntry.dirtyBuildingState = null;
742 return newEntry;
743 }
744
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000745 /**
746 * Do not use except in custom evaluator implementations! Added only temporarily.
747 *
748 * <p>Clones a InMemoryMutableNodeEntry iff it is a done node. Otherwise it fails.
749 */
750 public synchronized InMemoryNodeEntry cloneNodeEntry() {
janakr1cde8722017-10-10 03:22:21 +0200751 return cloneNodeEntry(new InMemoryNodeEntry());
Nathan Harmatab408f9e2015-02-10 02:13:05 +0000752 }
753}