blob: d72bb3421ef6adfbd6d98d714787b9ea2eef6f70 [file] [log] [blame]
ulfjack9274cba2017-08-11 23:19:48 +02001// Copyright 2017 The Bazel Authors. All rights reserved.
2//
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.remote;
15
Jakob Buchgraber321138f2018-05-07 05:24:53 -070016import static com.google.common.base.Strings.isNullOrEmpty;
chiwangae539912021-04-23 00:25:02 -070017import static com.google.devtools.build.lib.profiler.ProfilerTask.REMOTE_DOWNLOAD;
buchgrd480c5f2019-04-03 00:53:34 -070018import static com.google.devtools.build.lib.remote.util.Utils.createSpawnResult;
Jakob Buchgraber321138f2018-05-07 05:24:53 -070019
Chi Wang46c3f172021-08-05 00:52:44 -070020import com.google.common.annotations.VisibleForTesting;
George Gensure7aa74982020-04-01 00:54:15 -070021import com.google.common.base.Stopwatch;
George Gensure54b062c2020-09-02 05:06:40 -070022import com.google.common.base.Throwables;
ulfjack9274cba2017-08-11 23:19:48 +020023import com.google.devtools.build.lib.actions.ActionInput;
24import com.google.devtools.build.lib.actions.ExecException;
shahan602cc852018-06-06 20:09:57 -070025import com.google.devtools.build.lib.actions.FileArtifactValue;
janakr300c11e2021-05-18 12:10:43 -070026import com.google.devtools.build.lib.actions.ForbiddenActionInputException;
ulfjack9274cba2017-08-11 23:19:48 +020027import com.google.devtools.build.lib.actions.Spawn;
George Gensure7aa74982020-04-01 00:54:15 -070028import com.google.devtools.build.lib.actions.SpawnMetrics;
rupertsda40fbf2017-09-22 05:59:42 +020029import com.google.devtools.build.lib.actions.SpawnResult;
30import com.google.devtools.build.lib.actions.SpawnResult.Status;
Mike Moreartyd8ac06a2018-04-12 01:59:34 -070031import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
ulfjack9274cba2017-08-11 23:19:48 +020032import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
Benjamin Peterson3ff87f72017-08-21 18:41:45 +020033import com.google.devtools.build.lib.events.Event;
34import com.google.devtools.build.lib.events.Reporter;
ulfjack9274cba2017-08-11 23:19:48 +020035import com.google.devtools.build.lib.exec.SpawnCache;
Chi Wangf0983dfd2021-06-10 21:28:52 -070036import com.google.devtools.build.lib.exec.SpawnCheckingCacheEvent;
37import com.google.devtools.build.lib.exec.SpawnExecutingEvent;
tomlu29e306d2018-04-19 05:41:44 -070038import com.google.devtools.build.lib.exec.SpawnRunner.SpawnExecutionContext;
ulfjack5f436f32018-11-06 05:17:23 -080039import com.google.devtools.build.lib.profiler.Profiler;
Jakob Buchgraber4b3c2eb2019-04-04 02:01:48 -070040import com.google.devtools.build.lib.profiler.ProfilerTask;
ulfjack5f436f32018-11-06 05:17:23 -080041import com.google.devtools.build.lib.profiler.SilentCloseable;
chiwangae539912021-04-23 00:25:02 -070042import com.google.devtools.build.lib.remote.RemoteExecutionService.RemoteAction;
43import com.google.devtools.build.lib.remote.RemoteExecutionService.RemoteActionResult;
Jakob Buchgraber18462692019-11-06 04:34:16 -080044import com.google.devtools.build.lib.remote.common.CacheNotFoundException;
Jakob Buchgraber75b7ed42019-03-27 10:27:13 -070045import com.google.devtools.build.lib.remote.options.RemoteOptions;
Jakob Buchgrabera79a4b62019-06-23 02:06:20 -070046import com.google.devtools.build.lib.remote.util.Utils;
buchgrd480c5f2019-04-03 00:53:34 -070047import com.google.devtools.build.lib.remote.util.Utils.InMemoryOutput;
ulfjack9274cba2017-08-11 23:19:48 +020048import com.google.devtools.build.lib.vfs.Path;
ulfjack9274cba2017-08-11 23:19:48 +020049import java.io.IOException;
Jakob Buchgraber321138f2018-05-07 05:24:53 -070050import java.util.HashSet;
ulfjack9274cba2017-08-11 23:19:48 +020051import java.util.NoSuchElementException;
Jakob Buchgraber321138f2018-05-07 05:24:53 -070052import java.util.Set;
Benjamin Peterson3ff87f72017-08-21 18:41:45 +020053import javax.annotation.Nullable;
ulfjack9274cba2017-08-11 23:19:48 +020054
Jakob Buchgraber321138f2018-05-07 05:24:53 -070055/** A remote {@link SpawnCache} implementation. */
ulfjack9274cba2017-08-11 23:19:48 +020056@ThreadSafe // If the RemoteActionCache implementation is thread-safe.
ulfjack9274cba2017-08-11 23:19:48 +020057final class RemoteSpawnCache implements SpawnCache {
Jakob Buchgraber50c10042019-04-11 02:11:19 -070058
Chi Wangf0983dfd2021-06-10 21:28:52 -070059 private static final SpawnCheckingCacheEvent SPAWN_CHECKING_CACHE_EVENT =
60 SpawnCheckingCacheEvent.create("remote-cache");
61
62 private static final SpawnExecutingEvent SPAWN_EXECUTING_EVENT =
63 SpawnExecutingEvent.create("remote-cache");
64
ulfjack9274cba2017-08-11 23:19:48 +020065 private final Path execRoot;
66 private final RemoteOptions options;
George Gensure54b062c2020-09-02 05:06:40 -070067 private final boolean verboseFailures;
Benjamin Peterson3ff87f72017-08-21 18:41:45 +020068 @Nullable private final Reporter cmdlineReporter;
Jakob Buchgraber321138f2018-05-07 05:24:53 -070069 private final Set<String> reportedErrors = new HashSet<>();
chiwangae539912021-04-23 00:25:02 -070070 private final RemoteExecutionService remoteExecutionService;
Jakob Buchgraber50c10042019-04-11 02:11:19 -070071
olaola6f32d5a2017-09-20 17:12:19 +020072 RemoteSpawnCache(
73 Path execRoot,
74 RemoteOptions options,
George Gensure54b062c2020-09-02 05:06:40 -070075 boolean verboseFailures,
buchgr559a07d2017-11-30 11:09:35 -080076 @Nullable Reporter cmdlineReporter,
chiwangae539912021-04-23 00:25:02 -070077 RemoteExecutionService remoteExecutionService) {
ulfjack9274cba2017-08-11 23:19:48 +020078 this.execRoot = execRoot;
79 this.options = options;
George Gensure54b062c2020-09-02 05:06:40 -070080 this.verboseFailures = verboseFailures;
Benjamin Peterson3ff87f72017-08-21 18:41:45 +020081 this.cmdlineReporter = cmdlineReporter;
chiwangae539912021-04-23 00:25:02 -070082 this.remoteExecutionService = remoteExecutionService;
ulfjack9274cba2017-08-11 23:19:48 +020083 }
84
Chi Wang46c3f172021-08-05 00:52:44 -070085 @VisibleForTesting
86 RemoteExecutionService getRemoteExecutionService() {
87 return remoteExecutionService;
88 }
89
ulfjack9274cba2017-08-11 23:19:48 +020090 @Override
tomlu29e306d2018-04-19 05:41:44 -070091 public CacheHandle lookup(Spawn spawn, SpawnExecutionContext context)
janakr300c11e2021-05-18 12:10:43 -070092 throws InterruptedException, IOException, ExecException, ForbiddenActionInputException {
Chi Wang46c3f172021-08-05 00:52:44 -070093 boolean shouldAcceptCachedResult = remoteExecutionService.shouldAcceptCachedResult(spawn);
94 boolean shouldUploadLocalResults = remoteExecutionService.shouldUploadLocalResults(spawn);
95 if (!shouldAcceptCachedResult && !shouldUploadLocalResults) {
Benjamin Petersonf1570532019-01-24 07:14:18 -080096 return SpawnCache.NO_RESULT_NO_STORE;
97 }
Benjamin Peterson7e1c7bc2018-05-03 04:30:19 -070098
George Gensure7aa74982020-04-01 00:54:15 -070099 Stopwatch totalTime = Stopwatch.createStarted();
100
chiwangae539912021-04-23 00:25:02 -0700101 RemoteAction action = remoteExecutionService.buildRemoteAction(spawn, context);
George Gensure7aa74982020-04-01 00:54:15 -0700102 SpawnMetrics.Builder spawnMetrics =
Googler2b7e71a2020-06-04 01:32:01 -0700103 SpawnMetrics.Builder.forRemoteExec()
chiwangae539912021-04-23 00:25:02 -0700104 .setInputBytes(action.getInputBytes())
105 .setInputFiles(action.getInputFiles());
Benjamin Peterson7e1c7bc2018-05-03 04:30:19 -0700106
Jakob Buchgraber4b3c2eb2019-04-04 02:01:48 -0700107 Profiler prof = Profiler.instance();
Chi Wang46c3f172021-08-05 00:52:44 -0700108 if (shouldAcceptCachedResult) {
Chi Wangf0983dfd2021-06-10 21:28:52 -0700109 context.report(SPAWN_CHECKING_CACHE_EVENT);
Benjamin Peterson7e1c7bc2018-05-03 04:30:19 -0700110 // Metadata will be available in context.current() until we detach.
111 // This is done via a thread-local variable.
Benjamin Peterson7e1c7bc2018-05-03 04:30:19 -0700112 try {
chiwangae539912021-04-23 00:25:02 -0700113 RemoteActionResult result;
Jakob Buchgraber4b3c2eb2019-04-04 02:01:48 -0700114 try (SilentCloseable c = prof.profile(ProfilerTask.REMOTE_CACHE_CHECK, "check cache hit")) {
chiwangae539912021-04-23 00:25:02 -0700115 result = remoteExecutionService.lookupCache(action);
ulfjack5f436f32018-11-06 05:17:23 -0800116 }
Jakob Buchgraber50c10042019-04-11 02:11:19 -0700117 // In case the remote cache returned a failed action (exit code != 0) we treat it as a
118 // cache miss
ishikhman62f54582019-03-18 03:42:42 -0700119 if (result != null && result.getExitCode() == 0) {
George Gensure7aa74982020-04-01 00:54:15 -0700120 Stopwatch fetchTime = Stopwatch.createStarted();
chiwangae539912021-04-23 00:25:02 -0700121 InMemoryOutput inMemoryOutput;
122 try (SilentCloseable c = prof.profile(REMOTE_DOWNLOAD, "download outputs")) {
123 inMemoryOutput = remoteExecutionService.downloadOutputs(action, result);
ulfjack5f436f32018-11-06 05:17:23 -0800124 }
George Gensure7aa74982020-04-01 00:54:15 -0700125 fetchTime.stop();
126 totalTime.stop();
127 spawnMetrics
128 .setFetchTime(fetchTime.elapsed())
129 .setTotalTime(totalTime.elapsed())
chiwangae539912021-04-23 00:25:02 -0700130 .setNetworkTime(action.getNetworkTime().getDuration());
Benjamin Peterson7e1c7bc2018-05-03 04:30:19 -0700131 SpawnResult spawnResult =
buchgrd480c5f2019-04-03 00:53:34 -0700132 createSpawnResult(
George Gensure7aa74982020-04-01 00:54:15 -0700133 result.getExitCode(),
janakrf8dc2eb2020-09-30 08:06:53 -0700134 /*cacheHit=*/ true,
ron-stripecf57d032021-08-26 06:07:30 -0700135 result.cacheName(),
George Gensure7aa74982020-04-01 00:54:15 -0700136 inMemoryOutput,
janakrf8dc2eb2020-09-30 08:06:53 -0700137 spawnMetrics.build(),
138 spawn.getMnemonic());
Benjamin Peterson7e1c7bc2018-05-03 04:30:19 -0700139 return SpawnCache.success(spawnResult);
140 }
Benjamin Peterson1532df02019-01-24 08:45:44 -0800141 } catch (CacheNotFoundException e) {
142 // Intentionally left blank
Benjamin Peterson7e1c7bc2018-05-03 04:30:19 -0700143 } catch (IOException e) {
George Gensure54b062c2020-09-02 05:06:40 -0700144 if (BulkTransferException.isOnlyCausedByCacheNotFoundException(e)) {
145 // Intentionally left blank
146 } else {
147 String errorMessage;
148 if (!verboseFailures) {
149 errorMessage = Utils.grpcAwareErrorMessage(e);
150 } else {
151 // On --verbose_failures print the whole stack trace
152 errorMessage = Throwables.getStackTraceAsString(e);
153 }
154 if (isNullOrEmpty(errorMessage)) {
155 errorMessage = e.getClass().getSimpleName();
156 }
157 errorMessage = "Reading from Remote Cache:\n" + errorMessage;
158 report(Event.warn(errorMessage));
Benjamin Peterson1532df02019-01-24 08:45:44 -0800159 }
ulfjack9274cba2017-08-11 23:19:48 +0200160 }
ulfjack9274cba2017-08-11 23:19:48 +0200161 }
buchgrd480c5f2019-04-03 00:53:34 -0700162
Chi Wangf0983dfd2021-06-10 21:28:52 -0700163 context.report(SPAWN_EXECUTING_EVENT);
164
buchgrd480c5f2019-04-03 00:53:34 -0700165 context.prefetchInputs();
166
Chi Wang46c3f172021-08-05 00:52:44 -0700167 if (shouldUploadLocalResults) {
olaolaba8b0b32017-10-20 09:48:56 +0200168 return new CacheHandle() {
169 @Override
170 public boolean hasResult() {
171 return false;
172 }
173
174 @Override
175 public SpawnResult getResult() {
176 throw new NoSuchElementException();
177 }
178
179 @Override
180 public boolean willStore() {
181 return true;
182 }
183
184 @Override
Jakob Buchgraberbac30fe2019-01-28 05:24:23 -0800185 public void store(SpawnResult result) throws ExecException, InterruptedException {
186 boolean uploadResults = Status.SUCCESS.equals(result.status()) && result.exitCode() == 0;
187 if (!uploadResults) {
188 return;
189 }
190
ulfjack8896d2e2018-01-19 02:55:21 -0800191 if (options.experimentalGuardAgainstConcurrentChanges) {
Jakob Buchgraber4b3c2eb2019-04-04 02:01:48 -0700192 try (SilentCloseable c = prof.profile("RemoteCache.checkForConcurrentModifications")) {
ulfjack8896d2e2018-01-19 02:55:21 -0800193 checkForConcurrentModifications();
194 } catch (IOException e) {
195 report(Event.warn(e.getMessage()));
196 return;
197 }
198 }
Jakob Buchgraberbac30fe2019-01-28 05:24:23 -0800199
Jakob Buchgraber4b3c2eb2019-04-04 02:01:48 -0700200 try (SilentCloseable c = prof.profile(ProfilerTask.UPLOAD_TIME, "upload outputs")) {
chiwangae539912021-04-23 00:25:02 -0700201 remoteExecutionService.uploadOutputs(action);
olaolaba8b0b32017-10-20 09:48:56 +0200202 } catch (IOException e) {
George Gensure54b062c2020-09-02 05:06:40 -0700203 String errorMessage;
204 if (!verboseFailures) {
205 errorMessage = Utils.grpcAwareErrorMessage(e);
206 } else {
207 // On --verbose_failures print the whole stack trace
208 errorMessage = Throwables.getStackTraceAsString(e);
olaolaba8b0b32017-10-20 09:48:56 +0200209 }
George Gensure54b062c2020-09-02 05:06:40 -0700210 if (isNullOrEmpty(errorMessage)) {
211 errorMessage = e.getClass().getSimpleName();
212 }
213 errorMessage = "Writing to Remote Cache:\n" + errorMessage;
214 report(Event.warn(errorMessage));
olaolaba8b0b32017-10-20 09:48:56 +0200215 }
216 }
217
218 @Override
219 public void close() {}
ulfjack8896d2e2018-01-19 02:55:21 -0800220
221 private void checkForConcurrentModifications() throws IOException {
chiwangae539912021-04-23 00:25:02 -0700222 for (ActionInput input : action.getInputMap().values()) {
Mike Moreartyd8ac06a2018-04-12 01:59:34 -0700223 if (input instanceof VirtualActionInput) {
224 continue;
225 }
shahan499503b2018-06-07 18:57:07 -0700226 FileArtifactValue metadata = context.getMetadataProvider().getMetadata(input);
olaolaf0aa55d2018-08-16 08:51:06 -0700227 Path path = execRoot.getRelative(input.getExecPath());
228 if (metadata.wasModifiedSinceDigest(path)) {
229 throw new IOException(path + " was modified during execution");
ulfjack8896d2e2018-01-19 02:55:21 -0800230 }
231 }
232 }
olaolaba8b0b32017-10-20 09:48:56 +0200233 };
234 } else {
235 return SpawnCache.NO_RESULT_NO_STORE;
236 }
ulfjack9274cba2017-08-11 23:19:48 +0200237 }
Benjamin Peterson3ff87f72017-08-21 18:41:45 +0200238
Benjamin Peterson3ff87f72017-08-21 18:41:45 +0200239 private void report(Event evt) {
Jakob Buchgraber321138f2018-05-07 05:24:53 -0700240 if (cmdlineReporter == null) {
241 return;
242 }
243
244 synchronized (this) {
245 if (reportedErrors.contains(evt.getMessage())) {
246 return;
247 }
248 reportedErrors.add(evt.getMessage());
Benjamin Peterson3ff87f72017-08-21 18:41:45 +0200249 cmdlineReporter.handle(evt);
250 }
251 }
Sergio Rodriguez Orellana8860c3e2019-07-25 01:12:58 -0700252
larsrc02838a12020-11-10 03:46:53 -0800253 @Override
254 public boolean usefulInDynamicExecution() {
255 return false;
256 }
ulfjack9274cba2017-08-11 23:19:48 +0200257}