Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/java/com/google/devtools/build/lib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/cmdline",
"//src/main/java/com/google/devtools/build/lib/events",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ java_library(
deps = [
"//src/main/java/com/google/devtools/build/docgen/annot",
"//src/main/java/com/google/devtools/build/lib:runtime",
"//src/main/java/com/google/devtools/build/lib:runtime/remote_repo_contents_cache",
"//src/main/java/com/google/devtools/build/lib/actions:file_metadata",
"//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster",
"//src/main/java/com/google/devtools/build/lib/analysis:blaze_directories",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import com.google.devtools.build.lib.rules.repository.RepositoryFunction;
import com.google.devtools.build.lib.rules.repository.WorkspaceFileHelper;
import com.google.devtools.build.lib.runtime.ProcessWrapper;
import com.google.devtools.build.lib.runtime.RemoteRepoContentsCache;
import com.google.devtools.build.lib.runtime.RepositoryRemoteExecutor;
import com.google.devtools.build.lib.skyframe.IgnoredSubdirectoriesValue;
import com.google.devtools.build.lib.skyframe.PrecomputedValue;
Expand Down Expand Up @@ -125,13 +126,20 @@ public void reportSkyframeRestart(Environment env, RepositoryName repoName) {

private static class State extends WorkerSkyKeyComputeState<FetchResult> {
@Nullable FetchResult result;
final RemoteRepoContentsCache.LookupState repoContentsCacheLookupState =
new RemoteRepoContentsCache.LookupState();
}

@Override
public boolean wasJustFetched(Environment env) {
return env.getState(State::new).result != null;
}

@Override
public RemoteRepoContentsCache.LookupState getRemoteRepoContentsCacheLookupState(Environment env) {
return env.getState(State::new).repoContentsCacheLookupState;
}

private record FetchArgs(
Rule rule, Path outputDirectory, BlazeDirectories directories, Environment env, SkyKey key) {
FetchArgs toWorkerArgs(Environment env) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import com.google.devtools.build.lib.actions.FileArtifactValue.RemoteFileArtifactValue;
import com.google.devtools.build.lib.actions.FileArtifactValue.RemoteFileArtifactValueWithMaterializationData;
import com.google.devtools.build.lib.actions.FileContentsProxy;
import com.google.devtools.build.lib.actions.FileStateType;
import com.google.devtools.build.lib.actions.cache.OutputMetadataStore;
import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
import com.google.devtools.build.lib.cmdline.LabelConstants;
Expand Down Expand Up @@ -247,6 +248,17 @@ protected Path execRoot() {
return execRootSupplier.get();
}

/**
* Returns whether the given path lives under the external repository root. Unlike {@link
* #execRoot()}, this can be evaluated during external repository materialization, where the exec
* root isn't available yet.
*/
private boolean isUnderExternalRepoRoot(Path path) {
return path.asFragment()
.startsWith(
outputBase.getRelative(LabelConstants.EXTERNAL_REPOSITORY_LOCATION).asFragment());
}

/**
* Resolves an exec path to an absolute path, avoiding evaluation of execRoot() if possible as it
* isn't available during server startup. This logic is unique to Bazel 8.x as it still names the
Expand Down Expand Up @@ -412,7 +424,19 @@ private ListenableFuture<Void> prefetchFile(
PathFragment execPath = input.getExecPath();

FileArtifactValue metadata = metadataSupplier.getMetadata(input);
if (metadata == null || !canDownloadFile(resolveExecPath(execPath), metadata)) {
if (metadata == null) {
return immediateVoidFuture();
}
Path inputPath = resolveExecPath(execPath);
if (metadata.getType() == FileStateType.SYMLINK && isUnderExternalRepoRoot(inputPath)) {
return toListenableFuture(
plantUnresolvedSymlink(
inputPath.forHostFileSystem(),
PathFragment.create(
((FileArtifactValue.UnresolvedSymlinkArtifactValue) metadata)
.getSymlinkTarget())));
}
if (!canDownloadFile(inputPath, metadata)) {
return immediateVoidFuture();
}

Expand Down Expand Up @@ -752,6 +776,17 @@ private Completable plantSymlink(Symlink symlink) {
forceRefetch(resolveExecPath(symlink.linkExecPath())));
}

private Completable plantUnresolvedSymlink(Path linkPath, PathFragment target) {
return downloadCache.executeIfNot(
linkPath,
Completable.defer(
() -> {
linkPath.delete();
linkPath.createSymbolicLink(target);
return Completable.complete();
}));
}

public ImmutableSet<Path> downloadedFiles() {
return downloadCache.getFinishedTasks();
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/google/devtools/build/lib/remote/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/remote/util",
"//src/main/java/com/google/devtools/build/lib/remote/util:digest_utils",
"//src/main/java/com/google/devtools/build/lib/remote/zstd",
"//src/main/java/com/google/devtools/build/lib/rules:repository/repo_recorded_input",
"//src/main/java/com/google/devtools/build/lib/skyframe:action_execution_value",
"//src/main/java/com/google/devtools/build/lib/skyframe:sky_functions",
"//src/main/java/com/google/devtools/build/lib/skyframe:tree_artifact_value",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,15 @@ public CachedActionResult downloadActionResult(
boolean inlineOutErr,
Set<String> inlineOutputFiles)
throws IOException, InterruptedException {
return getFromFuture(
downloadActionResultAsync(context, actionKey, inlineOutErr, inlineOutputFiles));
}

public ListenableFuture<CachedActionResult> downloadActionResultAsync(
RemoteActionExecutionContext context,
ActionKey actionKey,
boolean inlineOutErr,
Set<String> inlineOutputFiles) {
var spawnExecutionContext = context.getSpawnExecutionContext();

ListenableFuture<CachedActionResult> future = immediateFuture(null);
Expand Down Expand Up @@ -254,7 +263,7 @@ public CachedActionResult downloadActionResult(
directExecutor());
}

return getFromFuture(future);
return future;
}

private ListenableFuture<ActionResult> downloadActionResultFromRemote(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,13 @@ public void afterCommand() {
*/
public boolean injectRemoteRepo(RepositoryName repo, Tree remoteContents, String markerFile)
throws IOException, InterruptedException {
var repoDir = externalDirectory.getChild(repo.getName());
deleteTree(repoDir);
var unused = delete(externalDirectory.getChild(repo.getMarkerFileName()));
var childMap =
remoteContents.getChildrenList().stream()
.collect(
toImmutableMap(cache.digestUtil::compute, directory -> directory, (a, b) -> a));
var repoDir = externalDirectory.getChild(repo.getName());
var filesToPrefetch = new ArrayList<PathFragment>();
injectRecursively(
externalFs,
Expand All @@ -220,7 +222,7 @@ public boolean injectRemoteRepo(RepositoryName repo, Tree remoteContents, String
}
// Create the repo directory on disk so that readdir reflects the overlaid state of the external
// directory.
nativeFs.createDirectoryAndParents(externalDirectory.getChild(repo.getName()));
nativeFs.createDirectoryAndParents(repoDir);
// Keep the marker file contents in memory so that it can be written out when the repo is
// materialized. This doubles as a presence marker for the in-memory repo contents.
markerFileContents.put(repo.getName(), markerFile);
Expand Down Expand Up @@ -313,12 +315,8 @@ private void doMaterialize(RepositoryName repo, ExtendedEventHandler reporter)
}
prefetch(walkResult.files());
// Create symlinks last as some platforms don't allow creating a symlink to a non-existent
// target. A symlink may have already been created as an input to an action.
for (var remoteSymlink : walkResult.symlinks()) {
var nativeSymlink = nativeFs.getPath(remoteSymlink);
FileSystemUtils.ensureSymbolicLink(
nativeSymlink, externalFs.getPath(remoteSymlink).readSymbolicLink());
}
// target.
prefetch(walkResult.symlinks());

// After the repo has been copied, atomically materialize the marker file. This ensures that the
// repo doesn't have to be refetched after the next server restart.
Expand Down Expand Up @@ -654,9 +652,11 @@ private RemoteActionExecutionContext makeRemoteContext(PathFragment relativePath
}

private FileArtifactValue getMetadata(PathFragment path) throws IOException {
var info =
(RemoteActionFileSystem.RemoteInMemoryFileInfo) stat(path, /* followSymlinks= */ true);
return info.getMetadata();
var status = stat(path, /* followSymlinks= */ false);
if (!status.isSymbolicLink()) {
return ((RemoteActionFileSystem.RemoteInMemoryFileInfo) status).getMetadata();
}
return FileArtifactValue.createForUnresolvedSymlink(externalFs.getPath(path));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,7 @@ public void beforeCommand(CommandEnvironment env) throws AbruptExitException {

repositoryRemoteHelpersFactoryDelegate.init(
new RepositoryRemoteHelpersFactoryImpl(
env.getDirectories(),
actionContextProvider.getCombinedCache(),
actionContextProvider.getRemoteExecutionClient(),
buildRequestId,
Expand Down
Loading