|
29 | 29 | import static com.google.devtools.build.lib.remote.util.Utils.waitForBulkTransfer; |
30 | 30 | import static com.google.devtools.build.lib.util.StringUtil.reencodeExternalToInternal; |
31 | 31 | import static com.google.devtools.build.lib.util.StringUtil.reencodeInternalToExternal; |
| 32 | +import static java.util.Collections.min; |
32 | 33 |
|
33 | 34 | import build.bazel.remote.execution.v2.Action; |
34 | 35 | import build.bazel.remote.execution.v2.ActionResult; |
|
156 | 157 | import java.util.concurrent.Semaphore; |
157 | 158 | import java.util.concurrent.atomic.AtomicBoolean; |
158 | 159 | import java.util.concurrent.atomic.AtomicReference; |
| 160 | +import java.util.stream.Stream; |
159 | 161 | import javax.annotation.Nullable; |
160 | 162 |
|
161 | 163 | /** |
@@ -196,6 +198,8 @@ public class RemoteExecutionService { |
196 | 198 | @Nullable private final Scrubber scrubber; |
197 | 199 | private final Set<Digest> knownMissingCasDigests; |
198 | 200 |
|
| 201 | + private Boolean useOutputPaths; |
| 202 | + |
199 | 203 | public RemoteExecutionService( |
200 | 204 | Executor executor, |
201 | 205 | Reporter reporter, |
@@ -242,32 +246,39 @@ public RemoteExecutionService( |
242 | 246 | } |
243 | 247 |
|
244 | 248 | private Command buildCommand( |
| 249 | + boolean useOutputPaths, |
245 | 250 | Collection<? extends ActionInput> outputs, |
246 | 251 | List<String> arguments, |
247 | 252 | ImmutableMap<String, String> env, |
248 | 253 | @Nullable Platform platform, |
249 | 254 | RemotePathResolver remotePathResolver, |
250 | 255 | @Nullable SpawnScrubber spawnScrubber) { |
251 | 256 | Command.Builder command = Command.newBuilder(); |
252 | | - ArrayList<String> outputFiles = new ArrayList<>(); |
253 | | - ArrayList<String> outputDirectories = new ArrayList<>(); |
254 | | - ArrayList<String> outputPaths = new ArrayList<>(); |
255 | | - for (ActionInput output : outputs) { |
256 | | - String pathString = |
257 | | - reencodeInternalToExternal(remotePathResolver.localPathToOutputPath(output)); |
258 | | - if (output.isDirectory()) { |
259 | | - outputDirectories.add(pathString); |
260 | | - } else { |
261 | | - outputFiles.add(pathString); |
| 257 | + if (useOutputPaths) { |
| 258 | + var outputPaths = new ArrayList<String>(); |
| 259 | + for (ActionInput output : outputs) { |
| 260 | + String pathString = |
| 261 | + reencodeInternalToExternal(remotePathResolver.localPathToOutputPath(output)); |
| 262 | + outputPaths.add(pathString); |
262 | 263 | } |
263 | | - outputPaths.add(pathString); |
| 264 | + Collections.sort(outputPaths); |
| 265 | + command.addAllOutputPaths(outputPaths); |
| 266 | + } else { |
| 267 | + var outputFiles = new ArrayList<String>(); |
| 268 | + var outputDirectories = new ArrayList<String>(); |
| 269 | + for (ActionInput output : outputs) { |
| 270 | + String pathString = |
| 271 | + reencodeInternalToExternal(remotePathResolver.localPathToOutputPath(output)); |
| 272 | + if (output.isDirectory()) { |
| 273 | + outputDirectories.add(pathString); |
| 274 | + } else { |
| 275 | + outputFiles.add(pathString); |
| 276 | + } |
| 277 | + } |
| 278 | + Collections.sort(outputFiles); |
| 279 | + Collections.sort(outputDirectories); |
| 280 | + command.addAllOutputFiles(outputFiles).addAllOutputDirectories(outputDirectories); |
264 | 281 | } |
265 | | - Collections.sort(outputFiles); |
266 | | - Collections.sort(outputDirectories); |
267 | | - Collections.sort(outputPaths); |
268 | | - command.addAllOutputFiles(outputFiles); |
269 | | - command.addAllOutputDirectories(outputDirectories); |
270 | | - command.addAllOutputPaths(outputPaths); |
271 | 282 |
|
272 | 283 | if (platform != null) { |
273 | 284 | command.setPlatform(platform); |
@@ -542,6 +553,65 @@ private void maybeReleaseRemoteActionBuildingSemaphore() { |
542 | 553 | remoteActionBuildingSemaphore.release(); |
543 | 554 | } |
544 | 555 |
|
| 556 | + private boolean useOutputPaths() { |
| 557 | + if (this.useOutputPaths == null) { |
| 558 | + initUseOutputPaths(); |
| 559 | + } |
| 560 | + return this.useOutputPaths; |
| 561 | + } |
| 562 | + |
| 563 | + private synchronized void initUseOutputPaths() { |
| 564 | + // If this has already been initialized, return |
| 565 | + if (this.useOutputPaths != null) { |
| 566 | + return; |
| 567 | + } |
| 568 | + ApiVersion serverHighestVersion = null; |
| 569 | + try { |
| 570 | + // If both Remote Executor and Remote Cache are configured, |
| 571 | + // use the highest version supported by both. |
| 572 | + |
| 573 | + ClientApiVersion.ServerSupportedStatus executorSupportStatus = null; |
| 574 | + if (remoteExecutor != null) { |
| 575 | + var serverCapabilities = remoteExecutor.getServerCapabilities(); |
| 576 | + if (serverCapabilities != null) { |
| 577 | + executorSupportStatus = |
| 578 | + ClientApiVersion.current.checkServerSupportedVersions(serverCapabilities); |
| 579 | + } |
| 580 | + } |
| 581 | + |
| 582 | + ClientApiVersion.ServerSupportedStatus cacheSupportStatus = null; |
| 583 | + if (remoteCache != null) { |
| 584 | + var serverCapabilities = remoteCache.getRemoteServerCapabilities(); |
| 585 | + if (serverCapabilities != null) { |
| 586 | + cacheSupportStatus = |
| 587 | + ClientApiVersion.current.checkServerSupportedVersions(serverCapabilities); |
| 588 | + } |
| 589 | + } |
| 590 | + |
| 591 | + ApiVersion executorHighestVersion = null; |
| 592 | + if (executorSupportStatus != null && executorSupportStatus.isSupported()) { |
| 593 | + executorHighestVersion = executorSupportStatus.getHighestSupportedVersion(); |
| 594 | + } |
| 595 | + |
| 596 | + ApiVersion cacheHighestVersion = null; |
| 597 | + if (cacheSupportStatus != null && cacheSupportStatus.isSupported()) { |
| 598 | + cacheHighestVersion = cacheSupportStatus.getHighestSupportedVersion(); |
| 599 | + } |
| 600 | + |
| 601 | + if (executorHighestVersion != null && cacheHighestVersion != null) { |
| 602 | + serverHighestVersion = min(ImmutableList.of(executorHighestVersion, cacheHighestVersion)); |
| 603 | + } else if (executorHighestVersion != null) { |
| 604 | + serverHighestVersion = executorHighestVersion; |
| 605 | + } else if (cacheHighestVersion != null) { |
| 606 | + serverHighestVersion = cacheHighestVersion; |
| 607 | + } |
| 608 | + } catch (IOException e) { |
| 609 | + // Intentionally ignored. |
| 610 | + } |
| 611 | + this.useOutputPaths = |
| 612 | + serverHighestVersion == null || serverHighestVersion.compareTo(ApiVersion.twoPointOne) >= 0; |
| 613 | + } |
| 614 | + |
545 | 615 | /** Creates a new {@link RemoteAction} instance from spawn. */ |
546 | 616 | public RemoteAction buildRemoteAction(Spawn spawn, SpawnExecutionContext context) |
547 | 617 | throws IOException, ExecException, ForbiddenActionInputException, InterruptedException { |
@@ -570,6 +640,7 @@ public RemoteAction buildRemoteAction(Spawn spawn, SpawnExecutionContext context |
570 | 640 |
|
571 | 641 | Command command = |
572 | 642 | buildCommand( |
| 643 | + useOutputPaths(), |
573 | 644 | spawn.getOutputFiles(), |
574 | 645 | spawn.getArguments(), |
575 | 646 | spawn.getEnvironment(), |
@@ -1540,8 +1611,15 @@ public SpawnResult waitForAndReuseOutputs(RemoteAction action, LocalExecution pr |
1540 | 1611 | Map<Path, Path> realToTmpPath = new HashMap<>(); |
1541 | 1612 | ByteString inMemoryOutputContent = null; |
1542 | 1613 | String inMemoryOutputPath = null; |
| 1614 | + var outputPathsList = |
| 1615 | + useOutputPaths() |
| 1616 | + ? action.getCommand().getOutputPathsList() |
| 1617 | + : Stream.concat( |
| 1618 | + action.getCommand().getOutputFilesList().stream(), |
| 1619 | + action.getCommand().getOutputDirectoriesList().stream()) |
| 1620 | + .toList(); |
1543 | 1621 | try { |
1544 | | - for (String output : action.getCommand().getOutputPathsList()) { |
| 1622 | + for (String output : outputPathsList) { |
1545 | 1623 | String reencodedOutput = reencodeExternalToInternal(output); |
1546 | 1624 | Path sourcePath = |
1547 | 1625 | previousExecution.action.getRemotePathResolver().outputPathToLocalPath(reencodedOutput); |
|
0 commit comments