blob: a1bb69a924dd44d55d75015fe65b7f585ebdc062 [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.lib.buildtool;
15
mstaibd9b141d2017-09-14 20:47:31 +020016import static com.google.common.collect.ImmutableSet.toImmutableSet;
Eric Fellheimere9b41c62016-06-14 15:39:51 +000017
steinman13a628a2019-01-09 08:39:32 -080018import com.google.common.annotations.VisibleForTesting;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010019import com.google.common.base.Predicate;
20import com.google.common.base.Stopwatch;
mschaller40379082019-02-01 14:14:47 -080021import com.google.common.base.Throwables;
Philipp Wollermann45bf15b2015-06-18 13:06:16 +000022import com.google.common.collect.ImmutableList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010023import com.google.common.collect.ImmutableMap;
24import com.google.common.collect.ImmutableSet;
ichern121933e2020-01-27 02:08:19 -080025import com.google.common.collect.ImmutableSortedSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010026import com.google.devtools.build.lib.actions.Action;
27import com.google.devtools.build.lib.actions.ActionCacheChecker;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010028import com.google.devtools.build.lib.actions.ActionGraph;
ulfjack5b99e502017-07-20 22:22:36 +020029import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
Ulf Adams3d67e002016-03-29 16:23:01 +000030import com.google.devtools.build.lib.actions.ArtifactFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010031import com.google.devtools.build.lib.actions.BuildFailedException;
schmitt37aeabc2020-01-27 08:34:29 -080032import com.google.devtools.build.lib.actions.DynamicStrategyRegistry;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010033import com.google.devtools.build.lib.actions.Executor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010034import com.google.devtools.build.lib.actions.ExecutorInitException;
35import com.google.devtools.build.lib.actions.LocalHostCapacity;
janakrae323982017-09-29 21:11:53 +020036import com.google.devtools.build.lib.actions.PackageRoots;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010037import com.google.devtools.build.lib.actions.ResourceManager;
Mark Schallerdffb6ee2015-02-25 20:01:01 +000038import com.google.devtools.build.lib.actions.ResourceSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010039import com.google.devtools.build.lib.actions.TestExecException;
40import com.google.devtools.build.lib.actions.cache.ActionCache;
jmmvccb43ee2017-08-30 22:07:10 +020041import com.google.devtools.build.lib.actions.cache.Protos.ActionCacheStatistics;
ulfjackc23bdac2018-06-13 03:06:16 -070042import com.google.devtools.build.lib.analysis.AnalysisResult;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010043import com.google.devtools.build.lib.analysis.ConfiguredTarget;
Googlerbfd4e242016-07-15 22:23:37 +000044import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010045import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper;
Lukacs Berki7b2f2e82016-11-23 14:16:43 +000046import com.google.devtools.build.lib.analysis.actions.SymlinkTreeActionContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010047import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
brandjon7b5043f2019-11-25 12:30:22 -080048import com.google.devtools.build.lib.analysis.config.BuildOptions;
49import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
schmitt4d6aff92020-01-13 10:49:30 -080050import com.google.devtools.build.lib.analysis.test.TestActionContext;
Googler87636392019-12-30 12:57:56 -080051import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.ConvenienceSymlink;
52import com.google.devtools.build.lib.buildtool.BuildRequestOptions.ConvenienceSymlinksMode;
53import com.google.devtools.build.lib.buildtool.buildevent.ConvenienceSymlinksIdentifiedEvent;
arostovtsev20b056a2019-08-30 15:00:31 -070054import com.google.devtools.build.lib.buildtool.buildevent.ExecRootPreparedEvent;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010055import com.google.devtools.build.lib.buildtool.buildevent.ExecutionPhaseCompleteEvent;
56import com.google.devtools.build.lib.buildtool.buildevent.ExecutionStartingEvent;
Kristina Chodorow33aada22016-06-22 14:23:47 +000057import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010058import com.google.devtools.build.lib.events.Event;
59import com.google.devtools.build.lib.events.EventHandler;
60import com.google.devtools.build.lib.events.EventKind;
61import com.google.devtools.build.lib.events.Reporter;
Ulf Adamsdba3c832016-12-21 16:50:02 +000062import com.google.devtools.build.lib.exec.BlazeExecutor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010063import com.google.devtools.build.lib.exec.CheckUpToDateFilter;
64import com.google.devtools.build.lib.exec.ExecutionOptions;
Ulf Adamsdba3c832016-12-21 16:50:02 +000065import com.google.devtools.build.lib.exec.ExecutorBuilder;
schmittbe241a12020-01-16 13:30:55 -080066import com.google.devtools.build.lib.exec.ExecutorLifecycleListener;
schmitt37aeabc2020-01-27 08:34:29 -080067import com.google.devtools.build.lib.exec.ModuleActionContextRegistry;
68import com.google.devtools.build.lib.exec.RemoteLocalFallbackRegistry;
69import com.google.devtools.build.lib.exec.SpawnStrategyRegistry;
70import com.google.devtools.build.lib.exec.SpawnStrategyResolver;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010071import com.google.devtools.build.lib.exec.SymlinkTreeStrategy;
Nathan Harmatad4803012015-09-08 20:03:22 +000072import com.google.devtools.build.lib.profiler.AutoProfiler;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010073import com.google.devtools.build.lib.profiler.ProfilePhase;
74import com.google.devtools.build.lib.profiler.Profiler;
75import com.google.devtools.build.lib.profiler.ProfilerTask;
ulfjack4cf2ebd2018-06-11 06:00:36 -070076import com.google.devtools.build.lib.profiler.SilentCloseable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010077import com.google.devtools.build.lib.runtime.BlazeModule;
78import com.google.devtools.build.lib.runtime.BlazeRuntime;
Ulf Adams633f5392015-09-15 11:13:08 +000079import com.google.devtools.build.lib.runtime.CommandEnvironment;
Dmitry Lomove2033b12015-08-19 16:57:49 +000080import com.google.devtools.build.lib.skyframe.AspectValue;
tomlu6ed4fd52018-04-03 10:01:10 -070081import com.google.devtools.build.lib.skyframe.AspectValue.AspectKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010082import com.google.devtools.build.lib.skyframe.Builder;
cpeyser8e9b28f2018-06-04 08:05:13 -070083import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010084import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010085import com.google.devtools.build.lib.util.AbruptExitException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010086import com.google.devtools.build.lib.util.LoggingUtil;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010087import com.google.devtools.build.lib.vfs.FileSystemUtils;
Eric Fellheimerf3b43af2015-11-13 19:51:20 +000088import com.google.devtools.build.lib.vfs.ModifiedFileSet;
shahane35e8cf2018-06-18 08:14:01 -070089import com.google.devtools.build.lib.vfs.OutputService;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010090import com.google.devtools.build.lib.vfs.Path;
91import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080092import com.google.devtools.build.lib.vfs.Root;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010093import java.io.IOException;
94import java.io.OutputStream;
lberki0d8d4cf2017-09-05 16:01:44 +020095import java.io.OutputStreamWriter;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010096import java.io.PrintWriter;
lberki0d8d4cf2017-09-05 16:01:44 +020097import java.nio.charset.StandardCharsets;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010098import java.util.Collection;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010099import java.util.HashSet;
100import java.util.LinkedHashSet;
janakrae323982017-09-29 21:11:53 +0200101import java.util.Optional;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100102import java.util.Set;
Eric Fellheimer2db6a742015-04-28 21:38:43 +0000103import java.util.UUID;
jmmvccb43ee2017-08-30 22:07:10 +0200104import java.util.concurrent.TimeUnit;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100105import java.util.logging.Level;
106import java.util.logging.Logger;
brandjon7b5043f2019-11-25 12:30:22 -0800107import javax.annotation.Nullable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100108
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100109/**
110 * This class manages the execution phase. The entry point is {@link #executeBuild}.
111 *
112 * <p>This is only intended for use by {@link BuildTool}.
113 *
mstaibd9b141d2017-09-14 20:47:31 +0200114 * <p>This class contains an ActionCache, and refers to the Blaze Runtime's BuildView and
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100115 * PackageCache.
116 *
117 * @see BuildTool
Kristina Chodorowe423fdb2016-09-15 14:08:08 +0000118 * @see com.google.devtools.build.lib.analysis.BuildView
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100119 */
120public class ExecutionTool {
lberki97abb522017-09-04 18:51:57 +0200121 static final Logger logger = Logger.getLogger(ExecutionTool.class.getName());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100122
Ulf Adams633f5392015-09-15 11:13:08 +0000123 private final CommandEnvironment env;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100124 private final BlazeRuntime runtime;
125 private final BuildRequest request;
126 private BlazeExecutor executor;
Ulf Adamsccd5c0a2017-01-13 15:46:51 +0000127 private final ActionInputPrefetcher prefetcher;
schmitt37aeabc2020-01-27 08:34:29 -0800128 private final SpawnStrategyRegistry spawnStrategyRegistry;
129 private final ModuleActionContextRegistry actionContextRegistry;
schmittbe241a12020-01-16 13:30:55 -0800130 private final ImmutableSet<ExecutorLifecycleListener> executorLifecycleListeners;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100131
Ulf Adams633f5392015-09-15 11:13:08 +0000132 ExecutionTool(CommandEnvironment env, BuildRequest request) throws ExecutorInitException {
133 this.env = env;
134 this.runtime = env.getRuntime();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100135 this.request = request;
136
felly472320c2018-10-29 14:27:00 -0700137 try {
138 env.getExecRoot().createDirectoryAndParents();
139 } catch (IOException e) {
140 throw new ExecutorInitException("Execroot creation failed", e);
ulfjackef5b63d2018-06-15 07:19:11 -0700141 }
Philipp Wollermann590ea392015-08-25 13:57:33 +0000142
schmitt37aeabc2020-01-27 08:34:29 -0800143 ExecutionOptions options = request.getOptions(ExecutionOptions.class);
Ulf Adamsa0e3af42016-10-31 16:52:48 +0000144 ExecutorBuilder builder = new ExecutorBuilder();
schmitt37aeabc2020-01-27 08:34:29 -0800145 ModuleActionContextRegistry.Builder actionContextRegistryBuilder =
146 new ModuleActionContextRegistry.Builder()
147 // TODO(philwo): ExecutionTool should not modify action contexts on its own, instead
148 // these should be added and restricted in modules.
149 .restrictTo(TestActionContext.class, options.testStrategy)
150 .register(
151 SymlinkTreeActionContext.class,
152 new SymlinkTreeStrategy(
153 env.getOutputService(), env.getBlazeWorkspace().getBinTools()))
154 .register(SpawnStrategyResolver.class, new SpawnStrategyResolver());
155 SpawnStrategyRegistry.Builder spawnStrategyRegistryBuilder =
156 new SpawnStrategyRegistry.Builder()
157 // TODO: Wrap in incompatible flag.
158 .useLegacyDescriptionFilterPrecedence();
Ulf Adamsa0e3af42016-10-31 16:52:48 +0000159 for (BlazeModule module : runtime.getBlazeModules()) {
schmitt37aeabc2020-01-27 08:34:29 -0800160 try (SilentCloseable ignored = Profiler.instance().profile(module + ".executorInit")) {
ulfjackef5b63d2018-06-15 07:19:11 -0700161 module.executorInit(env, request, builder);
162 }
schmitt37aeabc2020-01-27 08:34:29 -0800163
164 try (SilentCloseable ignored =
165 Profiler.instance().profile(module + ".registerActionContexts")) {
166 module.registerActionContexts(actionContextRegistryBuilder, env, request);
167 }
168
169 try (SilentCloseable ignored =
170 Profiler.instance().profile(module + ".registerSpawnStrategies")) {
171 module.registerSpawnStrategies(spawnStrategyRegistryBuilder, env);
172 }
Ulf Adamsa0e3af42016-10-31 16:52:48 +0000173 }
schmitt37aeabc2020-01-27 08:34:29 -0800174
175 spawnStrategyRegistry = spawnStrategyRegistryBuilder.build();
176 actionContextRegistryBuilder.register(SpawnStrategyRegistry.class, spawnStrategyRegistry);
177 actionContextRegistryBuilder.register(DynamicStrategyRegistry.class, spawnStrategyRegistry);
178 actionContextRegistryBuilder.register(RemoteLocalFallbackRegistry.class, spawnStrategyRegistry);
179
180 actionContextRegistry = actionContextRegistryBuilder.build();
181 executorLifecycleListeners = builder.getExecutorLifecycleListeners();
schmitt4d6aff92020-01-13 10:49:30 -0800182
Ulf Adamsccd5c0a2017-01-13 15:46:51 +0000183 this.prefetcher = builder.getActionInputPrefetcher();
steinman3501b212019-03-25 12:36:43 -0700184
185 if (options.availableResources != null && options.removeLocalResources) {
186 throw new ExecutorInitException(
187 "--local_resources is deprecated. Please use "
188 + "--local_ram_resources and/or --local_cpu_resources");
189 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100190 }
191
192 Executor getExecutor() throws ExecutorInitException {
193 if (executor == null) {
194 executor = createExecutor();
schmittbe241a12020-01-16 13:30:55 -0800195 for (ExecutorLifecycleListener executorLifecycleListener : executorLifecycleListeners) {
196 executorLifecycleListener.executorCreated();
197 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100198 }
199 return executor;
200 }
201
buchgr7b515522019-03-29 04:42:17 -0700202 /** Creates an executor for the current set of blaze runtime, execution options, and request. */
203 private BlazeExecutor createExecutor() throws ExecutorInitException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100204 return new BlazeExecutor(
tomluf903eb52017-10-27 12:12:11 -0400205 runtime.getFileSystem(),
Ulf Adams94b72db2016-03-30 11:58:37 +0000206 env.getExecRoot(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100207 getReporter(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100208 runtime.getClock(),
209 request,
schmitt37aeabc2020-01-27 08:34:29 -0800210 actionContextRegistry,
211 spawnStrategyRegistry);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100212 }
213
214 void init() throws ExecutorInitException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100215 getExecutor();
216 }
217
218 void shutdown() {
schmittbe241a12020-01-16 13:30:55 -0800219 for (ExecutorLifecycleListener executorLifecycleListener : executorLifecycleListeners) {
220 executorLifecycleListener.executionPhaseEnding();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100221 }
222 }
223
224 /**
janakrae323982017-09-29 21:11:53 +0200225 * Performs the execution phase (phase 3) of the build, in which the Builder is applied to the
226 * action graph to bring the targets up to date. (This function will return prior to
227 * execution-proper if --nobuild was specified.)
228 *
Eric Fellheimer2db6a742015-04-28 21:38:43 +0000229 * @param buildId UUID of the build id
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100230 * @param analysisResult the analysis phase output
231 * @param buildResult the mutable build result
Lukacs Berki3ea4d442016-01-21 15:15:30 +0000232 * @param packageRoots package roots collected from loading phase and BuildConfigurationCollection
janakrae323982017-09-29 21:11:53 +0200233 * creation. May be empty if {@link
234 * SkyframeExecutor#getForcedSingleSourceRootIfNoExecrootSymlinkCreation} is false.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100235 */
janakrae323982017-09-29 21:11:53 +0200236 void executeBuild(
237 UUID buildId,
238 AnalysisResult analysisResult,
Laurent Le Brunf3cf98f2016-06-17 13:36:24 +0000239 BuildResult buildResult,
janakrae323982017-09-29 21:11:53 +0200240 PackageRoots packageRoots,
Googlerbfd4e242016-07-15 22:23:37 +0000241 TopLevelArtifactContext topLevelArtifactContext)
Nathan Harmataca06fa22015-07-27 19:54:14 +0000242 throws BuildFailedException, InterruptedException, TestExecException, AbruptExitException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100243 Stopwatch timer = Stopwatch.createStarted();
ichern121933e2020-01-27 02:08:19 -0800244 prepare(packageRoots, analysisResult.getNonSymlinkedDirectoriesUnderExecRoot());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100245
246 ActionGraph actionGraph = analysisResult.getActionGraph();
247
Ulf Adams706b7f22015-10-20 09:06:45 +0000248 OutputService outputService = env.getOutputService();
Eric Fellheimerf3b43af2015-11-13 19:51:20 +0000249 ModifiedFileSet modifiedOutputFiles = ModifiedFileSet.EVERYTHING_MODIFIED;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100250 if (outputService != null) {
ulfjackef5b63d2018-06-15 07:19:11 -0700251 try (SilentCloseable c = Profiler.instance().profile("outputService.startBuild")) {
252 modifiedOutputFiles =
253 outputService.startBuild(
254 env.getReporter(), buildId, request.getBuildOptions().finalizeActions);
255 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100256 } else {
Kristina Chodorowe423fdb2016-09-15 14:08:08 +0000257 // TODO(bazel-team): this could be just another OutputService
ulfjackef5b63d2018-06-15 07:19:11 -0700258 try (SilentCloseable c = Profiler.instance().profile("startLocalOutputBuild")) {
259 startLocalOutputBuild();
260 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100261 }
262
buchgr7b515522019-03-29 04:42:17 -0700263 if (outputService == null || !outputService.actionFileSystemType().inMemoryFileSystem()) {
264 // Must be created after the output path is created above.
265 createActionLogDirectory();
266 }
janakr0049e962017-04-05 21:41:23 +0000267
Googler87636392019-12-30 12:57:56 -0800268 handleConvenienceSymlinks(analysisResult);
Lukacs Berki85c63c42016-01-22 09:25:20 +0000269
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100270 ActionCache actionCache = getActionCache();
jmmv9573a0d2017-09-26 11:59:22 -0400271 actionCache.resetStatistics();
Ulf Adams80613022015-09-16 09:11:33 +0000272 SkyframeExecutor skyframeExecutor = env.getSkyframeExecutor();
ulfjackef5b63d2018-06-15 07:19:11 -0700273 Builder builder;
274 try (SilentCloseable c = Profiler.instance().profile("createBuilder")) {
buchgr7b515522019-03-29 04:42:17 -0700275 builder = createBuilder(request, actionCache, skyframeExecutor, modifiedOutputFiles);
ulfjackef5b63d2018-06-15 07:19:11 -0700276 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100277
278 //
279 // Execution proper. All statements below are logically nested in
280 // begin/end pairs. No early returns or exceptions please!
281 //
282
283 Collection<ConfiguredTarget> configuredTargets = buildResult.getActualTargets();
ulfjackef5b63d2018-06-15 07:19:11 -0700284 try (SilentCloseable c = Profiler.instance().profile("ExecutionStartingEvent")) {
285 env.getEventBus().post(new ExecutionStartingEvent(configuredTargets));
286 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100287
288 getReporter().handle(Event.progress("Building..."));
289
290 // Conditionally record dependency-checker log:
291 ExplanationHandler explanationHandler =
buchgr7b515522019-03-29 04:42:17 -0700292 installExplanationHandler(
293 request.getBuildOptions().explanationPath, request.getOptionsDescription());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100294
cpeyser8e9b28f2018-06-04 08:05:13 -0700295 Set<ConfiguredTargetKey> builtTargets = new HashSet<>();
tomlu6ed4fd52018-04-03 10:01:10 -0700296 Set<AspectKey> builtAspects = new HashSet<>();
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000297 Collection<AspectValue> aspects = analysisResult.getAspects();
298
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000299 if (request.isRunningInEmacs()) {
300 // The syntax of this message is tightly constrained by lisp/progmodes/compile.el in emacs
Klaus Aehligad87c132017-08-14 12:20:39 +0200301 request
302 .getOutErr()
brandjon79712cb2019-12-04 10:01:17 -0800303 .printErrLn(runtime.getProductName() + ": Entering directory `" + getExecRoot() + "/'");
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000304 }
mschaller40379082019-02-01 14:14:47 -0800305
306 Throwable catastrophe = null;
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000307 boolean buildCompleted = false;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100308 try {
Googler594c32d2019-07-17 17:55:18 -0700309 if (request.getViewOptions().discardAnalysisCache
310 || !skyframeExecutor.tracksStateForIncrementality()) {
311 // Free memory by removing cache entries that aren't going to be needed.
312 try (SilentCloseable c = Profiler.instance().profile("clearAnalysisCache")) {
313 env.getSkyframeBuildView()
314 .clearAnalysisCache(analysisResult.getTargetsToBuild(), analysisResult.getAspects());
315 }
316 }
317
schmittbe241a12020-01-16 13:30:55 -0800318 for (ExecutorLifecycleListener executorLifecycleListener : executorLifecycleListeners) {
ulfjackef5b63d2018-06-15 07:19:11 -0700319 try (SilentCloseable c =
schmittbe241a12020-01-16 13:30:55 -0800320 Profiler.instance().profile(executorLifecycleListener + ".executionPhaseStarting")) {
321 executorLifecycleListener.executionPhaseStarting(
janakrccb74562018-07-30 10:56:57 -0700322 actionGraph,
Googler184b4542019-07-19 19:34:19 -0700323 // If this supplier is ever consumed by more than one ActionContextProvider, it can be
324 // pulled out of the loop and made a memoizing supplier.
325 () ->
326 TopLevelArtifactHelper.makeTopLevelArtifactsToOwnerLabels(
327 analysisResult, aspects));
ulfjackef5b63d2018-06-15 07:19:11 -0700328 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100329 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100330 skyframeExecutor.drainChangedFiles();
331
ulfjackef5b63d2018-06-15 07:19:11 -0700332 try (SilentCloseable c = Profiler.instance().profile("configureResourceManager")) {
ulfjack985a34ad2019-08-09 01:51:15 -0700333 configureResourceManager(env.getLocalResourceManager(), request);
ulfjackef5b63d2018-06-15 07:19:11 -0700334 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100335
336 Profiler.instance().markPhase(ProfilePhase.EXECUTE);
Dmitry Lomove2033b12015-08-19 16:57:49 +0000337 builder.buildArtifacts(
Ulf Adams5b9009b2015-09-24 09:52:53 +0000338 env.getReporter(),
janakrccb74562018-07-30 10:56:57 -0700339 analysisResult.getTopLevelArtifactsToOwnerLabels().getArtifacts(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100340 analysisResult.getParallelTests(),
341 analysisResult.getExclusiveTests(),
342 analysisResult.getTargetsToBuild(),
gregce45ae0962017-07-22 00:11:13 +0200343 analysisResult.getTargetsToSkip(),
Dmitry Lomove2033b12015-08-19 16:57:49 +0000344 analysisResult.getAspects(),
345 executor,
346 builtTargets,
tomlu6ed4fd52018-04-03 10:01:10 -0700347 builtAspects,
tomlu2661be82018-08-30 08:30:01 -0700348 request,
Googlerbfd4e242016-07-15 22:23:37 +0000349 env.getBlazeWorkspace().getLastExecutionTimeRange(),
350 topLevelArtifactContext);
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000351 buildCompleted = true;
352 } catch (BuildFailedException | TestExecException e) {
353 buildCompleted = true;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100354 throw e;
mschaller40379082019-02-01 14:14:47 -0800355 } catch (Error | RuntimeException e) {
356 catastrophe = e;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100357 } finally {
mschaller40379082019-02-01 14:14:47 -0800358 // These may flush logs, which may help if there is a catastrophic failure.
schmittbe241a12020-01-16 13:30:55 -0800359 for (ExecutorLifecycleListener executorLifecycleListener : executorLifecycleListeners) {
360 executorLifecycleListener.executionPhaseEnding();
mschaller40379082019-02-01 14:14:47 -0800361 }
362
363 // Handlers process these events and others (e.g. CommandCompleteEvent), even in the event of
364 // a catastrophic failure. Posting these is consistent with other behavior.
janakrac58ca82019-02-14 09:34:20 -0800365 env.getEventBus().post(skyframeExecutor.createExecutionFinishedEvent());
mschaller40379082019-02-01 14:14:47 -0800366
367 env.getEventBus()
368 .post(new ExecutionPhaseCompleteEvent(timer.stop().elapsed(TimeUnit.MILLISECONDS)));
369
370 if (catastrophe != null) {
371 Throwables.throwIfUnchecked(catastrophe);
372 }
373 // NOTE: No finalization activities below will run in the event of a catastrophic error!
374
Ulf Adamsb5146102015-10-20 08:57:26 +0000375 env.recordLastExecutionTime();
mschaller40379082019-02-01 14:14:47 -0800376
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100377 if (request.isRunningInEmacs()) {
Klaus Aehligad87c132017-08-14 12:20:39 +0200378 request
379 .getOutErr()
brandjon79712cb2019-12-04 10:01:17 -0800380 .printErrLn(runtime.getProductName() + ": Leaving directory `" + getExecRoot() + "/'");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100381 }
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000382 if (buildCompleted) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100383 getReporter().handle(Event.progress("Building complete."));
384 }
385
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000386 if (buildCompleted) {
jmmv59787f12017-08-28 21:41:21 +0200387 saveActionCache(actionCache);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100388 }
389
ulfjack1fbe72e2018-06-14 04:46:27 -0700390 try (SilentCloseable c = Profiler.instance().profile("Show results")) {
Ulf Adams7a3fe522015-12-04 10:48:56 +0000391 buildResult.setSuccessfulTargets(
tomlu6ed4fd52018-04-03 10:01:10 -0700392 determineSuccessfulTargets(configuredTargets, builtTargets));
393 buildResult.setSuccessfulAspects(determineSuccessfulAspects(aspects, builtAspects));
gregce45ae0962017-07-22 00:11:13 +0200394 buildResult.setSkippedTargets(analysisResult.getTargetsToSkip());
Googler3ca7b782015-10-12 15:44:09 +0000395 BuildResultPrinter buildResultPrinter = new BuildResultPrinter(env);
mschaller40379082019-02-01 14:14:47 -0800396 buildResultPrinter.showBuildResult(
397 request,
398 buildResult,
399 configuredTargets,
400 analysisResult.getTargetsToSkip(),
401 analysisResult.getAspects());
Nathan Harmatad4803012015-09-08 20:03:22 +0000402 }
Googler3ca7b782015-10-12 15:44:09 +0000403
ulfjack1fbe72e2018-06-14 04:46:27 -0700404 try (SilentCloseable c = Profiler.instance().profile("Show artifacts")) {
Googler3ca7b782015-10-12 15:44:09 +0000405 if (request.getBuildOptions().showArtifacts) {
406 BuildResultPrinter buildResultPrinter = new BuildResultPrinter(env);
buchgr7b515522019-03-29 04:42:17 -0700407 buildResultPrinter.showArtifacts(request, configuredTargets, analysisResult.getAspects());
Googler3ca7b782015-10-12 15:44:09 +0000408 }
409 }
410
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100411 if (explanationHandler != null) {
412 uninstallExplanationHandler(explanationHandler);
laszlocsomor482235b2018-11-22 08:15:15 -0800413 try {
414 explanationHandler.close();
415 } catch (IOException _ignored) {
416 // Ignored
417 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100418 }
419 // Finalize output service last, so that if we do throw an exception, we know all the other
420 // code has already run.
Ulf Adams706b7f22015-10-20 09:06:45 +0000421 if (env.getOutputService() != null) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100422 boolean isBuildSuccessful =
423 buildResult.getSuccessfulTargets().size() == configuredTargets.size();
Ulf Adams706b7f22015-10-20 09:06:45 +0000424 env.getOutputService().finalizeBuild(isBuildSuccessful);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100425 }
426 }
427 }
428
ichern121933e2020-01-27 02:08:19 -0800429 private void prepare(
430 PackageRoots packageRoots, ImmutableSortedSet<String> nonSymlinkedDirectoriesUnderExecRoot)
431 throws AbruptExitException, InterruptedException {
tomluee6a6862018-01-17 14:36:26 -0800432 Optional<ImmutableMap<PackageIdentifier, Root>> packageRootMap =
janakrae323982017-09-29 21:11:53 +0200433 packageRoots.getPackageRootsMap();
arostovtsev20b056a2019-08-30 15:00:31 -0700434 if (packageRootMap.isPresent()) {
435 // Prepare for build.
436 Profiler.instance().markPhase(ProfilePhase.PREPARE);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100437
arostovtsev20b056a2019-08-30 15:00:31 -0700438 // Plant the symlink forest.
439 try (SilentCloseable c = Profiler.instance().profile("plantSymlinkForest")) {
ichern121933e2020-01-27 02:08:19 -0800440 SymlinkForest symlinkForest =
441 new SymlinkForest(
442 packageRootMap.get(),
443 getExecRoot(),
444 runtime.getProductName(),
445 nonSymlinkedDirectoriesUnderExecRoot);
446 symlinkForest.plantSymlinkForest();
arostovtsev20b056a2019-08-30 15:00:31 -0700447 } catch (IOException e) {
448 throw new ExecutorInitException("Source forest creation failed", e);
449 }
Kristina Chodorow52bc57c2016-06-20 14:27:56 +0000450 }
arostovtsev20b056a2019-08-30 15:00:31 -0700451 env.getEventBus().post(new ExecRootPreparedEvent(packageRootMap));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100452 }
453
Nathan Harmataca06fa22015-07-27 19:54:14 +0000454 private void createActionLogDirectory() throws ExecutorInitException {
jmmv88e22cd2019-09-15 09:59:49 -0700455 Path directory = env.getActionTempsDirectory();
arostovtsev702a1c62020-01-15 11:59:50 -0800456 if (directory.exists()) {
457 try {
jmmv5cc1f652019-03-20 09:34:08 -0700458 directory.deleteTree();
arostovtsev702a1c62020-01-15 11:59:50 -0800459 } catch (IOException e) {
460 throw new ExecutorInitException("Couldn't delete action output directory", e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100461 }
arostovtsev702a1c62020-01-15 11:59:50 -0800462 }
463
464 try {
janakr0049e962017-04-05 21:41:23 +0000465 FileSystemUtils.createDirectoryAndParents(directory);
Nathan Harmataca06fa22015-07-27 19:54:14 +0000466 } catch (IOException e) {
arostovtsev702a1c62020-01-15 11:59:50 -0800467 throw new ExecutorInitException("Couldn't create action output directory", e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100468 }
469 }
470
brandjon07cc56d2019-11-25 10:00:12 -0800471 /**
brandjon7b5043f2019-11-25 12:30:22 -0800472 * Obtains the {@link BuildConfiguration} for a given {@link BuildOptions} for the purpose of
473 * symlink creation.
474 *
475 * <p>In the event of a {@link InvalidConfigurationException}, a warning is emitted and null is
476 * returned.
477 */
478 @Nullable
479 private static BuildConfiguration getConfiguration(
480 SkyframeExecutor executor, Reporter reporter, BuildOptions options) {
481 try {
482 return executor.getConfiguration(reporter, options, /*keepGoing=*/ false);
483 } catch (InvalidConfigurationException e) {
484 reporter.handle(
485 Event.warn(
486 "Couldn't get configuration for convenience symlink creation: " + e.getMessage()));
487 return null;
488 }
489 }
490
491 /**
Googler87636392019-12-30 12:57:56 -0800492 * Handles what action to perform on the convenience symlinks. If the the mode is {@link
493 * ConvenienceSymlinksMode.IGNORE}, then skip any creating or cleaning of convenience symlinks.
494 * Otherwise, manage the convenience symlinks and then post a {@link
495 * ConvenienceSymlinksIdentifiedEvent} build event.
496 */
497 private void handleConvenienceSymlinks(AnalysisResult analysisResult) {
498 ImmutableList<ConvenienceSymlink> convenienceSymlinks = ImmutableList.of();
499 if (request.getBuildOptions().experimentalConvenienceSymlinks
500 != ConvenienceSymlinksMode.IGNORE) {
501 convenienceSymlinks = createConvenienceSymlinks(request.getBuildOptions(), analysisResult);
502 }
503 if (request.getBuildOptions().experimentalConvenienceSymlinksBepEvent) {
504 env.getEventBus().post(new ConvenienceSymlinksIdentifiedEvent(convenienceSymlinks));
505 }
506 }
507
508 /**
brandjon07cc56d2019-11-25 10:00:12 -0800509 * Creates convenience symlinks based on the target configurations.
510 *
511 * <p>Exactly what target configurations we consider depends on the value of {@code
512 * --use_top_level_targets_for_symlinks}. If this flag is false, we use the top-level target
513 * configuration as represented by the command line prior to processing any target. If the flag is
514 * true, we instead use the configurations OF the top-level targets -- meaning that we account for
515 * the effects of any rule transitions these targets may have.
516 *
517 * <p>For each type of convenience symlink, if all the considered configurations agree on what
518 * path the symlink should point to, it gets created; otherwise, the symlink is not created, and
519 * in fact gets removed if it was already present from a previous invocation.
520 */
Googler87636392019-12-30 12:57:56 -0800521 private ImmutableList<ConvenienceSymlink> createConvenienceSymlinks(
brandjon07cc56d2019-11-25 10:00:12 -0800522 BuildRequestOptions buildRequestOptions, AnalysisResult analysisResult) {
523 SkyframeExecutor executor = env.getSkyframeExecutor();
524 Reporter reporter = env.getReporter();
525
526 // Gather configurations to consider.
527 Set<BuildConfiguration> targetConfigurations =
528 buildRequestOptions.useTopLevelTargetsForSymlinks()
529 ? analysisResult.getTargetsToBuild().stream()
530 .map(ConfiguredTarget::getConfigurationKey)
531 .filter(configuration -> configuration != null)
532 .distinct()
533 .map((key) -> executor.getConfiguration(reporter, key))
534 .collect(toImmutableSet())
535 : ImmutableSet.copyOf(
536 analysisResult.getConfigurationCollection().getTargetConfigurations());
537
538 String productName = runtime.getProductName();
brandjon07cc56d2019-11-25 10:00:12 -0800539 try (SilentCloseable c =
540 Profiler.instance().profile("OutputDirectoryLinksUtils.createOutputDirectoryLinks")) {
Googler87636392019-12-30 12:57:56 -0800541 return OutputDirectoryLinksUtils.createOutputDirectoryLinks(
brandjon8a603602019-12-04 10:40:38 -0800542 runtime.getRuleClassProvider().getSymlinkDefinitions(),
brandjon282958b2019-12-04 08:14:26 -0800543 buildRequestOptions,
Googler87636392019-12-30 12:57:56 -0800544 env.getWorkspaceName(),
brandjon07cc56d2019-11-25 10:00:12 -0800545 env.getWorkspace(),
Googler87636392019-12-30 12:57:56 -0800546 env.getDirectories(),
brandjon07cc56d2019-11-25 10:00:12 -0800547 getReporter(),
548 targetConfigurations,
brandjon7b5043f2019-11-25 12:30:22 -0800549 options -> getConfiguration(executor, reporter, options),
brandjon282958b2019-12-04 08:14:26 -0800550 productName);
brandjon07cc56d2019-11-25 10:00:12 -0800551 }
552 }
553
buchgr7b515522019-03-29 04:42:17 -0700554 /** Prepare for a local output build. */
kchodorow85ae1902017-04-22 15:07:22 -0400555 private void startLocalOutputBuild() throws ExecutorInitException {
ulfjack1fbe72e2018-06-14 04:46:27 -0700556 try (SilentCloseable c = Profiler.instance().profile("Starting local output build")) {
kchodorow85ae1902017-04-22 15:07:22 -0400557 Path outputPath = env.getDirectories().getOutputPath(env.getWorkspaceName());
Ulf Adams94b72db2016-03-30 11:58:37 +0000558 Path localOutputPath = env.getDirectories().getLocalOutputPath();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100559
560 if (outputPath.isSymbolicLink()) {
Nathan Harmataca06fa22015-07-27 19:54:14 +0000561 try {
562 // Remove the existing symlink first.
563 outputPath.delete();
564 if (localOutputPath.exists()) {
565 // Pre-existing local output directory. Move to outputPath.
566 localOutputPath.renameTo(outputPath);
567 }
568 } catch (IOException e) {
569 throw new ExecutorInitException("Couldn't handle local output directory symlinks", e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100570 }
571 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100572 }
573 }
574
575 /**
buchgr7b515522019-03-29 04:42:17 -0700576 * If a path is supplied, creates and installs an ExplanationHandler. Returns an instance on
577 * success. Reports an error and returns null otherwise.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100578 */
buchgr7b515522019-03-29 04:42:17 -0700579 private ExplanationHandler installExplanationHandler(
580 PathFragment explanationPath, String allOptions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100581 if (explanationPath == null) {
582 return null;
583 }
584 ExplanationHandler handler;
585 try {
buchgr7b515522019-03-29 04:42:17 -0700586 handler =
587 new ExplanationHandler(
588 getWorkspace().getRelative(explanationPath).getOutputStream(), allOptions);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100589 } catch (IOException e) {
buchgr7b515522019-03-29 04:42:17 -0700590 getReporter()
591 .handle(
592 Event.warn(
593 String.format(
594 "Cannot write explanation of rebuilds to file '%s': %s",
595 explanationPath, e.getMessage())));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100596 return null;
597 }
buchgr7b515522019-03-29 04:42:17 -0700598 getReporter()
599 .handle(Event.info("Writing explanation of rebuilds to '" + explanationPath + "'"));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100600 getReporter().addHandler(handler);
601 return handler;
602 }
603
buchgr7b515522019-03-29 04:42:17 -0700604 /** Uninstalls the specified ExplanationHandler (if any) and closes the log file. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100605 private void uninstallExplanationHandler(ExplanationHandler handler) {
606 if (handler != null) {
607 getReporter().removeHandler(handler);
608 handler.log.close();
609 }
610 }
611
612 /**
laszlocsomor482235b2018-11-22 08:15:15 -0800613 * An ErrorEventListener implementation that records DEPCHECKER events into a log file, iff the
614 * --explain flag is specified during a build.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100615 */
laszlocsomor482235b2018-11-22 08:15:15 -0800616 private static class ExplanationHandler implements EventHandler, AutoCloseable {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100617 private final PrintWriter log;
618
619 private ExplanationHandler(OutputStream log, String optionsDescription) {
lberki0d8d4cf2017-09-05 16:01:44 +0200620 this.log = new PrintWriter(new OutputStreamWriter(log, StandardCharsets.UTF_8));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100621 this.log.println("Build options: " + optionsDescription);
622 }
623
laszlocsomor482235b2018-11-22 08:15:15 -0800624 @Override
625 public void close() throws IOException {
626 this.log.close();
627 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100628
629 @Override
630 public void handle(Event event) {
631 if (event.getKind() == EventKind.DEPCHECKER) {
632 log.println(event.getMessage());
633 }
634 }
635 }
636
637 /**
tomlu6ed4fd52018-04-03 10:01:10 -0700638 * Computes the result of the build. Sets the list of successful (up-to-date) targets in the
639 * request object.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100640 *
tomlu6ed4fd52018-04-03 10:01:10 -0700641 * @param configuredTargets The configured targets whose artifacts are to be built.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100642 */
Ulf Adams7a3fe522015-12-04 10:48:56 +0000643 private Collection<ConfiguredTarget> determineSuccessfulTargets(
cpeyser8e9b28f2018-06-04 08:05:13 -0700644 Collection<ConfiguredTarget> configuredTargets, Set<ConfiguredTargetKey> builtTargets) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100645 // Maintain the ordering by copying builtTargets into a LinkedHashSet in the same iteration
646 // order as configuredTargets.
647 Collection<ConfiguredTarget> successfulTargets = new LinkedHashSet<>();
648 for (ConfiguredTarget target : configuredTargets) {
cpeyser8e9b28f2018-06-04 08:05:13 -0700649 if (builtTargets.contains(ConfiguredTargetKey.inTargetConfig(target))) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100650 successfulTargets.add(target);
651 }
652 }
Ulf Adams7a3fe522015-12-04 10:48:56 +0000653 return successfulTargets;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100654 }
655
tomlu6ed4fd52018-04-03 10:01:10 -0700656 private Collection<AspectValue> determineSuccessfulAspects(
657 Collection<AspectValue> aspects, Set<AspectKey> builtAspects) {
658 // Maintain the ordering by copying builtTargets into a LinkedHashSet in the same iteration
659 // order as configuredTargets.
660 Collection<AspectValue> successfulAspects = new LinkedHashSet<>();
661 for (AspectValue aspect : aspects) {
662 if (builtAspects.contains(aspect.getKey())) {
663 successfulAspects.add(aspect);
664 }
665 }
666 return successfulAspects;
667 }
668
ccalvarinb5fd7612017-12-14 12:21:48 -0800669 /** Get action cache if present or reload it from the on-disk cache. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100670 private ActionCache getActionCache() throws LocalEnvironmentException {
671 try {
Ulf Adams80613022015-09-16 09:11:33 +0000672 return env.getPersistentActionCache();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100673 } catch (IOException e) {
674 // TODO(bazel-team): (2010) Ideally we should just remove all cache data and reinitialize
675 // caches.
buchgr7b515522019-03-29 04:42:17 -0700676 LoggingUtil.logToRemote(
677 Level.WARNING, "Failed to initialize action cache: " + e.getMessage(), e);
Dan Fabulich1d35ca02018-07-05 16:08:06 -0700678 throw new LocalEnvironmentException(
679 "couldn't create action cache: "
680 + e.getMessage()
681 + ". If error persists, use 'bazel clean'");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100682 }
683 }
684
buchgr7b515522019-03-29 04:42:17 -0700685 private Builder createBuilder(
686 BuildRequest request,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100687 ActionCache actionCache,
Eric Fellheimerf3b43af2015-11-13 19:51:20 +0000688 SkyframeExecutor skyframeExecutor,
Ulf Adams1ac1b992016-11-02 12:50:26 +0000689 ModifiedFileSet modifiedOutputFiles) {
janakr6b1b8a92017-11-10 23:20:22 +0100690 BuildRequestOptions options = request.getBuildOptions();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100691
jmmv88e22cd2019-09-15 09:59:49 -0700692 Path actionOutputRoot = env.getActionTempsDirectory();
buchgr7b515522019-03-29 04:42:17 -0700693 Predicate<Action> executionFilter =
694 CheckUpToDateFilter.fromOptions(request.getOptions(ExecutionOptions.class));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100695
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100696 skyframeExecutor.setActionOutputRoot(actionOutputRoot);
Ulf Adams3d67e002016-03-29 16:23:01 +0000697 ArtifactFactory artifactFactory = env.getSkyframeBuildView().getArtifactFactory();
Googler2f111922017-02-28 20:58:45 +0000698 return new SkyframeBuilder(
699 skyframeExecutor,
ulfjack985a34ad2019-08-09 01:51:15 -0700700 env.getLocalResourceManager(),
Googler2f111922017-02-28 20:58:45 +0000701 new ActionCacheChecker(
702 actionCache,
703 artifactFactory,
tomlu3d1a1942017-11-29 14:01:21 -0800704 skyframeExecutor.getActionKeyContext(),
Googler2f111922017-02-28 20:58:45 +0000705 executionFilter,
706 ActionCacheChecker.CacheConfig.builder()
707 .setEnabled(options.useActionCache)
708 .setVerboseExplanations(options.verboseExplanations)
709 .build()),
fellyc5c078c2019-07-31 12:05:24 -0700710 env.getTopDownActionCache(),
Nathan Harmata60108832016-03-25 08:02:42 +0000711 request.getPackageCacheOptions().checkOutputFiles
Googler2f111922017-02-28 20:58:45 +0000712 ? modifiedOutputFiles
713 : ModifiedFileSet.NOTHING_MODIFIED,
schmitte6433402020-01-07 12:57:46 -0800714 env.getFileCache(),
tomlu2661be82018-08-30 08:30:01 -0700715 prefetcher);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100716 }
717
steinman13a628a2019-01-09 08:39:32 -0800718 @VisibleForTesting
ulfjack985a34ad2019-08-09 01:51:15 -0700719 public static void configureResourceManager(ResourceManager resourceMgr, BuildRequest request) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100720 ExecutionOptions options = request.getOptions(ExecutionOptions.class);
Mark Schallerdffb6ee2015-02-25 20:01:01 +0000721 ResourceSet resources;
steinman3501b212019-03-25 12:36:43 -0700722 if (options.availableResources != null && !options.removeLocalResources) {
steinman13a628a2019-01-09 08:39:32 -0800723 logger.warning(
724 "--local_resources will be deprecated. Please use --local_ram_resources "
725 + "and/or --local_cpu_resources.");
Mark Schallerdffb6ee2015-02-25 20:01:01 +0000726 resources = options.availableResources;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100727 resourceMgr.setRamUtilizationPercentage(100);
steinman13a628a2019-01-09 08:39:32 -0800728 } else if (options.ramUtilizationPercentage != 0) {
729 logger.warning(
730 "--ram_utilization_factor will soon be deprecated. Please use "
731 + "--local_ram_resources=HOST_RAM*<float>, where <float> is the percentage of "
732 + "available RAM you want to devote to Bazel.");
733 resources =
734 ResourceSet.createWithRamCpu(
735 LocalHostCapacity.getLocalHostCapacity().getMemoryMb(), options.localCpuResources);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100736 resourceMgr.setRamUtilizationPercentage(options.ramUtilizationPercentage);
steinman13a628a2019-01-09 08:39:32 -0800737 } else {
738 resources =
739 ResourceSet.createWithRamCpu(options.localRamResources, options.localCpuResources);
740 resourceMgr.setRamUtilizationPercentage(100);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100741 }
Josh Pieper7f3bddd2018-05-04 00:39:37 -0700742 resourceMgr.setUseLocalMemoryEstimate(options.localMemoryEstimate);
Mark Schallerdffb6ee2015-02-25 20:01:01 +0000743
buchgr7b515522019-03-29 04:42:17 -0700744 resourceMgr.setAvailableResources(
745 ResourceSet.create(
746 resources.getMemoryMb(),
747 resources.getCpuUsage(),
748 request.getExecutionOptions().usingLocalTestJobs()
749 ? request.getExecutionOptions().localTestJobs
750 : Integer.MAX_VALUE));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100751 }
752
753 /**
jmmv59787f12017-08-28 21:41:21 +0200754 * Writes the action cache files to disk, reporting any errors that occurred during writing and
755 * capturing statistics.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100756 */
jmmv59787f12017-08-28 21:41:21 +0200757 private void saveActionCache(ActionCache actionCache) {
jmmvccb43ee2017-08-30 22:07:10 +0200758 ActionCacheStatistics.Builder builder = ActionCacheStatistics.newBuilder();
jmmv9573a0d2017-09-26 11:59:22 -0400759 actionCache.mergeIntoActionCacheStatistics(builder);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100760
lberki97abb522017-09-04 18:51:57 +0200761 AutoProfiler p =
762 AutoProfiler.profiledAndLogged("Saving action cache", ProfilerTask.INFO, logger);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100763 try {
jmmv59787f12017-08-28 21:41:21 +0200764 builder.setSizeInBytes(actionCache.save());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100765 } catch (IOException e) {
jmmv59787f12017-08-28 21:41:21 +0200766 builder.setSizeInBytes(0);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100767 getReporter().handle(Event.error("I/O error while writing action log: " + e.getMessage()));
768 } finally {
jmmvccb43ee2017-08-30 22:07:10 +0200769 builder.setSaveTimeInMs(
770 TimeUnit.MILLISECONDS.convert(p.completeAndGetElapsedTimeNanos(), TimeUnit.NANOSECONDS));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100771 }
jmmv59787f12017-08-28 21:41:21 +0200772
773 env.getEventBus().post(builder.build());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100774 }
775
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100776 private Reporter getReporter() {
Ulf Adams633f5392015-09-15 11:13:08 +0000777 return env.getReporter();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100778 }
779
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100780 private Path getWorkspace() {
Ulf Adams94b72db2016-03-30 11:58:37 +0000781 return env.getWorkspace();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100782 }
783
784 private Path getExecRoot() {
Ulf Adams94b72db2016-03-30 11:58:37 +0000785 return env.getExecRoot();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100786 }
787}