Update Fileset with the HasDigest interface.
RELNOTES: None
PiperOrigin-RevId: 257247094
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 14514f5..348fc02 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
@@ -13,6 +13,9 @@
// limitations under the License.
package com.google.devtools.build.lib.skyframe;
+import static com.google.devtools.build.lib.vfs.UnixGlob.DEFAULT_SYSCALLS;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import com.google.common.collect.Collections2;
@@ -20,13 +23,18 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
import com.google.devtools.build.lib.actions.FileArtifactValue;
+import com.google.devtools.build.lib.actions.FileStateType;
+import com.google.devtools.build.lib.actions.FileStateValue;
import com.google.devtools.build.lib.actions.FileValue;
+import com.google.devtools.build.lib.actions.HasDigest;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.ResolvedFile;
import com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.ResolvedFileFactory;
import com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.TraversalRequest;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.Dirent;
import com.google.devtools.build.lib.vfs.FileStatus;
import com.google.devtools.build.lib.vfs.Path;
@@ -36,9 +44,11 @@
import com.google.devtools.build.lib.vfs.Symlinks;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.io.IOException;
+import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -52,6 +62,15 @@
private static final class MissingDepException extends Exception {}
+ private static final byte[] MISSING_FINGERPRINT =
+ new BigInteger(1, "NonexistentFileStateValue".getBytes(UTF_8)).toByteArray();
+
+ @AutoCodec @AutoCodec.VisibleForSerialization
+ static final HasDigest NON_EXISTENT_HAS_DIGEST = () -> MISSING_FINGERPRINT;
+
+ private static final FileInfo NON_EXISTENT_FILE_INFO =
+ new FileInfo(FileType.NONEXISTENT, NON_EXISTENT_HAS_DIGEST, null, null);
+
/** Base class for exceptions that {@link RecursiveFilesystemTraversalFunctionException} wraps. */
public abstract static class RecursiveFilesystemTraversalException extends Exception {
protected RecursiveFilesystemTraversalException(String message) {
@@ -213,15 +232,16 @@
private static final class FileInfo {
final FileType type;
- final Object metadata;
+ final HasDigest metadata;
@Nullable final RootedPath realPath;
@Nullable final PathFragment unresolvedSymlinkTarget;
FileInfo(
FileType type,
- Object metadata,
+ HasDigest metadata,
@Nullable RootedPath realPath,
@Nullable PathFragment unresolvedSymlinkTarget) {
+ Preconditions.checkNotNull(metadata.getDigest(), metadata);
this.type = Preconditions.checkNotNull(type);
this.metadata = metadata;
this.realPath = realPath;
@@ -239,13 +259,10 @@
}
}
- private static final FileInfo NON_EXISTENT_FILE_INFO =
- new FileInfo(FileType.NONEXISTENT, new Integer(0), null, null);
-
private static FileInfo lookUpFileInfo(Environment env, TraversalRequest traversal)
throws MissingDepException, IOException, InterruptedException {
if (traversal.isRootGenerated) {
- SkyValue fsVal = null;
+ HasDigest fsVal = null;
if (traversal.root.getOutputArtifact() != null) {
Artifact artifact = traversal.root.getOutputArtifact();
SkyKey artifactKey = Artifact.key(artifact);
@@ -254,10 +271,8 @@
throw new MissingDepException();
}
- if (value instanceof FileArtifactValue) {
- fsVal = value;
- } else if (value instanceof TreeArtifactValue) {
- fsVal = value;
+ if (value instanceof FileArtifactValue || value instanceof TreeArtifactValue) {
+ fsVal = (HasDigest) value;
} else if (value instanceof ActionExecutionValue) {
fsVal =
Preconditions.checkNotNull(
@@ -277,19 +292,23 @@
// FileArtifactValue does not currently track symlinks. If it did, we could potentially
// remove some of the filesystem operations we're doing here.
Path path = traversal.root.asRootedPath().asPath();
- FileStatus noFollowStat = path.stat(Symlinks.NOFOLLOW);
+ FileStateValue fileState =
+ FileStateValue.create(traversal.root.asRootedPath(), DEFAULT_SYSCALLS, null);
+ if (fileState.getType() == FileStateType.NONEXISTENT) {
+ throw new IOException("Missing file: " + path);
+ }
FileStatus followStat = path.statIfFound(Symlinks.FOLLOW);
FileType type;
PathFragment unresolvedLinkTarget = null;
if (followStat == null) {
type = FileType.DANGLING_SYMLINK;
- if (!noFollowStat.isSymbolicLink()) {
- throw new IOException("Expected symlink for " + path + ", but got: " + noFollowStat);
+ if (fileState.getType() != FileStateType.SYMLINK) {
+ throw new IOException("Expected symlink for " + path + ", but got: " + fileState);
}
unresolvedLinkTarget = path.readSymbolicLink();
- } else if (noFollowStat.isFile()) {
+ } else if (fileState.getType() == FileStateType.REGULAR_FILE) {
type = FileType.FILE;
- } else if (noFollowStat.isDirectory()) {
+ } else if (fileState.getType() == FileStateType.DIRECTORY) {
type = FileType.DIRECTORY;
} else {
unresolvedLinkTarget = path.readSymbolicLink();
@@ -298,8 +317,10 @@
Root.absoluteRoot(path.getFileSystem()), path.resolveSymbolicLinks());
type = followStat.isFile() ? FileType.SYMLINK_TO_FILE : FileType.SYMLINK_TO_DIRECTORY;
}
- return new FileInfo(
- type, fsVal != null ? fsVal : noFollowStat.hashCode(), realPath, unresolvedLinkTarget);
+ if (fsVal == null) {
+ fsVal = fileState;
+ }
+ return new FileInfo(type, withDigest(fsVal), realPath, unresolvedLinkTarget);
}
} else {
// Stat the file.
@@ -321,18 +342,32 @@
type = fileValue.isDirectory() ? FileType.DIRECTORY : FileType.FILE;
}
return new FileInfo(
- type, fileValue.realFileStateValue(), fileValue.realRootedPath(), unresolvedLinkTarget);
+ type,
+ withDigest(fileValue.realFileStateValue()),
+ fileValue.realRootedPath(),
+ unresolvedLinkTarget);
} else {
// If it doesn't exist, or it's a dangling symlink, we still want to handle that gracefully.
return new FileInfo(
fileValue.isSymlink() ? FileType.DANGLING_SYMLINK : FileType.NONEXISTENT,
- fileValue.realFileStateValue(),
+ withDigest(fileValue.realFileStateValue()),
null,
fileValue.isSymlink() ? fileValue.getUnresolvedLinkTarget() : null);
}
}
}
+ private static HasDigest withDigest(HasDigest fsVal) {
+ if (fsVal instanceof FileStateValue) {
+ return new HasDigest.ByteStringDigest(
+ ((FileStateValue) fsVal).getValueFingerprint().toByteArray());
+ } else if (fsVal instanceof FileArtifactValue) {
+ return new HasDigest.ByteStringDigest(
+ ((FileArtifactValue) fsVal).getValueFingerprint().toByteArray());
+ }
+ return fsVal;
+ }
+
private static final class PkgLookupResult {
private enum Type {
CONFLICT, DIRECTORY, PKG
@@ -511,18 +546,20 @@
return RecursiveFilesystemTraversalValue.of(root, paths.build());
}
- private static int hashDirectorySymlink(Iterable<ResolvedFile> children, Object metadata) {
+ private static HasDigest hashDirectorySymlink(
+ Iterable<ResolvedFile> children, HasDigest metadata) {
// If the root is a directory symlink, the associated FileStateValue does not change when the
// linked directory's contents change, so we can't use the FileStateValue as metadata like we
// do with other ResolvedFile kinds. Instead we compute a metadata hash from the child
// elements and return that as the ResolvedFile's metadata hash.
-
- // Compute the hash using the method described in Effective Java, 2nd ed., Item 9.
- int result = 0;
- for (ResolvedFile c : children) {
- result = 31 * result + c.getMetadata().hashCode();
+ Fingerprint fp = new Fingerprint();
+ fp.addBytes(metadata.getDigest());
+ for (ResolvedFile file : children) {
+ fp.addPath(file.getNameInSymlinkTree());
+ fp.addBytes(file.getMetadata().getDigest());
}
- return 31 * result + metadata.hashCode();
+ byte[] result = fp.digestAndReset();
+ return new HasDigest.ByteStringDigest(result);
}
private static SkyValue getDependentSkyValue(Environment env, SkyKey key)