-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a flag to force Bazel to download certain artifacts when using --remote_download_minimal #15638
Changes from 1 commit
1cc9731
1fa3b54
1e6ea20
01a26a4
eefb0cd
ecc33b9
4fef106
987d387
fdf3b25
df6de24
73fd192
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -147,6 +147,9 @@ | |
import java.util.concurrent.Executor; | ||
import java.util.concurrent.Phaser; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import java.util.function.Predicate; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import javax.annotation.Nullable; | ||
|
||
/** | ||
|
@@ -174,6 +177,8 @@ public class RemoteExecutionService { | |
|
||
private final AtomicBoolean shutdown = new AtomicBoolean(false); | ||
private final AtomicBoolean buildInterrupted = new AtomicBoolean(false); | ||
private final boolean shouldForceDownloads; | ||
private final Predicate<String> shouldForceDownloadPredicate; | ||
|
||
public RemoteExecutionService( | ||
Executor executor, | ||
|
@@ -215,6 +220,16 @@ public RemoteExecutionService( | |
this.captureCorruptedOutputsDir = captureCorruptedOutputsDir; | ||
|
||
this.scheduler = Schedulers.from(executor, /*interruptibleWorker=*/ true); | ||
|
||
String regex = remoteOptions.experimentalForceDownloadsRegex; | ||
// TODO(bazel-team): Consider adding a warning or more validation if the experimentalForceDownloadsRegex is used | ||
// without RemoteOutputsMode.MINIMAL | ||
this.shouldForceDownloads = !regex.isEmpty() && remoteOptions.remoteOutputsMode == RemoteOutputsMode.MINIMAL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can also use this flag for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
Pattern pattern = Pattern.compile(regex); | ||
this.shouldForceDownloadPredicate = path -> { | ||
Matcher m = pattern.matcher(path); | ||
return m.matches(); | ||
}; | ||
} | ||
|
||
static Command buildCommand( | ||
|
@@ -1021,24 +1036,9 @@ public InMemoryOutput downloadOutputs(RemoteAction action, RemoteActionResult re | |
/* exitCode = */ result.getExitCode(), | ||
hasFilesToDownload(action.getSpawn().getOutputFiles(), filesToDownload)); | ||
|
||
ImmutableList.Builder<ListenableFuture<FileMetadata>> forcedDownloadsBuilder = ImmutableList.builder(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not reuse There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was trying to steer away from the current downloads codepath since I'm not an expert in this part of the code. Wanted to make sure this change is isolated to avoid any potential problems but if you want I can try to unify them using downloadsBuilder. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, please unify them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to unify them in a few ways but I always ended up finding issues and making the code more unreadable. Do you have any suggestions? Since this is experimental I'm inclined to leave it as it is right now and if we can confirm this is a good direction then we can refactor the code to make it more readable (I still find it very confusing the code path that depends on the downloadOutputs boolean) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
As you said this is an experimental feature, I am fine to move forward without unifying them at this PR if that introduce other issues. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I understood that, but some tests are failing when I'm unifying them and it's not entirely clear to me why that's the case. Seems like a bug somewhere where downloadOutputs is not entirely consistent with using BwoB. I'll go ahead as is. |
||
if (downloadOutputs) { | ||
HashSet<PathFragment> queuedFilePaths = new HashSet<>(); | ||
|
||
for (FileMetadata file : metadata.files()) { | ||
PathFragment filePath = file.path().asFragment(); | ||
if (queuedFilePaths.add(filePath)) { | ||
downloadsBuilder.add(downloadFile(action, file)); | ||
} | ||
} | ||
|
||
for (Map.Entry<Path, DirectoryMetadata> entry : metadata.directories()) { | ||
for (FileMetadata file : entry.getValue().files()) { | ||
PathFragment filePath = file.path().asFragment(); | ||
if (queuedFilePaths.add(filePath)) { | ||
downloadsBuilder.add(downloadFile(action, file)); | ||
} | ||
} | ||
} | ||
downloadsBuilder.addAll(buildFilesToDownload(metadata, action)); | ||
} else { | ||
checkState( | ||
result.getExitCode() == 0, | ||
|
@@ -1049,6 +1049,9 @@ public InMemoryOutput downloadOutputs(RemoteAction action, RemoteActionResult re | |
"Symlinks in action outputs are not yet supported by " | ||
+ "--experimental_remote_download_outputs=minimal"); | ||
} | ||
if (shouldForceDownloads) { | ||
forcedDownloadsBuilder.addAll(buildFilesToDownloadWithPredicate(metadata, action, shouldForceDownloadPredicate)); | ||
} | ||
} | ||
|
||
FileOutErr tmpOutErr = outErr.childOutErr(); | ||
|
@@ -1068,6 +1071,15 @@ public InMemoryOutput downloadOutputs(RemoteAction action, RemoteActionResult re | |
throw e; | ||
} | ||
|
||
ImmutableList<ListenableFuture<FileMetadata>> forcedDownloads = forcedDownloadsBuilder.build(); | ||
try (SilentCloseable c = Profiler.instance().profile("Remote.forcedDownload")) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider extracting this into a function to share the code above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @coeuvre unfortunately the generic Exception catch here is making this code very brittle. Exception handling needs to be improved before we can move this to a generic function, I've added a TODO to avoid mixing things up. That was causing the test failures from my previous attempts. |
||
waitForBulkTransfer(forcedDownloads, /* cancelRemainingOnInterrupt= */ true); | ||
} catch (Exception e) { | ||
captureCorruptedOutputs(e); | ||
deletePartialDownloadedOutputs(result, tmpOutErr, e); | ||
throw e; | ||
} | ||
|
||
FileOutErr.dump(tmpOutErr, outErr); | ||
|
||
// Ensure that we are the only ones writing to the output files when using the dynamic spawn | ||
|
@@ -1079,6 +1091,10 @@ public InMemoryOutput downloadOutputs(RemoteAction action, RemoteActionResult re | |
tmpOutErr.clearOut(); | ||
tmpOutErr.clearErr(); | ||
|
||
if (!forcedDownloads.isEmpty()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider moving this into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
moveOutputsToFinalLocation(forcedDownloads); | ||
} | ||
|
||
if (downloadOutputs) { | ||
moveOutputsToFinalLocation(downloads); | ||
|
||
|
@@ -1133,6 +1149,35 @@ public InMemoryOutput downloadOutputs(RemoteAction action, RemoteActionResult re | |
return null; | ||
} | ||
|
||
private ImmutableList<ListenableFuture<FileMetadata>> buildFilesToDownload( | ||
ActionResultMetadata metadata, RemoteAction action) { | ||
Predicate<String> alwaysTrue = unused -> true; | ||
return buildFilesToDownloadWithPredicate(metadata, action, alwaysTrue); | ||
} | ||
|
||
private ImmutableList<ListenableFuture<FileMetadata>> buildFilesToDownloadWithPredicate( | ||
ActionResultMetadata metadata, RemoteAction action, Predicate<String> predicate) { | ||
HashSet<PathFragment> queuedFilePaths = new HashSet<>(); | ||
ImmutableList.Builder<ListenableFuture<FileMetadata>> builder = new ImmutableList.Builder<>(); | ||
for (FileMetadata file : metadata.files()) { | ||
PathFragment filePath = file.path().asFragment(); | ||
if (queuedFilePaths.add(filePath) && predicate.test(file.path.toString())) { | ||
builder.add(downloadFile(action, file)); | ||
} | ||
} | ||
|
||
for (Map.Entry<Path, DirectoryMetadata> entry : metadata.directories()) { | ||
for (FileMetadata file : entry.getValue().files()) { | ||
PathFragment filePath = file.path().asFragment(); | ||
if (queuedFilePaths.add(filePath) && predicate.test(file.path.toString())) { | ||
builder.add(downloadFile(action, file)); | ||
} | ||
} | ||
} | ||
|
||
return builder.build(); | ||
} | ||
|
||
private static String prettyPrint(ActionInput actionInput) { | ||
if (actionInput instanceof Artifact) { | ||
return ((Artifact) actionInput).prettyPrint(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -574,6 +574,16 @@ public RemoteOutputsStrategyConverter() { | |
help = "Maximum number of open files allowed during BEP artifact upload.") | ||
public int maximumOpenFiles; | ||
|
||
@Option( | ||
name = "experimental_force_downloads_regex", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about name this flag There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
defaultValue = "", | ||
documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, | ||
effectTags = {OptionEffectTag.AFFECTS_OUTPUTS}, | ||
help = "Force Bazel to download the artifacts that match the given regexp. To be used in conjunction with" + | ||
"--remote_download_minimal to allow the client to request certain artifacts that might be needed" + | ||
"locally (e.g. IDE support)") | ||
public String experimentalForceDownloadsRegex; | ||
|
||
// The below options are not configurable by users, only tests. | ||
// This is part of the effort to reduce the overall number of flags. | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment needs update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done