1414
1515package com .google .devtools .build .lib .remote ;
1616
17+ import com .google .common .annotations .VisibleForTesting ;
1718import com .google .common .base .Throwables ;
1819import com .google .common .collect .ImmutableMap ;
1920import com .google .devtools .build .lib .actions .ActionInput ;
5455
5556/** A client for the remote execution service. */
5657@ ThreadSafe
57- final class RemoteSpawnRunner implements SpawnRunner {
58+ class RemoteSpawnRunner implements SpawnRunner {
5859 private final Path execRoot ;
5960 private final RemoteOptions options ;
6061 // TODO(olaola): This will be set on a per-action basis instead.
@@ -127,7 +128,8 @@ public SpawnResult exec(Spawn spawn, SpawnExecutionPolicy policy)
127128 }
128129
129130 if (remoteExecutor == null ) {
130- return execLocally (spawn , policy , inputMap , remoteCache , actionKey );
131+ return execLocally (spawn , policy , inputMap , options .remoteUploadLocalResults ,
132+ remoteCache , actionKey );
131133 }
132134
133135 // Upload the command and all the inputs into the remote cache.
@@ -142,7 +144,8 @@ public SpawnResult exec(Spawn spawn, SpawnExecutionPolicy policy)
142144 ExecuteResponse reply = remoteExecutor .executeRemotely (request .build ());
143145 result = reply .getResult ();
144146 if (options .remoteLocalFallback && result .getExitCode () != 0 ) {
145- return execLocally (spawn , policy , inputMap , remoteCache , actionKey );
147+ return execLocally (spawn , policy , inputMap , options .remoteUploadLocalResults ,
148+ remoteCache , actionKey );
146149 }
147150 remoteCache .download (result , execRoot , policy .getFileOutErr ());
148151 return new SpawnResult .Builder ()
@@ -151,7 +154,8 @@ public SpawnResult exec(Spawn spawn, SpawnExecutionPolicy policy)
151154 .build ();
152155 } catch (IOException e ) {
153156 if (options .remoteLocalFallback ) {
154- return execLocally (spawn , policy , inputMap , remoteCache , actionKey );
157+ return execLocally (spawn , policy , inputMap , options .remoteUploadLocalResults ,
158+ remoteCache , actionKey );
155159 }
156160
157161 String message = "" ;
@@ -206,7 +210,7 @@ private Command buildCommand(List<String> arguments, ImmutableMap<String, String
206210 return command .build ();
207211 }
208212
209- Map <Path , Long > getInputCtimes (SortedMap <PathFragment , ActionInput > inputMap ) {
213+ private Map <Path , Long > getInputCtimes (SortedMap <PathFragment , ActionInput > inputMap ) {
210214 HashMap <Path , Long > ctimes = new HashMap <>();
211215 for (Map .Entry <PathFragment , ActionInput > e : inputMap .entrySet ()) {
212216 ActionInput input = e .getValue ();
@@ -227,23 +231,36 @@ Map<Path, Long> getInputCtimes(SortedMap<PathFragment, ActionInput> inputMap) {
227231 }
228232
229233 /**
230- * Fallback: execute the spawn locally. If an ActionKey is provided, try to upload results to
231- * remote action cache.
234+ * Execute a {@link Spawn} locally, using {@link #fallbackRunner}.
235+ *
236+ * <p>If possible also upload the {@link SpawnResult} to a remote cache.
232237 */
233238 private SpawnResult execLocally (
234239 Spawn spawn ,
235240 SpawnExecutionPolicy policy ,
236241 SortedMap <PathFragment , ActionInput > inputMap ,
237- RemoteActionCache remoteCache ,
238- ActionKey actionKey )
239- throws ExecException , IOException , InterruptedException {
240- if (!options .remoteUploadLocalResults || !Spawns .mayBeCached (spawn ) || remoteCache == null
241- || actionKey == null ) {
242- // This is an optimization to not compute the ctimes in case remote upload is disabled.
243- return fallbackRunner .exec (spawn , policy );
242+ boolean uploadToCache ,
243+ @ Nullable RemoteActionCache remoteCache ,
244+ @ Nullable ActionKey actionKey ) throws ExecException , IOException , InterruptedException {
245+ if (uploadToCache && Spawns .mayBeCached (spawn ) && remoteCache != null && actionKey != null ) {
246+ return execLocallyAndUpload (spawn , policy , inputMap , remoteCache , actionKey );
244247 }
248+ return fallbackRunner .exec (spawn , policy );
249+ }
250+
251+ @ VisibleForTesting
252+ SpawnResult execLocallyAndUpload (
253+ Spawn spawn ,
254+ SpawnExecutionPolicy policy ,
255+ SortedMap <PathFragment , ActionInput > inputMap ,
256+ RemoteActionCache remoteCache ,
257+ ActionKey actionKey ) throws ExecException , IOException , InterruptedException {
245258 Map <Path , Long > ctimesBefore = getInputCtimes (inputMap );
246259 SpawnResult result = fallbackRunner .exec (spawn , policy );
260+ if (!Status .SUCCESS .equals (result .status ()) || result .exitCode () != 0 ) {
261+ // Don't upload failed actions.
262+ return result ;
263+ }
247264 Map <Path , Long > ctimesAfter = getInputCtimes (inputMap );
248265 for (Map .Entry <Path , Long > e : ctimesBefore .entrySet ()) {
249266 // Skip uploading to remote cache, because an input was modified during execution.
0 commit comments