blob: 128596140fabcbfc529dda7632c745a27585e854 [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 +000017import static java.util.concurrent.TimeUnit.MILLISECONDS;
Eric Fellheimere9b41c62016-06-14 15:39:51 +000018
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010019import com.google.common.base.Joiner;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010020import com.google.common.base.Predicate;
21import com.google.common.base.Stopwatch;
Chloe Calvarin5dc44f02017-03-21 14:40:28 +000022import com.google.common.base.Strings;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010023import com.google.common.collect.HashBasedTable;
Philipp Wollermann45bf15b2015-06-18 13:06:16 +000024import com.google.common.collect.ImmutableList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010025import com.google.common.collect.ImmutableMap;
Philipp Wollermann1ecdc512016-02-26 21:55:31 +000026import com.google.common.collect.ImmutableMultimap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010027import com.google.common.collect.ImmutableSet;
28import com.google.common.collect.Iterables;
Philipp Wollermann1ecdc512016-02-26 21:55:31 +000029import com.google.common.collect.Multimap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010030import com.google.common.collect.Ordering;
31import com.google.common.collect.Table;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010032import com.google.devtools.build.lib.actions.Action;
33import com.google.devtools.build.lib.actions.ActionCacheChecker;
ulfjack734b9e92017-06-19 16:22:17 +020034import com.google.devtools.build.lib.actions.ActionContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010035import com.google.devtools.build.lib.actions.ActionContextMarker;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010036import com.google.devtools.build.lib.actions.ActionGraph;
37import com.google.devtools.build.lib.actions.ActionInputFileCache;
ulfjack5b99e502017-07-20 22:22:36 +020038import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010039import com.google.devtools.build.lib.actions.Artifact;
Ulf Adams3d67e002016-03-29 16:23:01 +000040import com.google.devtools.build.lib.actions.ArtifactFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010041import com.google.devtools.build.lib.actions.BuildFailedException;
42import com.google.devtools.build.lib.actions.ExecException;
43import com.google.devtools.build.lib.actions.ExecutionStrategy;
44import com.google.devtools.build.lib.actions.Executor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010045import com.google.devtools.build.lib.actions.ExecutorInitException;
46import com.google.devtools.build.lib.actions.LocalHostCapacity;
47import com.google.devtools.build.lib.actions.ResourceManager;
Mark Schallerdffb6ee2015-02-25 20:01:01 +000048import com.google.devtools.build.lib.actions.ResourceSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010049import com.google.devtools.build.lib.actions.SpawnActionContext;
50import com.google.devtools.build.lib.actions.TestExecException;
51import com.google.devtools.build.lib.actions.cache.ActionCache;
jmmvccb43ee2017-08-30 22:07:10 +020052import com.google.devtools.build.lib.actions.cache.Protos.ActionCacheStatistics;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010053import com.google.devtools.build.lib.analysis.BuildView.AnalysisResult;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010054import com.google.devtools.build.lib.analysis.ConfiguredTarget;
Googlerbfd4e242016-07-15 22:23:37 +000055import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010056import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010057import com.google.devtools.build.lib.analysis.WorkspaceStatusAction;
Lukacs Berki7b2f2e82016-11-23 14:16:43 +000058import com.google.devtools.build.lib.analysis.actions.SymlinkTreeActionContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010059import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
60import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
ulfjackab21d182017-08-10 15:36:14 +020061import com.google.devtools.build.lib.analysis.test.TestActionContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010062import com.google.devtools.build.lib.buildtool.buildevent.ExecutionPhaseCompleteEvent;
63import com.google.devtools.build.lib.buildtool.buildevent.ExecutionStartingEvent;
Kristina Chodorow33aada22016-06-22 14:23:47 +000064import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010065import com.google.devtools.build.lib.events.Event;
66import com.google.devtools.build.lib.events.EventHandler;
67import com.google.devtools.build.lib.events.EventKind;
68import com.google.devtools.build.lib.events.Reporter;
Ulf Adamsdba3c832016-12-21 16:50:02 +000069import com.google.devtools.build.lib.exec.ActionContextConsumer;
70import com.google.devtools.build.lib.exec.ActionContextProvider;
71import com.google.devtools.build.lib.exec.BlazeExecutor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010072import com.google.devtools.build.lib.exec.CheckUpToDateFilter;
73import com.google.devtools.build.lib.exec.ExecutionOptions;
Ulf Adamsdba3c832016-12-21 16:50:02 +000074import com.google.devtools.build.lib.exec.ExecutorBuilder;
75import com.google.devtools.build.lib.exec.FilesetActionContextImpl;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010076import com.google.devtools.build.lib.exec.SingleBuildFileCache;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010077import com.google.devtools.build.lib.exec.SymlinkTreeStrategy;
Nathan Harmatad4803012015-09-08 20:03:22 +000078import com.google.devtools.build.lib.profiler.AutoProfiler;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079import com.google.devtools.build.lib.profiler.ProfilePhase;
80import com.google.devtools.build.lib.profiler.Profiler;
81import com.google.devtools.build.lib.profiler.ProfilerTask;
82import com.google.devtools.build.lib.rules.fileset.FilesetActionContext;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010083import com.google.devtools.build.lib.runtime.BlazeModule;
84import com.google.devtools.build.lib.runtime.BlazeRuntime;
Ulf Adams633f5392015-09-15 11:13:08 +000085import com.google.devtools.build.lib.runtime.CommandEnvironment;
Dmitry Lomove2033b12015-08-19 16:57:49 +000086import com.google.devtools.build.lib.skyframe.AspectValue;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010087import com.google.devtools.build.lib.skyframe.Builder;
ulfjackbc4eb272017-08-10 17:33:22 +020088import com.google.devtools.build.lib.skyframe.OutputService;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010089import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010090import com.google.devtools.build.lib.util.AbruptExitException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010091import com.google.devtools.build.lib.util.ExitCode;
92import com.google.devtools.build.lib.util.LoggingUtil;
Mark Schaller6df81792015-12-10 18:47:47 +000093import com.google.devtools.build.lib.util.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010094import com.google.devtools.build.lib.vfs.FileSystemUtils;
Eric Fellheimerf3b43af2015-11-13 19:51:20 +000095import com.google.devtools.build.lib.vfs.ModifiedFileSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010096import com.google.devtools.build.lib.vfs.Path;
97import com.google.devtools.build.lib.vfs.PathFragment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010098import java.io.IOException;
99import java.io.OutputStream;
lberki0d8d4cf2017-09-05 16:01:44 +0200100import java.io.OutputStreamWriter;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100101import java.io.PrintWriter;
lberki0d8d4cf2017-09-05 16:01:44 +0200102import java.nio.charset.StandardCharsets;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100103import java.util.ArrayList;
104import java.util.Collection;
105import java.util.HashMap;
106import java.util.HashSet;
107import java.util.LinkedHashSet;
108import java.util.List;
109import java.util.Map;
110import java.util.Set;
Philipp Wollermanna068dee2015-06-08 11:15:02 +0000111import java.util.TreeMap;
Eric Fellheimer2db6a742015-04-28 21:38:43 +0000112import java.util.UUID;
jmmvccb43ee2017-08-30 22:07:10 +0200113import java.util.concurrent.TimeUnit;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100114import java.util.logging.Level;
115import java.util.logging.Logger;
116
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100117/**
118 * This class manages the execution phase. The entry point is {@link #executeBuild}.
119 *
120 * <p>This is only intended for use by {@link BuildTool}.
121 *
mstaibd9b141d2017-09-14 20:47:31 +0200122 * <p>This class contains an ActionCache, and refers to the Blaze Runtime's BuildView and
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100123 * PackageCache.
124 *
125 * @see BuildTool
Kristina Chodorowe423fdb2016-09-15 14:08:08 +0000126 * @see com.google.devtools.build.lib.analysis.BuildView
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100127 */
128public class ExecutionTool {
129 private static class StrategyConverter {
130 private Table<Class<? extends ActionContext>, String, ActionContext> classMap =
131 HashBasedTable.create();
132 private Map<Class<? extends ActionContext>, ActionContext> defaultClassMap =
133 new HashMap<>();
134
135 /**
136 * Aggregates all {@link ActionContext}s that are in {@code contextProviders}.
137 */
138 @SuppressWarnings("unchecked")
139 private StrategyConverter(Iterable<ActionContextProvider> contextProviders) {
140 for (ActionContextProvider provider : contextProviders) {
141 for (ActionContext strategy : provider.getActionContexts()) {
142 ExecutionStrategy annotation =
143 strategy.getClass().getAnnotation(ExecutionStrategy.class);
ulfjack9274cba2017-08-11 23:19:48 +0200144 // TODO(ulfjack): Don't silently ignore action contexts without annotation.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100145 if (annotation != null) {
146 defaultClassMap.put(annotation.contextType(), strategy);
147
148 for (String name : annotation.name()) {
149 classMap.put(annotation.contextType(), name, strategy);
150 }
151 }
152 }
153 }
154 }
155
156 @SuppressWarnings("unchecked")
157 private <T extends ActionContext> T getStrategy(Class<T> clazz, String name) {
158 return (T) (name.isEmpty() ? defaultClassMap.get(clazz) : classMap.get(clazz, name));
159 }
160
161 private String getValidValues(Class<? extends ActionContext> context) {
162 return Joiner.on(", ").join(Ordering.natural().sortedCopy(classMap.row(context).keySet()));
163 }
164
165 private String getUserFriendlyName(Class<? extends ActionContext> context) {
166 ActionContextMarker marker = context.getAnnotation(ActionContextMarker.class);
167 return marker != null
168 ? marker.name()
169 : context.getSimpleName();
170 }
171 }
172
lberki97abb522017-09-04 18:51:57 +0200173 static final Logger logger = Logger.getLogger(ExecutionTool.class.getName());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100174
Ulf Adams633f5392015-09-15 11:13:08 +0000175 private final CommandEnvironment env;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100176 private final BlazeRuntime runtime;
177 private final BuildRequest request;
178 private BlazeExecutor executor;
Ulf Adams1ac1b992016-11-02 12:50:26 +0000179 private final ActionInputFileCache fileCache;
Ulf Adamsccd5c0a2017-01-13 15:46:51 +0000180 private final ActionInputPrefetcher prefetcher;
Philipp Wollermann45bf15b2015-06-18 13:06:16 +0000181 private final ImmutableList<ActionContextProvider> actionContextProviders;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100182
Philipp Wollermanna068dee2015-06-08 11:15:02 +0000183 private Map<String, SpawnActionContext> spawnStrategyMap =
184 new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100185 private List<ActionContext> strategies = new ArrayList<>();
186
Ulf Adams633f5392015-09-15 11:13:08 +0000187 ExecutionTool(CommandEnvironment env, BuildRequest request) throws ExecutorInitException {
188 this.env = env;
189 this.runtime = env.getRuntime();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100190 this.request = request;
191
Philipp Wollermann590ea392015-08-25 13:57:33 +0000192 // Create tools before getting the strategies from the modules as some of them need tools to
193 // determine whether the host actually supports certain strategies (e.g. sandboxing).
194 createToolsSymlinks();
195
Ulf Adamsa0e3af42016-10-31 16:52:48 +0000196 ExecutorBuilder builder = new ExecutorBuilder();
197 for (BlazeModule module : runtime.getBlazeModules()) {
198 module.executorInit(env, request, builder);
199 }
200 builder.addActionContextProvider(
201 new FilesetActionContextImpl.Provider(env.getReporter(), env.getWorkspaceName()));
202 builder.addActionContext(new SymlinkTreeStrategy(
203 env.getOutputService(), env.getBlazeWorkspace().getBinTools()));
204 // TODO(philwo) - the ExecutionTool should not add arbitrary dependencies on its own, instead
205 // these dependencies should be added to the ActionContextConsumer of the module that actually
206 // depends on them.
207 builder.addActionContextConsumer(
208 new ActionContextConsumer() {
209 @Override
210 public ImmutableMap<String, String> getSpawnActionContexts() {
211 return ImmutableMap.of();
212 }
213
214 @Override
215 public Multimap<Class<? extends ActionContext>, String> getActionContexts() {
216 return ImmutableMultimap.<Class<? extends ActionContext>, String>builder()
217 .put(FilesetActionContext.class, "")
218 .put(WorkspaceStatusAction.Context.class, "")
219 .put(SymlinkTreeActionContext.class, "")
220 .build();
221 }
222 });
223
Ulf Adams1ac1b992016-11-02 12:50:26 +0000224 ActionInputFileCache cache = builder.getActionInputFileCache();
225 if (cache == null) {
226 // Unfortunately, the exec root cache is not shared with caches in the remote execution
227 // client.
228 cache =
229 new SingleBuildFileCache(
230 env.getExecRoot().getPathString(), env.getDirectories().getFileSystem());
231 }
232 this.fileCache = cache;
Ulf Adamsccd5c0a2017-01-13 15:46:51 +0000233 this.prefetcher = builder.getActionInputPrefetcher();
Ulf Adams1ac1b992016-11-02 12:50:26 +0000234
Ulf Adamsa0e3af42016-10-31 16:52:48 +0000235 this.actionContextProviders = builder.getActionContextProviders();
Ulf Adamsccd5c0a2017-01-13 15:46:51 +0000236 for (ActionContextProvider provider : actionContextProviders) {
ulfjacka7f513c2017-08-10 12:49:16 +0200237 provider.init(fileCache);
Ulf Adamsccd5c0a2017-01-13 15:46:51 +0000238 }
239
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100240 StrategyConverter strategyConverter = new StrategyConverter(actionContextProviders);
Philipp Wollermann45bf15b2015-06-18 13:06:16 +0000241
Ulf Adamsa0e3af42016-10-31 16:52:48 +0000242 for (ActionContextConsumer consumer : builder.getActionContextConsumers()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100243 // There are many different SpawnActions, and we want to control the action context they use
244 // independently from each other, for example, to run genrules locally and Java compile action
245 // in prod. Thus, for SpawnActions, we decide the action context to use not only based on the
246 // context class, but also the mnemonic of the action.
247 for (Map.Entry<String, String> entry : consumer.getSpawnActionContexts().entrySet()) {
248 SpawnActionContext context =
249 strategyConverter.getStrategy(SpawnActionContext.class, entry.getValue());
250 if (context == null) {
Chloe Calvarin5dc44f02017-03-21 14:40:28 +0000251 String strategy = Strings.emptyToNull(entry.getKey());
Philipp Wollermann45bf15b2015-06-18 13:06:16 +0000252 throw makeExceptionForInvalidStrategyValue(
253 entry.getValue(),
Chloe Calvarin5dc44f02017-03-21 14:40:28 +0000254 Joiner.on(' ').skipNulls().join(strategy, "spawn"),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100255 strategyConverter.getValidValues(SpawnActionContext.class));
256 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100257 spawnStrategyMap.put(entry.getKey(), context);
258 }
259
260 for (Map.Entry<Class<? extends ActionContext>, String> entry :
Philipp Wollermann1ecdc512016-02-26 21:55:31 +0000261 consumer.getActionContexts().entries()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100262 ActionContext context = strategyConverter.getStrategy(entry.getKey(), entry.getValue());
Philipp Wollermann45bf15b2015-06-18 13:06:16 +0000263 if (context == null) {
264 throw makeExceptionForInvalidStrategyValue(
265 entry.getValue(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100266 strategyConverter.getUserFriendlyName(entry.getKey()),
267 strategyConverter.getValidValues(entry.getKey()));
268 }
Philipp Wollermann45bf15b2015-06-18 13:06:16 +0000269 strategies.add(context);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100270 }
271 }
272
Luis Fernando Pino Duque9b1fb682016-06-16 10:04:25 +0000273 String testStrategyValue = request.getOptions(ExecutionOptions.class).testStrategy;
274 ActionContext context = strategyConverter.getStrategy(TestActionContext.class,
275 testStrategyValue);
276 if (context == null) {
277 throw makeExceptionForInvalidStrategyValue(testStrategyValue, "test",
278 strategyConverter.getValidValues(TestActionContext.class));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100279 }
Luis Fernando Pino Duque9b1fb682016-06-16 10:04:25 +0000280 strategies.add(context);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100281 }
282
283 private static ExecutorInitException makeExceptionForInvalidStrategyValue(String value,
284 String strategy, String validValues) {
285 return new ExecutorInitException(String.format(
286 "'%s' is an invalid value for %s strategy. Valid values are: %s", value, strategy,
287 validValues), ExitCode.COMMAND_LINE_ERROR);
288 }
289
290 Executor getExecutor() throws ExecutorInitException {
291 if (executor == null) {
292 executor = createExecutor();
293 }
294 return executor;
295 }
296
297 /**
298 * Creates an executor for the current set of blaze runtime, execution options, and request.
299 */
300 private BlazeExecutor createExecutor()
301 throws ExecutorInitException {
302 return new BlazeExecutor(
Ulf Adams94b72db2016-03-30 11:58:37 +0000303 env.getExecRoot(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100304 getReporter(),
Ulf Adams633f5392015-09-15 11:13:08 +0000305 env.getEventBus(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100306 runtime.getClock(),
307 request,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100308 strategies,
309 spawnStrategyMap,
310 actionContextProviders);
311 }
312
313 void init() throws ExecutorInitException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100314 getExecutor();
315 }
316
317 void shutdown() {
318 for (ActionContextProvider actionContextProvider : actionContextProviders) {
319 actionContextProvider.executionPhaseEnding();
320 }
321 }
322
323 /**
324 * Performs the execution phase (phase 3) of the build, in which the Builder
325 * is applied to the action graph to bring the targets up to date. (This
326 * function will return prior to execution-proper if --nobuild was specified.)
Eric Fellheimer2db6a742015-04-28 21:38:43 +0000327 * @param buildId UUID of the build id
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100328 * @param analysisResult the analysis phase output
329 * @param buildResult the mutable build result
Lukacs Berki3ea4d442016-01-21 15:15:30 +0000330 * @param packageRoots package roots collected from loading phase and BuildConfigurationCollection
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100331 * creation
332 */
Eric Fellheimer2db6a742015-04-28 21:38:43 +0000333 void executeBuild(UUID buildId, AnalysisResult analysisResult,
Laurent Le Brunf3cf98f2016-06-17 13:36:24 +0000334 BuildResult buildResult,
335 BuildConfigurationCollection configurations,
Googlerbfd4e242016-07-15 22:23:37 +0000336 ImmutableMap<PackageIdentifier, Path> packageRoots,
337 TopLevelArtifactContext topLevelArtifactContext)
Nathan Harmataca06fa22015-07-27 19:54:14 +0000338 throws BuildFailedException, InterruptedException, TestExecException, AbruptExitException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100339 Stopwatch timer = Stopwatch.createStarted();
kchodorow85ae1902017-04-22 15:07:22 -0400340 prepare(packageRoots);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100341
342 ActionGraph actionGraph = analysisResult.getActionGraph();
343
344 // Get top-level artifacts.
345 ImmutableSet<Artifact> additionalArtifacts = analysisResult.getAdditionalArtifactsToBuild();
346
Ulf Adams706b7f22015-10-20 09:06:45 +0000347 OutputService outputService = env.getOutputService();
Eric Fellheimerf3b43af2015-11-13 19:51:20 +0000348 ModifiedFileSet modifiedOutputFiles = ModifiedFileSet.EVERYTHING_MODIFIED;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100349 if (outputService != null) {
ulfjack75483b52017-07-11 13:36:41 +0200350 modifiedOutputFiles =
351 outputService.startBuild(
352 env.getReporter(), buildId, request.getBuildOptions().finalizeActions);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100353 } else {
Kristina Chodorowe423fdb2016-09-15 14:08:08 +0000354 // TODO(bazel-team): this could be just another OutputService
kchodorow85ae1902017-04-22 15:07:22 -0400355 startLocalOutputBuild();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100356 }
357
janakr0049e962017-04-05 21:41:23 +0000358 // Must be created after the output path is created above.
359 createActionLogDirectory();
360
mstaibd9b141d2017-09-14 20:47:31 +0200361 // Create convenience symlinks from the configurations actually used by the requested targets.
362 // Symlinks will be created if all such configurations would point the symlink to the same path;
363 // if this does not hold, stale symlinks (if present from a previous invocation) will be
364 // deleted instead.
365 Set<BuildConfiguration> targetConfigurations =
366 request.getBuildOptions().useTopLevelTargetsForSymlinks()
367 ? analysisResult
368 .getTargetsToBuild()
369 .stream()
370 .map(ConfiguredTarget::getConfiguration)
371 .filter(configuration -> configuration != null)
372 .distinct()
373 .collect(toImmutableSet())
374 : ImmutableSet.copyOf(configurations.getTargetConfigurations());
375 String productName = runtime.getProductName();
376 String workspaceName = env.getWorkspaceName();
377 OutputDirectoryLinksUtils.createOutputDirectoryLinks(
378 workspaceName, env.getWorkspace(), env.getDirectories().getExecRoot(workspaceName),
379 env.getDirectories().getOutputPath(workspaceName), getReporter(), targetConfigurations,
380 request.getBuildOptions().getSymlinkPrefix(productName), productName);
Lukacs Berki85c63c42016-01-22 09:25:20 +0000381
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100382 ActionCache actionCache = getActionCache();
Ulf Adams80613022015-09-16 09:11:33 +0000383 SkyframeExecutor skyframeExecutor = env.getSkyframeExecutor();
Kristina Chodorowe423fdb2016-09-15 14:08:08 +0000384 Builder builder = createBuilder(
Ulf Adams1ac1b992016-11-02 12:50:26 +0000385 request, actionCache, skyframeExecutor, modifiedOutputFiles);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100386
387 //
388 // Execution proper. All statements below are logically nested in
389 // begin/end pairs. No early returns or exceptions please!
390 //
391
392 Collection<ConfiguredTarget> configuredTargets = buildResult.getActualTargets();
Ulf Adams633f5392015-09-15 11:13:08 +0000393 env.getEventBus().post(new ExecutionStartingEvent(configuredTargets));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100394
395 getReporter().handle(Event.progress("Building..."));
396
397 // Conditionally record dependency-checker log:
398 ExplanationHandler explanationHandler =
399 installExplanationHandler(request.getBuildOptions().explanationPath,
400 request.getOptionsDescription());
401
402 Set<ConfiguredTarget> builtTargets = new HashSet<>();
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000403 Collection<AspectValue> aspects = analysisResult.getAspects();
404
405 Iterable<Artifact> allArtifactsForProviders =
406 Iterables.concat(
407 additionalArtifacts,
408 TopLevelArtifactHelper.getAllArtifactsToBuild(
409 analysisResult.getTargetsToBuild(), analysisResult.getTopLevelContext())
410 .getAllArtifacts(),
411 TopLevelArtifactHelper.getAllArtifactsToBuildFromAspects(
412 aspects, analysisResult.getTopLevelContext())
413 .getAllArtifacts(),
414 //TODO(dslomov): Artifacts to test from aspects?
415 TopLevelArtifactHelper.getAllArtifactsToTest(analysisResult.getTargetsToTest()));
416
417 if (request.isRunningInEmacs()) {
418 // The syntax of this message is tightly constrained by lisp/progmodes/compile.el in emacs
Klaus Aehligad87c132017-08-14 12:20:39 +0200419 request
420 .getOutErr()
421 .printErrLn(
422 env.getRuntime().getProductName() + ": Entering directory `" + getExecRoot() + "/'");
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000423 }
424 boolean buildCompleted = false;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100425 try {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100426 for (ActionContextProvider actionContextProvider : actionContextProviders) {
Ulf Adamsccd5c0a2017-01-13 15:46:51 +0000427 actionContextProvider.executionPhaseStarting(actionGraph, allArtifactsForProviders);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100428 }
429 executor.executionPhaseStarting();
430 skyframeExecutor.drainChangedFiles();
431
432 if (request.getViewOptions().discardAnalysisCache) {
433 // Free memory by removing cache entries that aren't going to be needed. Note that in
434 // skyframe full, this destroys the action graph as well, so we can only do it after the
435 // action graph is no longer needed.
janakrdb4dec22017-03-28 22:39:35 +0000436 env.getSkyframeBuildView()
437 .clearAnalysisCache(analysisResult.getTargetsToBuild(), analysisResult.getAspects());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100438 }
439
440 configureResourceManager(request);
441
442 Profiler.instance().markPhase(ProfilePhase.EXECUTE);
443
Dmitry Lomove2033b12015-08-19 16:57:49 +0000444 builder.buildArtifacts(
Ulf Adams5b9009b2015-09-24 09:52:53 +0000445 env.getReporter(),
Dmitry Lomove2033b12015-08-19 16:57:49 +0000446 additionalArtifacts,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100447 analysisResult.getParallelTests(),
448 analysisResult.getExclusiveTests(),
449 analysisResult.getTargetsToBuild(),
gregce45ae0962017-07-22 00:11:13 +0200450 analysisResult.getTargetsToSkip(),
Dmitry Lomove2033b12015-08-19 16:57:49 +0000451 analysisResult.getAspects(),
452 executor,
453 builtTargets,
Miguel Alcon Pinto7cf23652015-03-10 21:27:48 +0000454 request.getBuildOptions().explanationPath != null,
Googlerbfd4e242016-07-15 22:23:37 +0000455 env.getBlazeWorkspace().getLastExecutionTimeRange(),
456 topLevelArtifactContext);
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000457 buildCompleted = true;
458 } catch (BuildFailedException | TestExecException e) {
459 buildCompleted = true;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100460 throw e;
461 } finally {
Ulf Adamsb5146102015-10-20 08:57:26 +0000462 env.recordLastExecutionTime();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100463 if (request.isRunningInEmacs()) {
Klaus Aehligad87c132017-08-14 12:20:39 +0200464 request
465 .getOutErr()
466 .printErrLn(
467 env.getRuntime().getProductName() + ": Leaving directory `" + getExecRoot() + "/'");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100468 }
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000469 if (buildCompleted) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100470 getReporter().handle(Event.progress("Building complete."));
471 }
472
Ulf Adams633f5392015-09-15 11:13:08 +0000473 env.getEventBus().post(new ExecutionFinishedEvent(ImmutableMap.<String, Long> of(), 0L,
Miguel Alcon Pinto9186f682015-04-09 21:49:34 +0000474 skyframeExecutor.getOutputDirtyFilesAndClear(),
475 skyframeExecutor.getModifiedFilesDuringPreviousBuildAndClear()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100476
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100477 executor.executionPhaseEnding();
478 for (ActionContextProvider actionContextProvider : actionContextProviders) {
479 actionContextProvider.executionPhaseEnding();
480 }
481
482 Profiler.instance().markPhase(ProfilePhase.FINISH);
483
Janak Ramakrishnana5d8d092015-12-08 18:32:47 +0000484 if (buildCompleted) {
jmmv59787f12017-08-28 21:41:21 +0200485 saveActionCache(actionCache);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100486 }
487
Nathan Harmatad4803012015-09-08 20:03:22 +0000488 try (AutoProfiler p = AutoProfiler.profiled("Show results", ProfilerTask.INFO)) {
Ulf Adams7a3fe522015-12-04 10:48:56 +0000489 buildResult.setSuccessfulTargets(
490 determineSuccessfulTargets(configuredTargets, builtTargets, timer));
gregce45ae0962017-07-22 00:11:13 +0200491 buildResult.setSkippedTargets(analysisResult.getTargetsToSkip());
Googler3ca7b782015-10-12 15:44:09 +0000492 BuildResultPrinter buildResultPrinter = new BuildResultPrinter(env);
gregce45ae0962017-07-22 00:11:13 +0200493 buildResultPrinter.showBuildResult(request, buildResult, configuredTargets,
494 analysisResult.getTargetsToSkip(), analysisResult.getAspects());
Nathan Harmatad4803012015-09-08 20:03:22 +0000495 }
Googler3ca7b782015-10-12 15:44:09 +0000496
497 try (AutoProfiler p = AutoProfiler.profiled("Show artifacts", ProfilerTask.INFO)) {
498 if (request.getBuildOptions().showArtifacts) {
499 BuildResultPrinter buildResultPrinter = new BuildResultPrinter(env);
500 buildResultPrinter.showArtifacts(
501 request, configuredTargets, analysisResult.getAspects());
502 }
503 }
504
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100505 if (explanationHandler != null) {
506 uninstallExplanationHandler(explanationHandler);
507 }
508 // Finalize output service last, so that if we do throw an exception, we know all the other
509 // code has already run.
Ulf Adams706b7f22015-10-20 09:06:45 +0000510 if (env.getOutputService() != null) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100511 boolean isBuildSuccessful =
512 buildResult.getSuccessfulTargets().size() == configuredTargets.size();
Ulf Adams706b7f22015-10-20 09:06:45 +0000513 env.getOutputService().finalizeBuild(isBuildSuccessful);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100514 }
515 }
516 }
517
kchodorow85ae1902017-04-22 15:07:22 -0400518 private void prepare(ImmutableMap<PackageIdentifier, Path> packageRoots)
Laurent Le Brunf3cf98f2016-06-17 13:36:24 +0000519 throws ExecutorInitException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100520 // Prepare for build.
521 Profiler.instance().markPhase(ProfilePhase.PREPARE);
522
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100523 // Plant the symlink forest.
Kristina Chodorow52bc57c2016-06-20 14:27:56 +0000524 try {
Dmitry Lomove36a66c2017-02-17 14:48:48 +0000525 new SymlinkForest(
kchodorow85ae1902017-04-22 15:07:22 -0400526 packageRoots, getExecRoot(), runtime.getProductName(), env.getWorkspaceName())
Kristina Chodorow36a6c172016-07-22 15:18:07 +0000527 .plantSymlinkForest();
Kristina Chodorow52bc57c2016-06-20 14:27:56 +0000528 } catch (IOException e) {
529 throw new ExecutorInitException("Source forest creation failed", e);
530 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100531 }
532
533 private void createToolsSymlinks() throws ExecutorInitException {
534 try {
kchodorow85ae1902017-04-22 15:07:22 -0400535 env.getBlazeWorkspace().getBinTools().setupBuildTools(env.getWorkspaceName());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100536 } catch (ExecException e) {
Nathan Harmataca06fa22015-07-27 19:54:14 +0000537 throw new ExecutorInitException("Tools symlink creation failed", e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100538 }
539 }
540
Nathan Harmataca06fa22015-07-27 19:54:14 +0000541 private void createActionLogDirectory() throws ExecutorInitException {
janakr0049e962017-04-05 21:41:23 +0000542 Path directory = env.getActionConsoleOutputDirectory();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100543 try {
544 if (directory.exists()) {
545 FileSystemUtils.deleteTree(directory);
546 }
janakr0049e962017-04-05 21:41:23 +0000547 FileSystemUtils.createDirectoryAndParents(directory);
Nathan Harmataca06fa22015-07-27 19:54:14 +0000548 } catch (IOException e) {
549 throw new ExecutorInitException("Couldn't delete action output directory", e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100550 }
551 }
552
553 /**
554 * Prepare for a local output build.
555 */
kchodorow85ae1902017-04-22 15:07:22 -0400556 private void startLocalOutputBuild() throws ExecutorInitException {
Nathan Harmatad4803012015-09-08 20:03:22 +0000557 try (AutoProfiler p = AutoProfiler.profiled("Starting local output build", ProfilerTask.INFO)) {
kchodorow85ae1902017-04-22 15:07:22 -0400558 Path outputPath = env.getDirectories().getOutputPath(env.getWorkspaceName());
Ulf Adams94b72db2016-03-30 11:58:37 +0000559 Path localOutputPath = env.getDirectories().getLocalOutputPath();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100560
561 if (outputPath.isSymbolicLink()) {
Nathan Harmataca06fa22015-07-27 19:54:14 +0000562 try {
563 // Remove the existing symlink first.
564 outputPath.delete();
565 if (localOutputPath.exists()) {
566 // Pre-existing local output directory. Move to outputPath.
567 localOutputPath.renameTo(outputPath);
568 }
569 } catch (IOException e) {
570 throw new ExecutorInitException("Couldn't handle local output directory symlinks", e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100571 }
572 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100573 }
574 }
575
576 /**
577 * If a path is supplied, creates and installs an ExplanationHandler. Returns
578 * an instance on success. Reports an error and returns null otherwise.
579 */
580 private ExplanationHandler installExplanationHandler(PathFragment explanationPath,
581 String allOptions) {
582 if (explanationPath == null) {
583 return null;
584 }
585 ExplanationHandler handler;
586 try {
587 handler = new ExplanationHandler(
588 getWorkspace().getRelative(explanationPath).getOutputStream(),
589 allOptions);
590 } catch (IOException e) {
591 getReporter().handle(Event.warn(String.format(
592 "Cannot write explanation of rebuilds to file '%s': %s",
593 explanationPath, e.getMessage())));
594 return null;
595 }
596 getReporter().handle(
597 Event.info("Writing explanation of rebuilds to '" + explanationPath + "'"));
598 getReporter().addHandler(handler);
599 return handler;
600 }
601
602 /**
603 * Uninstalls the specified ExplanationHandler (if any) and closes the log
604 * file.
605 */
606 private void uninstallExplanationHandler(ExplanationHandler handler) {
607 if (handler != null) {
608 getReporter().removeHandler(handler);
609 handler.log.close();
610 }
611 }
612
613 /**
614 * An ErrorEventListener implementation that records DEPCHECKER events into a log
615 * file, iff the --explain flag is specified during a build.
616 */
617 private static class ExplanationHandler implements EventHandler {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100618 private final PrintWriter log;
619
620 private ExplanationHandler(OutputStream log, String optionsDescription) {
lberki0d8d4cf2017-09-05 16:01:44 +0200621 this.log = new PrintWriter(new OutputStreamWriter(log, StandardCharsets.UTF_8));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100622 this.log.println("Build options: " + optionsDescription);
623 }
624
625
626 @Override
627 public void handle(Event event) {
628 if (event.getKind() == EventKind.DEPCHECKER) {
629 log.println(event.getMessage());
630 }
631 }
632 }
633
634 /**
635 * Computes the result of the build. Sets the list of successful (up-to-date)
636 * targets in the request object.
637 *
638 * @param configuredTargets The configured targets whose artifacts are to be
639 * built.
640 * @param timer A timer that was started when the execution phase started.
641 */
Ulf Adams7a3fe522015-12-04 10:48:56 +0000642 private Collection<ConfiguredTarget> determineSuccessfulTargets(
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100643 Collection<ConfiguredTarget> configuredTargets, Set<ConfiguredTarget> builtTargets,
644 Stopwatch timer) {
645 // 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) {
649 if (builtTargets.contains(target)) {
650 successfulTargets.add(target);
651 }
652 }
Ulf Adams633f5392015-09-15 11:13:08 +0000653 env.getEventBus().post(
Eric Fellheimere9b41c62016-06-14 15:39:51 +0000654 new ExecutionPhaseCompleteEvent(timer.stop().elapsed(MILLISECONDS)));
Ulf Adams7a3fe522015-12-04 10:48:56 +0000655 return successfulTargets;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100656 }
657
Dmitry Lomov56c7d552015-09-07 14:57:47 +0000658
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100659 private ActionCache getActionCache() throws LocalEnvironmentException {
660 try {
Ulf Adams80613022015-09-16 09:11:33 +0000661 return env.getPersistentActionCache();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100662 } catch (IOException e) {
663 // TODO(bazel-team): (2010) Ideally we should just remove all cache data and reinitialize
664 // caches.
665 LoggingUtil.logToRemote(Level.WARNING, "Failed to initialize action cache: "
666 + e.getMessage(), e);
667 throw new LocalEnvironmentException("couldn't create action cache: " + e.getMessage()
668 + ". If error persists, use 'blaze clean'");
669 }
670 }
671
672 private Builder createBuilder(BuildRequest request,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100673 ActionCache actionCache,
Eric Fellheimerf3b43af2015-11-13 19:51:20 +0000674 SkyframeExecutor skyframeExecutor,
Ulf Adams1ac1b992016-11-02 12:50:26 +0000675 ModifiedFileSet modifiedOutputFiles) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100676 BuildRequest.BuildRequestOptions options = request.getBuildOptions();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100677 boolean keepGoing = request.getViewOptions().keepGoing;
678
janakr0049e962017-04-05 21:41:23 +0000679 Path actionOutputRoot = env.getActionConsoleOutputDirectory();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100680 Predicate<Action> executionFilter = CheckUpToDateFilter.fromOptions(
681 request.getOptions(ExecutionOptions.class));
682
683 // jobs should have been verified in BuildRequest#validateOptions().
684 Preconditions.checkState(options.jobs >= -1);
685 int actualJobs = options.jobs == 0 ? 1 : options.jobs; // Treat 0 jobs as a single task.
686
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100687 skyframeExecutor.setActionOutputRoot(actionOutputRoot);
Ulf Adams3d67e002016-03-29 16:23:01 +0000688 ArtifactFactory artifactFactory = env.getSkyframeBuildView().getArtifactFactory();
Googler2f111922017-02-28 20:58:45 +0000689 return new SkyframeBuilder(
690 skyframeExecutor,
691 new ActionCacheChecker(
692 actionCache,
693 artifactFactory,
694 executionFilter,
695 ActionCacheChecker.CacheConfig.builder()
696 .setEnabled(options.useActionCache)
697 .setVerboseExplanations(options.verboseExplanations)
698 .build()),
699 keepGoing,
700 actualJobs,
Nathan Harmata60108832016-03-25 08:02:42 +0000701 request.getPackageCacheOptions().checkOutputFiles
Googler2f111922017-02-28 20:58:45 +0000702 ? modifiedOutputFiles
703 : ModifiedFileSet.NOTHING_MODIFIED,
704 options.finalizeActions,
705 fileCache,
ulfjack7599a4d2017-07-21 13:58:33 +0200706 prefetcher,
Googler2f111922017-02-28 20:58:45 +0000707 request.getBuildOptions().progressReportInterval);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100708 }
709
710 private void configureResourceManager(BuildRequest request) {
711 ResourceManager resourceMgr = ResourceManager.instance();
712 ExecutionOptions options = request.getOptions(ExecutionOptions.class);
Mark Schallerdffb6ee2015-02-25 20:01:01 +0000713 ResourceSet resources;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100714 if (options.availableResources != null) {
Mark Schallerdffb6ee2015-02-25 20:01:01 +0000715 resources = options.availableResources;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100716 resourceMgr.setRamUtilizationPercentage(100);
717 } else {
Mark Schallerdffb6ee2015-02-25 20:01:01 +0000718 resources = LocalHostCapacity.getLocalHostCapacity();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100719 resourceMgr.setRamUtilizationPercentage(options.ramUtilizationPercentage);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100720 }
Mark Schallerdffb6ee2015-02-25 20:01:01 +0000721
722 resourceMgr.setAvailableResources(ResourceSet.create(
723 resources.getMemoryMb(),
724 resources.getCpuUsage(),
725 resources.getIoUsage(),
726 request.getExecutionOptions().usingLocalTestJobs()
727 ? request.getExecutionOptions().localTestJobs : Integer.MAX_VALUE
728 ));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100729 }
730
731 /**
jmmv59787f12017-08-28 21:41:21 +0200732 * Writes the action cache files to disk, reporting any errors that occurred during writing and
733 * capturing statistics.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100734 */
jmmv59787f12017-08-28 21:41:21 +0200735 private void saveActionCache(ActionCache actionCache) {
jmmvccb43ee2017-08-30 22:07:10 +0200736 ActionCacheStatistics.Builder builder = ActionCacheStatistics.newBuilder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100737
lberki97abb522017-09-04 18:51:57 +0200738 AutoProfiler p =
739 AutoProfiler.profiledAndLogged("Saving action cache", ProfilerTask.INFO, logger);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100740 try {
jmmv59787f12017-08-28 21:41:21 +0200741 builder.setSizeInBytes(actionCache.save());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100742 } catch (IOException e) {
jmmv59787f12017-08-28 21:41:21 +0200743 builder.setSizeInBytes(0);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100744 getReporter().handle(Event.error("I/O error while writing action log: " + e.getMessage()));
745 } finally {
jmmvccb43ee2017-08-30 22:07:10 +0200746 builder.setSaveTimeInMs(
747 TimeUnit.MILLISECONDS.convert(p.completeAndGetElapsedTimeNanos(), TimeUnit.NANOSECONDS));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100748 }
jmmv59787f12017-08-28 21:41:21 +0200749
750 env.getEventBus().post(builder.build());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100751 }
752
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100753 private Reporter getReporter() {
Ulf Adams633f5392015-09-15 11:13:08 +0000754 return env.getReporter();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100755 }
756
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100757 private Path getWorkspace() {
Ulf Adams94b72db2016-03-30 11:58:37 +0000758 return env.getWorkspace();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100759 }
760
761 private Path getExecRoot() {
Ulf Adams94b72db2016-03-30 11:58:37 +0000762 return env.getExecRoot();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100763 }
764}