Improving efficiency of fileset builds by using previously stat'd FileStatus, reducing the number of file system calls.
RELNOTES: None.
PiperOrigin-RevId: 277502268
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 3ada580..9e9e1ac 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
@@ -16,6 +16,7 @@
import static com.google.devtools.build.lib.vfs.UnixGlob.DEFAULT_SYSCALLS;
import static java.nio.charset.StandardCharsets.UTF_8;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import com.google.common.collect.Collections2;
@@ -25,6 +26,7 @@
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.FileStateValue.RegularFileStateValue;
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;
@@ -320,7 +322,7 @@
if (fsVal == null) {
fsVal = fileState;
}
- return new FileInfo(type, withDigest(fsVal), realPath, unresolvedLinkTarget);
+ return new FileInfo(type, withDigest(fsVal, path), realPath, unresolvedLinkTarget);
}
} else {
// Stat the file.
@@ -341,31 +343,60 @@
} else {
type = fileValue.isDirectory() ? FileType.DIRECTORY : FileType.FILE;
}
+ Path path = traversal.root.asRootedPath().asPath();
return new FileInfo(
type,
- withDigest(fileValue.realFileStateValue()),
+ withDigest(fileValue.realFileStateValue(), path),
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,
- withDigest(fileValue.realFileStateValue()),
+ withDigest(fileValue.realFileStateValue(), null),
null,
fileValue.isSymlink() ? fileValue.getUnresolvedLinkTarget() : null);
}
}
}
- private static HasDigest withDigest(HasDigest fsVal) {
+ /**
+ * Transform the HasDigest to the appropriate type based on the current state of the digest. If
+ * fsVal is type RegularFileStateValue or FileArtifactValue and has a valid digest value, then we
+ * want to convert it to a new FileArtifactValue type. Otherwise if they are of the two
+ * forementioned types but do not have a digest, then we will create a FileArtifactValue using its
+ * {@link Path}. Otherwise we will fingerprint the digest and return it as a new {@link
+ * HasDigest.ByteStringDigest} object.
+ *
+ * @param fsVal - the HasDigest value that was in the graph.
+ * @param path - the Path of the digest.
+ * @return transformed HasDigest value based on the digest field and object type.
+ */
+ @VisibleForTesting
+ static HasDigest withDigest(HasDigest fsVal, Path path) throws IOException {
if (fsVal instanceof FileStateValue) {
- return new HasDigest.ByteStringDigest(
- ((FileStateValue) fsVal).getValueFingerprint().toByteArray());
+ FileStateValue fsv = (FileStateValue) fsVal;
+ if (fsv instanceof RegularFileStateValue) {
+ RegularFileStateValue rfsv = (RegularFileStateValue) fsv;
+ return rfsv.getDigest() != null
+ // If we have the digest, then simply convert it with the digest value.
+ ? FileArtifactValue.createForVirtualActionInput(rfsv.getDigest(), rfsv.getSize())
+ // Otherwise, create a file FileArtifactValue (RegularFileArtifactValue) based on the
+ // path and size.
+ : FileArtifactValue.createForNormalFileUsingPath(path, rfsv.getSize());
+ }
+ return new HasDigest.ByteStringDigest(fsv.getValueFingerprint().toByteArray());
} else if (fsVal instanceof FileArtifactValue) {
- FileArtifactValue artifactValue = (FileArtifactValue) fsVal;
- // Transforming the FileArtifactValue to fingerprint the digests and retain other values
- return FileArtifactValue.createForVirtualActionInput(
- artifactValue.getValueFingerprint().toByteArray(), artifactValue.getSize());
+ FileArtifactValue fav = ((FileArtifactValue) fsVal);
+ if (fav.getDigest() != null) {
+ return fav;
+ }
+
+ // In the case there is a directory, the HasDigest value should not be converted. Otherwise,
+ // if the HasDigest value is a file, convert it using the Path and size values.
+ return fav.getType().isFile()
+ ? FileArtifactValue.createForNormalFileUsingPath(path, fav.getSize())
+ : new HasDigest.ByteStringDigest(fav.getValueFingerprint().toByteArray());
}
return fsVal;
}