Skip to content

Commit 652b48e

Browse files
ckolli5jmillikin
authored andcommitted
Fix downloading remote execution output files inside output dirs. (#15444)
Adds a check to prevent creating multiple download futures for output files that are children of output directories. Fixes #15328 Closes #15329. PiperOrigin-RevId: 444542026 Co-authored-by: John Millikin <[email protected]>
1 parent a430042 commit 652b48e

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -1048,13 +1048,21 @@ public InMemoryOutput downloadOutputs(RemoteAction action, RemoteActionResult re
10481048
hasFilesToDownload(action.spawn.getOutputFiles(), filesToDownload));
10491049

10501050
if (downloadOutputs) {
1051+
HashSet<PathFragment> queuedFilePaths = new HashSet<>();
1052+
10511053
for (FileMetadata file : metadata.files()) {
1052-
downloadsBuilder.add(downloadFile(action, file));
1054+
PathFragment filePath = file.path().asFragment();
1055+
if (queuedFilePaths.add(filePath)) {
1056+
downloadsBuilder.add(downloadFile(action, file));
1057+
}
10531058
}
10541059

10551060
for (Map.Entry<Path, DirectoryMetadata> entry : metadata.directories()) {
10561061
for (FileMetadata file : entry.getValue().files()) {
1057-
downloadsBuilder.add(downloadFile(action, file));
1062+
PathFragment filePath = file.path().asFragment();
1063+
if (queuedFilePaths.add(filePath)) {
1064+
downloadsBuilder.add(downloadFile(action, file));
1065+
}
10581066
}
10591067
}
10601068
} else {

src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java

+35
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,41 @@ public void downloadOutputs_nestedOutputDirectories_works() throws Exception {
360360
assertThat(context.isLockOutputFilesCalled()).isTrue();
361361
}
362362

363+
@Test
364+
public void downloadOutputs_outputDirectoriesWithNestedFile_works() throws Exception {
365+
// Test that downloading an output directory containing a named output file works.
366+
367+
// arrange
368+
Digest fooDigest = cache.addContents(remoteActionExecutionContext, "foo-contents");
369+
Digest barDigest = cache.addContents(remoteActionExecutionContext, "bar-ontents");
370+
Tree subdirTreeMessage =
371+
Tree.newBuilder()
372+
.setRoot(
373+
Directory.newBuilder()
374+
.addFiles(FileNode.newBuilder().setName("foo").setDigest(fooDigest))
375+
.addFiles(FileNode.newBuilder().setName("bar").setDigest(barDigest)))
376+
.build();
377+
Digest subdirTreeDigest =
378+
cache.addContents(remoteActionExecutionContext, subdirTreeMessage.toByteArray());
379+
ActionResult.Builder builder = ActionResult.newBuilder();
380+
builder.addOutputFilesBuilder().setPath("outputs/subdir/foo").setDigest(fooDigest);
381+
builder.addOutputDirectoriesBuilder().setPath("outputs/subdir").setTreeDigest(subdirTreeDigest);
382+
RemoteActionResult result =
383+
RemoteActionResult.createFromCache(CachedActionResult.remote(builder.build()));
384+
Spawn spawn = newSpawnFromResult(result);
385+
FakeSpawnExecutionContext context = newSpawnExecutionContext(spawn);
386+
RemoteExecutionService service = newRemoteExecutionService();
387+
RemoteAction action = service.buildRemoteAction(spawn, context);
388+
389+
// act
390+
service.downloadOutputs(action, result);
391+
392+
// assert
393+
assertThat(digestUtil.compute(execRoot.getRelative("outputs/subdir/foo"))).isEqualTo(fooDigest);
394+
assertThat(digestUtil.compute(execRoot.getRelative("outputs/subdir/bar"))).isEqualTo(barDigest);
395+
assertThat(context.isLockOutputFilesCalled()).isTrue();
396+
}
397+
363398
@Test
364399
public void downloadOutputs_outputDirectoriesWithSameHash_works() throws Exception {
365400
// Test that downloading an output directory works when two Directory

0 commit comments

Comments
 (0)