Skip to content
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

WIP: Expand empty tree artifacts to marker file #15371

Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ public PathFragment getExecPath() {
}

/**
* Expands middleman artifacts in a sequence of {@link ActionInput}s.
* Expands middleman and tree artifacts in a sequence of {@link ActionInput}s.
*
* <p>Non-middleman artifacts are returned untouched.
* <p>Non-middleman, non-tree artifacts are returned untouched.
*/
public static List<ActionInput> expandArtifacts(
NestedSet<? extends ActionInput> inputs, ArtifactExpander artifactExpander) {
Expand Down
35 changes: 29 additions & 6 deletions src/main/java/com/google/devtools/build/lib/actions/Artifact.java
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,10 @@ public boolean isChildOfDeclaredDirectory() {
return false;
}

public boolean isEmptyDirectoryMarker() {
return false;
}

/**
* Returns whether the artifact represents a Fileset.
*
Expand Down Expand Up @@ -1292,6 +1296,10 @@ public ArchivedTreeArtifact deserialize(
* </ol>
*/
public static final class TreeFileArtifact extends DerivedArtifact {

private static final PathFragment EMPTY_DIRECTORY_MARKER = PathFragment.createAlreadyNormalized(
"BAZEL_TREE_FILE_ARTIFACT_EMPTY_DIRECTORY_MARKER");

private final SpecialArtifact parent;
private final PathFragment parentRelativePath;

Expand Down Expand Up @@ -1329,6 +1337,10 @@ public static TreeFileArtifact createTreeOutput(
return createTreeOutput(parent, PathFragment.create(parentRelativePath));
}

public static TreeFileArtifact createEmptyDirectoryMarker(SpecialArtifact parent) {
return createTreeOutput(parent, EMPTY_DIRECTORY_MARKER);
}

/**
* Creates a {@link TreeFileArtifact} representing the output of an action generated dynamically
* by an {@link ActionTemplate} during the execution phase.
Expand Down Expand Up @@ -1392,6 +1404,11 @@ public boolean isChildOfDeclaredDirectory() {
return !isActionTemplateExpansionKey(getArtifactOwner());
}

@Override
public boolean isEmptyDirectoryMarker() {
return parentRelativePath == EMPTY_DIRECTORY_MARKER;
}

private static boolean isActionTemplateExpansionKey(ActionLookupKey key) {
return SkyFunctions.ACTION_TEMPLATE_EXPANSION.equals(key.functionName());
}
Expand Down Expand Up @@ -1513,14 +1530,17 @@ public static String joinExecPaths(String delimiter, Iterable<Artifact> artifact
}

/**
* Renders a collection of artifacts as root-relative paths and joins
* them into a single string. Middleman artifacts are ignored by this method.
* Renders a collection of artifacts as root-relative paths and joins them into a single string.
* Middleman artifacts are ignored by this method.
*/
public static String joinRootRelativePaths(String delimiter, Iterable<Artifact> artifacts) {
return Joiner.on(delimiter).join(toRootRelativePaths(artifacts));
}

/** Adds a collection of artifacts to a given collection, with middleman actions expanded once. */
/**
* Adds a collection of artifacts to a given collection, with middleman actions and tree artifacts
* expanded once.
*/
static void addExpandedArtifacts(
Iterable<Artifact> artifacts,
Collection<? super Artifact> output,
Expand All @@ -1529,9 +1549,8 @@ static void addExpandedArtifacts(
}

/**
* Converts a collection of artifacts into the outputs computed by
* outputFormatter and adds them to a given collection. Middleman artifacts
* are expanded once.
* Converts a collection of artifacts into the outputs computed by outputFormatter and adds them
* to a given collection. Middleman artifacts and tree artifacts are expanded once.
*/
private static <E> void addExpandedArtifacts(Iterable<? extends Artifact> artifacts,
Collection<? super E> output,
Expand All @@ -1556,6 +1575,10 @@ private static <E> void expandArtifact(Artifact middleman,
for (Artifact artifact : artifacts) {
output.add(outputFormatter.apply(artifact));
}
if (middleman.isTreeArtifact() && artifacts.isEmpty()) {
output.add(outputFormatter.apply(TreeFileArtifact.createEmptyDirectoryMarker(
(SpecialArtifact) middleman)));
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.google.common.hash.HashCode;
import com.google.devtools.build.lib.actions.ActionContext;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.FileArtifactValue;
import com.google.devtools.build.lib.actions.MetadataProvider;
Expand Down Expand Up @@ -101,6 +102,9 @@ public void logSpawn(
if (input instanceof VirtualActionInput.EmptyActionInput) {
continue;
}
if (input instanceof Artifact && ((Artifact) input).isEmptyDirectoryMarker()) {
continue;
}
Path inputPath = execRoot.getRelative(input.getExecPathString());
if (inputPath.isDirectory()) {
listDirectoryContents(inputPath, builder::addInputs, metadataProvider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,6 @@ private static Spawn createCoveragePostProcessingSpawn(
.addTransitive(action.getInputs())
.addAll(expandedCoverageDir)
.add(action.getCollectCoverageScript())
.add(action.getCoverageDirectoryTreeArtifact())
.add(action.getCoverageManifest())
.addTransitive(action.getLcovMergerFilesToRun().build())
.build(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.google.common.util.concurrent.MoreExecutors;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.FileArtifactValue;
import com.google.devtools.build.lib.actions.MetadataProvider;
import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
Expand Down Expand Up @@ -132,7 +133,7 @@ private Single<TransferResult> downloadOneInput(
SandboxHelpers.atomicallyWriteVirtualInput(
virtualActionInput, outputPath, ".remote");
}
} else {
} else if (!(input instanceof Artifact) || !((Artifact) input).isEmptyDirectoryMarker()) {
FileArtifactValue metadata = metadataProvider.getMetadata(input);
if (metadata != null && metadata.isRemote()) {
Path path = execRoot.getRelative(input.getExecPath());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.common.base.Stopwatch;
import com.google.common.base.Throwables;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.FileArtifactValue;
import com.google.devtools.build.lib.actions.ForbiddenActionInputException;
Expand Down Expand Up @@ -203,6 +204,9 @@ private void checkForConcurrentModifications()
if (input instanceof VirtualActionInput) {
continue;
}
if (input instanceof Artifact && ((Artifact) input).isEmptyDirectoryMarker()) {
continue;
}
FileArtifactValue metadata = context.getMetadataProvider().getMetadata(input);
Path path = execRoot.getRelative(input.getExecPath());
if (metadata.wasModifiedSinceDigest(path)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.ListeningScheduledExecutorService;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.CommandLines.ParamFileActionInput;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.ForbiddenActionInputException;
Expand Down Expand Up @@ -543,6 +544,9 @@ private Map<Path, Long> getInputCtimes(SortedMap<PathFragment, ActionInput> inpu
if (input instanceof VirtualActionInput) {
continue;
}
if (input instanceof Artifact && ((Artifact) input).isEmptyDirectoryMarker()) {
continue;
}
Path path = execRoot.getRelative(input.getExecPathString());
try {
ctimes.put(path, path.stat().getLastChangeTime());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/actions:file_metadata",
"//src/main/java/com/google/devtools/build/lib/profiler",
"//src/main/java/com/google/devtools/build/lib/remote/util",
"//src/main/java/com/google/devtools/build/lib/skyframe:tree_artifact_value",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
"//third_party:guava",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.google.common.base.Preconditions;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.ActionInputHelper;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.FileArtifactValue;
import com.google.devtools.build.lib.actions.MetadataProvider;
import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
Expand Down Expand Up @@ -133,6 +134,8 @@ private static int buildFromActionInputs(
FileNode.createExecutable(
path.getBaseName(), virtualActionInput.getBytes(), d));
return childAdded ? 1 : 0;
} else if (input instanceof Artifact && ((Artifact) input).isEmptyDirectoryMarker()) {
return 0;
}

FileArtifactValue metadata =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ private static MerkleTree build(DirectoryTree tree, DigestUtil digestUtil) {
for (DirectoryTree.DirectoryNode dir : dirs) {
PathFragment subDirname = dirname.getRelative(dir.getPathSegment());
MerkleTree subMerkleTree =
Preconditions.checkNotNull(m.remove(subDirname), "subMerkleTree was null");
Preconditions.checkNotNull(m.remove(subDirname), "subMerkleTree at '%s' was null",
subDirname);
subDirs.put(dir.getPathSegment(), subMerkleTree);
}
MerkleTree mt = buildMerkleTree(new TreeSet<>(files), subDirs, digestUtil);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,6 @@ protected SandboxedSpawn prepareSpawn(Spawn spawn, SpawnExecutionContext context
SandboxInputs inputs =
helpers.processInputFiles(
context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
spawn,
context.getArtifactExpander(),
execRoot);
SandboxOutputs outputs = helpers.getOutputs(spawn);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,6 @@ protected SandboxedSpawn prepareSpawn(Spawn spawn, SpawnExecutionContext context
SandboxInputs inputs =
helpers.processInputFiles(
context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
spawn,
context.getArtifactExpander(),
execRoot);
SandboxOutputs outputs = helpers.getOutputs(spawn);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.common.collect.Maps;
import com.google.common.io.ByteStreams;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.ExecutionRequirements;
import com.google.devtools.build.lib.actions.FileArtifactValue;
Expand Down Expand Up @@ -184,8 +185,6 @@ protected SandboxedSpawn prepareSpawn(Spawn spawn, SpawnExecutionContext context
SandboxInputs inputs =
helpers.processInputFiles(
context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
spawn,
context.getArtifactExpander(),
execRoot);
SandboxOutputs outputs = helpers.getOutputs(spawn);

Expand Down Expand Up @@ -389,6 +388,9 @@ private void checkForConcurrentModifications(SpawnExecutionContext context)
if (input instanceof VirtualActionInput) {
continue;
}
if (input instanceof Artifact && ((Artifact) input).isEmptyDirectoryMarker()) {
continue;
}

FileArtifactValue metadata = context.getMetadataProvider().getMetadata(input);
Path path = execRoot.getRelative(input.getExecPath());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,6 @@ protected SandboxedSpawn prepareSpawn(Spawn spawn, SpawnExecutionContext context
SandboxInputs inputs =
helpers.processInputFiles(
context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
spawn,
context.getArtifactExpander(),
execRoot);
SandboxOutputs outputs = helpers.getOutputs(spawn);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import com.google.common.flogger.GoogleLogger;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander;
import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
import com.google.devtools.build.lib.actions.cache.VirtualActionInput.EmptyActionInput;
Expand All @@ -42,10 +41,8 @@
import com.google.devtools.common.options.OptionsParsingResult;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -487,27 +484,8 @@ private static void writeVirtualInputTo(VirtualActionInput input, Path target)
*/
public SandboxInputs processInputFiles(
Map<PathFragment, ActionInput> inputMap,
Spawn spawn,
ArtifactExpander artifactExpander,
Path execRoot)
throws IOException {
// SpawnInputExpander#getInputMapping uses ArtifactExpander#expandArtifacts to expand
// middlemen and tree artifacts, which expands empty tree artifacts to no entry. However,
// actions that accept TreeArtifacts as inputs generally expect that the empty directory is
// created. So we add those explicitly here.
// TODO(ulfjack): Move this code to SpawnInputExpander.
for (ActionInput input : spawn.getInputFiles().toList()) {
if (input instanceof Artifact && ((Artifact) input).isTreeArtifact()) {
List<Artifact> containedArtifacts = new ArrayList<>();
artifactExpander.expand((Artifact) input, containedArtifacts);
// Attempting to mount a non-empty directory results in ERR_DIRECTORY_NOT_EMPTY, so we
// only mount empty TreeArtifacts as directories.
if (containedArtifacts.isEmpty()) {
inputMap.put(input.getExecPath(), input);
}
}
}

Map<PathFragment, Path> inputFiles = new TreeMap<>();
Set<VirtualActionInput> virtualInputs = new HashSet<>();
Map<PathFragment, PathFragment> inputSymlinks = new TreeMap<>();
Expand All @@ -516,6 +494,10 @@ public SandboxInputs processInputFiles(
PathFragment pathFragment = e.getKey();
ActionInput actionInput = e.getValue();

if (actionInput instanceof Artifact && ((Artifact) actionInput).isEmptyDirectoryMarker()) {
continue;
}

// TODO(b/150963503): Make delayVirtualInputMaterialization the default and remove the
// alternate code path.
if (delayVirtualInputMaterialization) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ protected SandboxedSpawn prepareSpawn(Spawn spawn, SpawnExecutionContext context
SandboxInputs readablePaths =
helpers.processInputFiles(
context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
spawn,
context.getArtifactExpander(),
execRoot);

readablePaths.materializeVirtualInputs(execRoot);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,6 @@ public SpawnResult exec(Spawn spawn, SpawnExecutionContext context)
inputFiles =
helpers.processInputFiles(
context.getInputMapping(PathFragment.EMPTY_FRAGMENT),
spawn,
context.getArtifactExpander(),
execRoot);
}
SandboxOutputs outputs = helpers.getOutputs(spawn);
Expand Down
Loading