blob: 37233f088899b83e6ade2b76b2c9295312fa8736 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
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
tomlua155b532017-11-08 20:12:47 +010016import com.google.common.base.Preconditions;
Janak Ramakrishnan1acd4662016-02-10 20:30:41 +000017import com.google.common.collect.ImmutableList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010018import com.google.devtools.build.skyframe.GraphTester.ValueComputer;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010019import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010020import java.util.concurrent.CountDownLatch;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010021import javax.annotation.Nullable;
22
23/**
24 * {@link ValueComputer} that can be chained together with others of its type to synchronize the
25 * order in which builders finish.
26 */
Janak Ramakrishnan1acd4662016-02-10 20:30:41 +000027public final class ChainedFunction implements SkyFunction {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010028 @Nullable private final SkyValue value;
janakrb4ff31b2019-01-14 08:29:37 -080029 private final Runnable notifyStart;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010030 @Nullable private final CountDownLatch waitToFinish;
janakrb4ff31b2019-01-14 08:29:37 -080031 private final Runnable notifyFinish;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010032 private final boolean waitForException;
33 private final Iterable<SkyKey> deps;
34
Janak Ramakrishnan1acd4662016-02-10 20:30:41 +000035 /** Do not use! Use {@link Builder} instead. */
36 ChainedFunction(
37 @Nullable CountDownLatch notifyStart,
38 @Nullable CountDownLatch waitToFinish,
39 @Nullable CountDownLatch notifyFinish,
40 boolean waitForException,
41 @Nullable SkyValue value,
42 Iterable<SkyKey> deps) {
janakrb4ff31b2019-01-14 08:29:37 -080043 this(
44 makeRunnable(notifyStart),
45 waitToFinish,
46 makeRunnable(notifyFinish),
47 waitForException,
48 value,
49 deps);
50 }
51
52 private ChainedFunction(
53 Runnable notifyStart,
54 @Nullable CountDownLatch waitToFinish,
55 Runnable notifyFinish,
56 boolean waitForException,
57 @Nullable SkyValue value,
58 Iterable<SkyKey> deps) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010059 this.notifyStart = notifyStart;
60 this.waitToFinish = waitToFinish;
61 this.notifyFinish = notifyFinish;
62 this.waitForException = waitForException;
63 Preconditions.checkState(this.waitToFinish != null || !this.waitForException, value);
64 this.value = value;
65 this.deps = deps;
66 }
67
68 @Override
69 public SkyValue compute(SkyKey key, SkyFunction.Environment env) throws GenericFunctionException,
70 InterruptedException {
71 try {
janakrb4ff31b2019-01-14 08:29:37 -080072 notifyStart.run();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010073 if (waitToFinish != null) {
Janak Ramakrishnana67bb8b2015-09-02 17:56:08 +000074 TrackingAwaiter.INSTANCE.awaitLatchAndTrackExceptions(
75 waitToFinish, key + " timed out waiting to finish");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010076 if (waitForException) {
77 SkyFunctionEnvironment skyEnv = (SkyFunctionEnvironment) env;
Janak Ramakrishnana67bb8b2015-09-02 17:56:08 +000078 TrackingAwaiter.INSTANCE.awaitLatchAndTrackExceptions(
79 skyEnv.getExceptionLatchForTesting(), key + " timed out waiting for exception");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010080 }
81 }
82 for (SkyKey dep : deps) {
83 env.getValue(dep);
84 }
85 if (value == null) {
86 throw new GenericFunctionException(new SomeErrorException("oops"),
87 Transience.PERSISTENT);
88 }
89 if (env.valuesMissing()) {
90 return null;
91 }
92 return value;
93 } finally {
janakrb4ff31b2019-01-14 08:29:37 -080094 notifyFinish.run();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010095 }
96 }
97
janakrb4ff31b2019-01-14 08:29:37 -080098 private static Runnable makeRunnable(@Nullable CountDownLatch latch) {
99 return latch != null ? latch::countDown : () -> {};
100 }
101
Janak Ramakrishnan1acd4662016-02-10 20:30:41 +0000102 /** Builder for {@link ChainedFunction} objects. */
103 public static class Builder {
104 @Nullable private SkyValue value;
janakrb4ff31b2019-01-14 08:29:37 -0800105 Runnable notifyStart = makeRunnable(null);
Janak Ramakrishnan1acd4662016-02-10 20:30:41 +0000106 @Nullable private CountDownLatch waitToFinish;
janakrb4ff31b2019-01-14 08:29:37 -0800107 private Runnable notifyFinish = makeRunnable(null);
Janak Ramakrishnan1acd4662016-02-10 20:30:41 +0000108 private boolean waitForException;
109 private Iterable<SkyKey> deps = ImmutableList.of();
110
111 public Builder setValue(SkyValue value) {
112 this.value = value;
113 return this;
114 }
115
janakrb4ff31b2019-01-14 08:29:37 -0800116 public Builder setNotifyStart(Runnable notifyStart) {
Janak Ramakrishnan1acd4662016-02-10 20:30:41 +0000117 this.notifyStart = notifyStart;
118 return this;
119 }
120
121 public Builder setWaitToFinish(CountDownLatch waitToFinish) {
122 this.waitToFinish = waitToFinish;
123 return this;
124 }
125
janakrb4ff31b2019-01-14 08:29:37 -0800126 public Builder setNotifyFinish(Runnable notifyFinish) {
Janak Ramakrishnan1acd4662016-02-10 20:30:41 +0000127 this.notifyFinish = notifyFinish;
128 return this;
129 }
130
131 public Builder setWaitForException(boolean waitForException) {
132 this.waitForException = waitForException;
133 return this;
134 }
135
136 public Builder setDeps(Iterable<SkyKey> deps) {
137 this.deps = Preconditions.checkNotNull(deps);
138 return this;
139 }
140
141 public SkyFunction build() {
142 return new ChainedFunction(
143 notifyStart, waitToFinish, notifyFinish, waitForException, value, deps);
144 }
145 }
146
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100147 @Override
148 public String extractTag(SkyKey skyKey) {
149 throw new UnsupportedOperationException();
150 }
151}