Optimize memory usage of `RegularFileValue`... by removing it.
`RegularFileValue` (i.e. the path's real path is itself, and it's an existing file) is the common case situation for `FileValue`. In this situation we don't actually need to spend shallow heap to store a reference to the original `RootedPath` in order to service `FileValue#realRootedPath` and `FileValue#logicalChainDuringResolution`; instead we refactor all callers to pass in the original `RootedPath`. After making this change we notice that `RegularFileValue` is now just a wrapper around `FileStateValue`, so then we remove the need for the wrapper by turning `RegularFileValue` into an abstract class (an interface would also work), and then having `FileStateValue` extend it.
PiperOrigin-RevId: 655774211
Change-Id: Icf1684c85c605a267a85c7917bb53dffaeb85fd7
diff --git a/src/main/java/com/google/devtools/build/lib/actions/FileStateValue.java b/src/main/java/com/google/devtools/build/lib/actions/FileStateValue.java
index 245e9ed..dea15d0 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/FileStateValue.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/FileStateValue.java
@@ -19,6 +19,7 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
+import com.google.devtools.build.lib.actions.FileValue.RegularFileValue;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.io.InconsistentFilesystemException;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant;
@@ -34,7 +35,6 @@
import com.google.devtools.build.lib.vfs.Symlinks;
import com.google.devtools.build.lib.vfs.SyscallCache;
import com.google.devtools.build.lib.vfs.XattrProvider;
-import com.google.devtools.build.skyframe.SkyValue;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
@@ -57,9 +57,14 @@
* com.google.devtools.build.lib.skyframe.FileFunction}. Instead, {@link FileValue} should be used
* by {@link com.google.devtools.build.skyframe.SkyFunction} consumers that care about files.
*
+ * <p>The common case for {@link FileValue} is {@link RegularFileValue} (i.e. the path's real path
+ * is itself, and it's an existing file). As a memory optimization for this common case, we have
+ * {@link FileStateValue} be a {@link RegularFileValue} so that we don't need a wrapper object for
+ * the value of the corresponding {@link FileValue} node.
+ *
* <p>All subclasses must implement {@link #equals} and {@link #hashCode} properly.
*/
-public abstract class FileStateValue implements HasDigest, SkyValue {
+public abstract class FileStateValue extends RegularFileValue implements HasDigest {
@SerializationConstant
public static final DirectoryFileStateValue DIRECTORY_FILE_STATE_NODE =
new DirectoryFileStateValue();
@@ -205,6 +210,11 @@
return rootedPath;
}
+ @Override
+ public FileStateValue realFileStateValue() {
+ return this;
+ }
+
public abstract FileStateType getType();
/** Returns the target of the symlink, or throws an exception if this is not a symlink. */
@@ -212,7 +222,8 @@
throw new IllegalStateException();
}
- long getSize() {
+ @Override
+ public long getSize() {
throw new IllegalStateException();
}
@@ -404,7 +415,7 @@
}
@Override
- long getSize() {
+ public long getSize() {
return 0;
}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/FileValue.java b/src/main/java/com/google/devtools/build/lib/actions/FileValue.java
index a1a5253..698c062 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/FileValue.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/FileValue.java
@@ -41,26 +41,26 @@
* File values for missing files will be created on purpose in order to facilitate incremental
* builds in the case those files have reappeared.
*
- * <p>This class contains the relevant metadata for a file, although not the contents. Note that
- * since a FileValue doesn't store its corresponding SkyKey, it's possible for the FileValues for
- * two different paths to be the same.
+ * <p>This interface encapsulates the relevant metadata for a file, although not the contents. Note
+ * that since a FileValue doesn't necessarily store its corresponding SkyKey, it's possible for the
+ * FileValues for two different paths to be the same.
*
* <p>This should not be used for build outputs; use {@link ArtifactSkyKey} to create keys for
* those.
*/
@Immutable
@ThreadSafe
-public abstract class FileValue implements SkyValue {
+public interface FileValue extends SkyValue {
// Depends non-hermetically on package path, but that is under the control of a flag, so use
// semi-hermetic.
public static final SkyFunctionName FILE = SkyFunctionName.createSemiHermetic("FILE");
- public boolean exists() {
+ default boolean exists() {
return realFileStateValue().getType() != FileStateType.NONEXISTENT;
}
/** Returns true if the original path is a symlink; the target path can never be a symlink. */
- public boolean isSymlink() {
+ default boolean isSymlink() {
return false;
}
@@ -68,7 +68,7 @@
* Returns true if this value corresponds to a file or symlink to an existing regular or special
* file. If so, its parent directory is guaranteed to exist.
*/
- public boolean isFile() {
+ default boolean isFile() {
return realFileStateValue().getType() == FileStateType.REGULAR_FILE
|| realFileStateValue().getType() == FileStateType.SPECIAL_FILE;
}
@@ -77,7 +77,7 @@
* Returns true if this value corresponds to a special file or symlink to a special file. If so,
* its parent directory is guaranteed to exist.
*/
- public boolean isSpecialFile() {
+ default boolean isSpecialFile() {
return realFileStateValue().getType() == FileStateType.SPECIAL_FILE;
}
@@ -85,7 +85,7 @@
* Returns true if the file is a directory or a symlink to an existing directory. If so, its
* parent directory is guaranteed to exist.
*/
- public boolean isDirectory() {
+ default boolean isDirectory() {
return realFileStateValue().getType() == FileStateType.DIRECTORY;
}
@@ -99,28 +99,28 @@
* -- this information is only needed for resolving ancestors, and an existing file or a
* non-existent directory has no descendants, by definition.
*/
- public abstract ImmutableList<RootedPath> logicalChainDuringResolution();
+ ImmutableList<RootedPath> logicalChainDuringResolution(RootedPath initialRootedPath);
/**
* If a symlink pointing back to its own ancestor was encountered during the resolution of this
* {@link FileValue}, returns the path to it. Otherwise, returns null.
*/
- public abstract ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain();
+ ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain();
/**
* If a symlink pointing back to its own ancestor was encountered during the resolution of this
* {@link FileValue}, returns the symlinks in the cycle. Otherwise, returns null.
*/
- public abstract ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain();
+ ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain();
/**
* Returns the real rooted path of the file, taking ancestor symlinks into account. For example,
* the rooted path ['root']/['a/b'] is really ['root']/['c/b'] if 'a' is a symlink to 'c'. Note
* that ancestor symlinks outside the root boundary are not taken into consideration.
*/
- public abstract RootedPath realRootedPath();
+ RootedPath realRootedPath(RootedPath initialRootedPath);
- public abstract FileStateValue realFileStateValue();
+ FileStateValue realFileStateValue();
/**
* Returns the unresolved link target if {@link #isSymlink()}.
@@ -129,31 +129,31 @@
* example could be a build rule that copies a set of input files to the output directory, but
* upon encountering symbolic links it can decide between copying or following them.
*/
- public PathFragment getUnresolvedLinkTarget() {
+ default PathFragment getUnresolvedLinkTarget() {
throw new IllegalStateException(this.toString());
}
- public long getSize() {
+ default long getSize() {
Preconditions.checkState(isFile(), this);
return realFileStateValue().getSize();
}
@Nullable
- public byte[] getDigest() {
+ default byte[] getDigest() {
Preconditions.checkState(isFile(), this);
return realFileStateValue().getDigest();
}
/** Returns a key for building a file value for the given root-relative path. */
@ThreadSafe
- public static Key key(RootedPath rootedPath) {
+ static Key key(RootedPath rootedPath) {
return Key.create(rootedPath);
}
/** Key type for FileValue. */
@VisibleForSerialization
@AutoCodec
- public static class Key extends AbstractSkyKey<RootedPath> {
+ class Key extends AbstractSkyKey<RootedPath> {
private static final SkyKeyInterner<Key> interner = SkyKey.newInterner();
private Key(RootedPath arg) {
@@ -185,7 +185,7 @@
* Only intended to be used by {@link com.google.devtools.build.lib.skyframe.FileFunction}. Should
* not be used for symlink cycles.
*/
- public static FileValue value(
+ static FileValue value(
ImmutableList<RootedPath> logicalChainDuringResolution,
ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain,
ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain,
@@ -209,7 +209,7 @@
"logicalChainDuringResolution: %s, originalRootedPath: %s",
logicalChainDuringResolution,
originalRootedPath);
- return new RegularFileValue(originalRootedPath, fileStateValueFromAncestors);
+ return fileStateValueFromAncestors;
}
boolean shouldStoreChain =
@@ -253,25 +253,14 @@
}
/**
- * Implementation of {@link FileValue} for paths whose fully resolved path is the same as the
- * requested path. For example, this is the case for the path "foo/bar/baz" if neither 'foo' nor
- * 'foo/bar' nor 'foo/bar/baz' are symlinks.
+ * A {@link FileValue} for paths whose fully resolved path is the same as the requested path. For
+ * example, this is the case for the path "foo/bar/baz" if neither 'foo' nor 'foo/bar' nor
+ * 'foo/bar/baz' are symlinks.
*/
- @VisibleForTesting
- public static final class RegularFileValue extends FileValue {
-
- private final RootedPath rootedPath;
- private final FileStateValue fileStateValue;
-
- @VisibleForTesting
- public RegularFileValue(RootedPath rootedPath, FileStateValue fileStateValue) {
- this.rootedPath = Preconditions.checkNotNull(rootedPath);
- this.fileStateValue = Preconditions.checkNotNull(fileStateValue);
- }
-
+ abstract class RegularFileValue implements FileValue {
@Override
- public ImmutableList<RootedPath> logicalChainDuringResolution() {
- return ImmutableList.of(rootedPath);
+ public ImmutableList<RootedPath> logicalChainDuringResolution(RootedPath initialRootedPath) {
+ return ImmutableList.of(initialRootedPath);
}
@Nullable
@@ -287,34 +276,8 @@
}
@Override
- public RootedPath realRootedPath() {
- return rootedPath;
- }
-
- @Override
- public FileStateValue realFileStateValue() {
- return fileStateValue;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (!(obj instanceof RegularFileValue other)) {
- return false;
- }
- return rootedPath.equals(other.rootedPath) && fileStateValue.equals(other.fileStateValue);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(rootedPath, fileStateValue);
- }
-
- @Override
- public String toString() {
- return String.format("non-symlink (path=%s, state=%s)", rootedPath, fileStateValue);
+ public RootedPath realRootedPath(RootedPath initialRootedPath) {
+ return initialRootedPath;
}
}
@@ -323,8 +286,7 @@
* required traversing a symlink chain caused by a symlink pointing to its own ancestor but which
* eventually points to a real file.
*/
- @VisibleForTesting
- public static class DifferentRealPathFileValueWithUnboundedAncestorExpansion
+ class DifferentRealPathFileValueWithUnboundedAncestorExpansion
extends DifferentRealPathFileValueWithStoredChain {
protected final ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain;
protected final ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain;
@@ -401,7 +363,7 @@
* path "foo/bar/baz" if at least one of {'foo', 'foo/bar'} is a symlink but 'foo/bar/baz' not.
*/
@VisibleForTesting
- public static class DifferentRealPathFileValueWithStoredChain extends FileValue {
+ class DifferentRealPathFileValueWithStoredChain implements FileValue {
protected final RootedPath realRootedPath;
protected final FileStateValue realFileStateValue;
protected final ImmutableList<RootedPath> logicalChainDuringResolution;
@@ -417,7 +379,7 @@
}
@Override
- public RootedPath realRootedPath() {
+ public RootedPath realRootedPath(RootedPath initialRootedPath) {
return realRootedPath;
}
@@ -427,7 +389,7 @@
}
@Override
- public ImmutableList<RootedPath> logicalChainDuringResolution() {
+ public ImmutableList<RootedPath> logicalChainDuringResolution(RootedPath initialRootedPath) {
return logicalChainDuringResolution;
}
@@ -475,7 +437,7 @@
* #logicalChainDuringResolution}.
*/
@VisibleForTesting
- public static class DifferentRealPathFileValueWithoutStoredChain extends FileValue {
+ class DifferentRealPathFileValueWithoutStoredChain implements FileValue {
protected final RootedPath realRootedPath;
protected final FileStateValue realFileStateValue;
@@ -487,7 +449,7 @@
}
@Override
- public RootedPath realRootedPath() {
+ public RootedPath realRootedPath(RootedPath initialRootedPath) {
return realRootedPath;
}
@@ -497,7 +459,7 @@
}
@Override
- public ImmutableList<RootedPath> logicalChainDuringResolution() {
+ public ImmutableList<RootedPath> logicalChainDuringResolution(RootedPath initialRootedPath) {
throw new IllegalStateException(this.toString());
}
@@ -543,7 +505,7 @@
* by a symlink pointing to its own ancestor and which eventually points to a symlink.
*/
@VisibleForTesting
- public static final class SymlinkFileValueWithUnboundedAncestorExpansion
+ final class SymlinkFileValueWithUnboundedAncestorExpansion
extends SymlinkFileValueWithStoredChain {
private final ImmutableList<RootedPath> pathToUnboundedAncestorSymlinkExpansionChain;
private final ImmutableList<RootedPath> unboundedAncestorSymlinkExpansionChain;
@@ -620,8 +582,7 @@
/** Implementation of {@link FileValue} for paths that are themselves symlinks. */
@VisibleForTesting
- public static class SymlinkFileValueWithStoredChain
- extends DifferentRealPathFileValueWithStoredChain {
+ class SymlinkFileValueWithStoredChain extends DifferentRealPathFileValueWithStoredChain {
protected final PathFragment linkTarget;
@VisibleForTesting
@@ -677,7 +638,7 @@
* #logicalChainDuringResolution}.
*/
@VisibleForTesting
- public static final class SymlinkFileValueWithoutStoredChain
+ final class SymlinkFileValueWithoutStoredChain
extends DifferentRealPathFileValueWithoutStoredChain {
private final PathFragment linkTarget;
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/starlark/StarlarkBaseExternalContext.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/starlark/StarlarkBaseExternalContext.java
index 6e85a9e..8d2a0a3 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/starlark/StarlarkBaseExternalContext.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/starlark/StarlarkBaseExternalContext.java
@@ -1486,16 +1486,17 @@
if (repoCacheFriendlyPath == null) {
return;
}
+ var recordedInput = new RepoRecordedInput.File(repoCacheFriendlyPath);
+ var skyKey = recordedInput.getSkyKey(directories);
try {
- var recordedInput = new RepoRecordedInput.File(repoCacheFriendlyPath);
- FileValue fileValue =
- (FileValue) env.getValueOrThrow(recordedInput.getSkyKey(directories), IOException.class);
+ FileValue fileValue = (FileValue) env.getValueOrThrow(skyKey, IOException.class);
if (fileValue == null) {
throw new NeedsSkyframeRestartException();
}
recordedFileInputs.put(
- recordedInput, RepoRecordedInput.File.fileValueToMarkerValue(fileValue));
+ recordedInput,
+ RepoRecordedInput.File.fileValueToMarkerValue((RootedPath) skyKey.argument(), fileValue));
} catch (IOException e) {
throw new RepositoryFunctionException(e, Transience.TRANSIENT);
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/BUILD b/src/main/java/com/google/devtools/build/lib/rules/BUILD
index 62bbe82..a6a3363 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/rules/BUILD
@@ -346,6 +346,7 @@
"//src/main/java/com/google/devtools/build/lib/packages",
"//src/main/java/com/google/devtools/build/lib/skyframe:package_lookup_function",
"//src/main/java/com/google/devtools/build/lib/skyframe:package_lookup_value",
+ "//src/main/java/com/google/devtools/build/lib/util:pair",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
"//src/main/java/net/starlark/java/eval",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java b/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java
index aad74b6..1ed1b3b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java
@@ -22,6 +22,7 @@
import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
import com.google.devtools.build.lib.skyframe.PackageLookupFunction;
import com.google.devtools.build.lib.skyframe.PackageLookupValue;
+import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.lib.vfs.RootedPath;
@@ -74,6 +75,7 @@
private abstract static class BaseFileHandler {
private final String filename;
+ private RootedPath rootedPath;
private FileValue fileValue;
private String fileContent;
@@ -112,7 +114,9 @@
Transience.PERSISTENT);
} else if (hasFile) {
- fileValue = getFileValue(rule, env);
+ Pair<RootedPath, FileValue> rootedPathAndFileValue = getFileValue(rule, env);
+ rootedPath = rootedPathAndFileValue.getFirst();
+ fileValue = rootedPathAndFileValue.getSecond();
if (env.valuesMissing()) {
return false;
}
@@ -145,14 +149,14 @@
throws RepositoryFunctionException {
if (fileValue != null) {
// Link x/FILENAME to <build_root>/x.FILENAME.
- symlinkFile(fileValue, filename, outputDirectory);
+ symlinkFile(rootedPath, fileValue, filename, outputDirectory);
try {
Label label = getFileAttributeAsLabel(rule);
recordedInputValues.put(
new RepoRecordedInput.File(
RepoRecordedInput.RepoCacheFriendlyPath.createInsideWorkspace(
label.getRepository(), label.toPathFragment())),
- RepoRecordedInput.File.fileValueToMarkerValue(fileValue));
+ RepoRecordedInput.File.fileValueToMarkerValue(rootedPath, fileValue));
} catch (IOException e) {
throw new RepositoryFunctionException(e, Transience.TRANSIENT);
}
@@ -172,7 +176,7 @@
}
@Nullable
- private FileValue getFileValue(Rule rule, Environment env)
+ private Pair<RootedPath, FileValue> getFileValue(Rule rule, Environment env)
throws RepositoryFunctionException, InterruptedException {
Label label = getFileAttributeAsLabel(rule);
SkyKey pkgSkyKey = PackageLookupValue.key(label.getPackageIdentifier());
@@ -223,20 +227,23 @@
Transience.PERSISTENT);
}
- return fileValue;
+ return Pair.of(rootedFile, fileValue);
}
/**
* Symlinks a file from the local filesystem into the external repository's root.
*
+ * @param rootedPath {@link RootedPath} of the file to be linked in
* @param fileValue {@link FileValue} representing the file to be linked in
* @param outputDirectory the directory of the remote repository
* @throws RepositoryFunctionException if the file specified does not exist or cannot be linked.
*/
- private static void symlinkFile(FileValue fileValue, String filename, Path outputDirectory)
+ private static void symlinkFile(
+ RootedPath rootedPath, FileValue fileValue, String filename, Path outputDirectory)
throws RepositoryFunctionException {
Path filePath = outputDirectory.getRelative(filename);
- RepositoryFunction.createSymbolicLink(filePath, fileValue.realRootedPath().asPath());
+ RepositoryFunction.createSymbolicLink(
+ filePath, fileValue.realRootedPath(rootedPath).asPath());
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepoRecordedInput.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepoRecordedInput.java
index 8da9d50..7dc9bde 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepoRecordedInput.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepoRecordedInput.java
@@ -305,7 +305,8 @@
* for placing in a repository marker file. The file need not exist, and can be a file or a
* directory.
*/
- public static String fileValueToMarkerValue(FileValue fileValue) throws IOException {
+ public static String fileValueToMarkerValue(RootedPath rootedPath, FileValue fileValue)
+ throws IOException {
if (fileValue.isDirectory()) {
return "DIR";
}
@@ -316,7 +317,7 @@
byte[] digest = fileValue.realFileStateValue().getDigest();
if (digest == null) {
// Fast digest not available, or it would have been in the FileValue.
- digest = fileValue.realRootedPath().asPath().getDigest();
+ digest = fileValue.realRootedPath(rootedPath).asPath().getDigest();
}
return BaseEncoding.base16().lowerCase().encode(digest);
}
@@ -331,13 +332,13 @@
public boolean isUpToDate(
Environment env, BlazeDirectories directories, @Nullable String oldValue)
throws InterruptedException {
+ var skyKey = getSkyKey(directories);
try {
- FileValue fileValue =
- (FileValue) env.getValueOrThrow(getSkyKey(directories), IOException.class);
+ FileValue fileValue = (FileValue) env.getValueOrThrow(skyKey, IOException.class);
if (fileValue == null) {
return false;
}
- return oldValue.equals(fileValueToMarkerValue(fileValue));
+ return oldValue.equals(fileValueToMarkerValue((RootedPath) skyKey.argument(), fileValue));
} catch (IOException e) {
return false;
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingFunction.java
index eb01dcd..b31c0fa 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingFunction.java
@@ -38,7 +38,7 @@
return null;
}
- RootedPath realDirRootedPath = dirFileValue.realRootedPath();
+ RootedPath realDirRootedPath = dirFileValue.realRootedPath(dirRootedPath);
if (!dirFileValue.isDirectory()) {
// Recall that the directory is assumed to exist (see DirectoryListingValue#key).
throw new DirectoryListingFunctionException(new InconsistentFilesystemException(
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java
index d9e9f91..02da3e5 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryListingValue.java
@@ -95,10 +95,11 @@
static DirectoryListingValue value(RootedPath dirRootedPath, FileValue dirFileValue,
DirectoryListingStateValue realDirectoryListingStateValue) {
- return dirFileValue.realRootedPath().equals(dirRootedPath)
+ RootedPath realRootedPath = dirFileValue.realRootedPath(dirRootedPath);
+ return realRootedPath.equals(dirRootedPath)
? new RegularDirectoryListingValue(realDirectoryListingStateValue)
- : new DifferentRealPathDirectoryListingValue(dirFileValue.realRootedPath(),
- realDirectoryListingStateValue);
+ : new DifferentRealPathDirectoryListingValue(
+ realRootedPath, realDirectoryListingStateValue);
}
/** Normal {@link DirectoryListingValue}. */
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryTreeDigestFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryTreeDigestFunction.java
index ae23c37..80ad4ab 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryTreeDigestFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/DirectoryTreeDigestFunction.java
@@ -20,6 +20,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.FileValue;
import com.google.devtools.build.lib.util.Fingerprint;
+import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.Dirent;
import com.google.devtools.build.lib.vfs.RootedPath;
import com.google.devtools.build.skyframe.SkyFunction;
@@ -53,7 +54,8 @@
.collect(toImmutableSet());
// Turn each entry into a FileValue.
- ImmutableList<FileValue> fileValues = getFileValues(env, sortedDirents, rootedPath);
+ ImmutableList<Pair<RootedPath, FileValue>> fileValues =
+ getFileValues(env, sortedDirents, rootedPath);
if (fileValues == null) {
return null;
}
@@ -70,13 +72,15 @@
fp.addStrings(sortedDirents);
fp.addStrings(subDirTreeDigests);
try {
- for (FileValue fileValue : fileValues) {
+ for (Pair<RootedPath, FileValue> rootedPathAndFileValue : fileValues) {
+ RootedPath direntRootedPath = rootedPathAndFileValue.getFirst();
+ FileValue fileValue = rootedPathAndFileValue.getSecond();
fp.addInt(fileValue.realFileStateValue().getType().ordinal());
if (fileValue.isFile()) {
byte[] digest = fileValue.realFileStateValue().getDigest();
if (digest == null) {
// Fast digest not available, or it would have been in the FileValue.
- digest = fileValue.realRootedPath().asPath().getDigest();
+ digest = fileValue.realRootedPath(direntRootedPath).asPath().getDigest();
}
fp.addBytes(digest);
}
@@ -89,7 +93,7 @@
}
@Nullable
- private static ImmutableList<FileValue> getFileValues(
+ private static ImmutableList<Pair<RootedPath, FileValue>> getFileValues(
Environment env, ImmutableSet<String> sortedDirents, RootedPath rootedPath)
throws InterruptedException {
ImmutableSet<FileValue.Key> fileValueKeys =
@@ -105,10 +109,9 @@
if (env.valuesMissing()) {
return null;
}
- ImmutableList<FileValue> fileValues =
+ ImmutableList<Pair<RootedPath, FileValue>> fileValues =
fileValueKeys.stream()
- .map(result::get)
- .map(FileValue.class::cast)
+ .map(k -> Pair.of((RootedPath) k.argument(), (FileValue) result.get(k)))
.collect(toImmutableList());
if (env.valuesMissing()) {
return null;
@@ -118,11 +121,12 @@
@Nullable
private static ImmutableList<String> getSubDirTreeDigests(
- Environment env, ImmutableList<FileValue> fileValues) throws InterruptedException {
+ Environment env, ImmutableList<Pair<RootedPath, FileValue>> fileValues)
+ throws InterruptedException {
ImmutableSet<SkyKey> dirTreeDigestValueKeys =
fileValues.stream()
- .filter(FileValue::isDirectory)
- .map(fv -> DirectoryTreeDigestValue.key(fv.realRootedPath()))
+ .filter(p -> p.getSecond().isDirectory())
+ .map(p -> DirectoryTreeDigestValue.key(p.getSecond().realRootedPath(p.getFirst())))
.collect(toImmutableSet());
SkyframeLookupResult result = env.getValuesAndExceptions(dirTreeDigestValueKeys);
if (env.valuesMissing()) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java
index 4d7d97d..1439311 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileFunction.java
@@ -196,14 +196,19 @@
}
RootedPath rootedPathFromAncestors =
- getChild(parentFileValue.realRootedPath(), baseName, parentRootedPath, rootedPath);
+ getChild(
+ parentFileValue.realRootedPath(parentRootedPath),
+ baseName,
+ parentRootedPath,
+ rootedPath);
if (!parentFileValue.exists() || !parentFileValue.isDirectory()) {
return new PartialResolutionResult(
rootedPathFromAncestors, FileStateValue.NONEXISTENT_FILE_STATE_NODE);
}
- for (RootedPath parentPartialRootedPath : parentFileValue.logicalChainDuringResolution()) {
+ for (RootedPath parentPartialRootedPath :
+ parentFileValue.logicalChainDuringResolution(parentRootedPath)) {
checkAndNotePathSeenDuringPartialResolution(
getChild(parentPartialRootedPath, baseName, parentRootedPath, rootedPath),
symlinkResolutionState,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
index 0151bc0..6aec2b6 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveFilesystemTraversalFunction.java
@@ -386,21 +386,24 @@
}
} else {
// Stat the file.
+ RootedPath rootedPath = traversal.root().asRootedPath();
FileValue fileValue =
- (FileValue)
- env.getValueOrThrow(
- FileValue.key(traversal.root().asRootedPath()), IOException.class);
+ (FileValue) env.getValueOrThrow(FileValue.key(rootedPath), IOException.class);
if (env.valuesMissing()) {
return null;
}
- return toFileInfo(fileValue, env, traversal.root().asPath(), syscallCache);
+ return toFileInfo(rootedPath, fileValue, env, traversal.root().asPath(), syscallCache);
}
}
@Nullable
private static FileInfo toFileInfo(
- FileValue fileValue, Environment env, Path path, SyscallCache syscallCache)
+ RootedPath rootedPath,
+ FileValue fileValue,
+ Environment env,
+ Path path,
+ SyscallCache syscallCache)
throws IOException, InterruptedException {
if (fileValue.unboundedAncestorSymlinkExpansionChain() != null) {
SkyKey uniquenessKey =
@@ -437,7 +440,7 @@
return new FileInfo(
type,
withDigest(fileValue.realFileStateValue(), path, syscallCache),
- fileValue.realRootedPath(),
+ fileValue.realRootedPath(rootedPath),
unresolvedLinkTarget);
}
@@ -715,7 +718,12 @@
}
if (key instanceof FileValue.Key fileKey) {
FileInfo fileInfo =
- toFileInfo((FileValue) value, env, fileKey.argument().asPath(), syscallCache);
+ toFileInfo(
+ fileKey.argument(),
+ (FileValue) value,
+ env,
+ fileKey.argument().asPath(),
+ syscallCache);
if (fileInfo != null) {
childValues.add(resultForFileRoot(fileKey.argument(), fileInfo));
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/config/PlatformMappingFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/config/PlatformMappingFunction.java
index fd7f68a..f27aa6c 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/config/PlatformMappingFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/config/PlatformMappingFunction.java
@@ -111,7 +111,8 @@
List<String> lines;
try {
- lines = FileSystemUtils.readLines(fileValue.realRootedPath().asPath(), UTF_8);
+ lines =
+ FileSystemUtils.readLines(fileValue.realRootedPath(rootedMappingPath).asPath(), UTF_8);
} catch (IOException e) {
throw new PlatformMappingFunctionException(e);
}