Gracefully handle filesystem inconsistencies in `RecursiveFilesystemTraversalFunction`. PiperOrigin-RevId: 577878638 Change-Id: I696e1ace5338a026345ece2222b620cea99ae264
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ArtifactFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ArtifactFunction.java index 8c2a068..62e2ca4 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/ArtifactFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ArtifactFunction.java
@@ -319,6 +319,9 @@ case SYMLINK_CYCLE_OR_INFINITE_EXPANSION: throw new ArtifactFunctionException( SourceArtifactException.create(artifact, e), Transience.PERSISTENT); + case INCONSISTENT_FILESYSTEM: + throw new ArtifactFunctionException( + SourceArtifactException.create(artifact, e), Transience.TRANSIENT); case CANNOT_CROSS_PACKAGE_BOUNDARY: throw new IllegalStateException( String.format(
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD index cc6855b..a39bc53 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -2003,6 +2003,7 @@ "//src/main/java/com/google/devtools/build/lib/io:file_symlink_exception", "//src/main/java/com/google/devtools/build/lib/io:file_symlink_infinite_expansion_exception", "//src/main/java/com/google/devtools/build/lib/io:file_symlink_infinite_expansion_uniqueness_function", + "//src/main/java/com/google/devtools/build/lib/io:inconsistent_filesystem_exception", "//src/main/java/com/google/devtools/build/lib/packages", "//src/main/java/com/google/devtools/build/lib/profiler", "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec",
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 70fa69d..6c03cb3 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
@@ -15,7 +15,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.common.annotations.VisibleForTesting; @@ -36,6 +35,7 @@ import com.google.devtools.build.lib.io.FileSymlinkException; import com.google.devtools.build.lib.io.FileSymlinkInfiniteExpansionException; import com.google.devtools.build.lib.io.FileSymlinkInfiniteExpansionUniquenessFunction; +import com.google.devtools.build.lib.io.InconsistentFilesystemException; import com.google.devtools.build.lib.packages.BuildFileNotFoundException; import com.google.devtools.build.lib.profiler.Profiler; import com.google.devtools.build.lib.profiler.ProfilerTask; @@ -106,6 +106,9 @@ /** A file/directory visited was part of a symlink cycle or infinite expansion. */ SYMLINK_CYCLE_OR_INFINITE_EXPANSION, + + /** The filesystem told us inconsistent information. */ + INCONSISTENT_FILESYSTEM, } private final RecursiveFilesystemTraversalException.Type type; @@ -170,7 +173,11 @@ if (!rootInfo.type.exists()) { // May be a dangling symlink or a non-existent file. Handle gracefully. if (rootInfo.type.isSymlink()) { - return resultForDanglingSymlink(traversal.root().asRootedPath(), rootInfo); + return RecursiveFilesystemTraversalValue.of( + ResolvedFileFactory.danglingSymlink( + traversal.root().asRootedPath(), + rootInfo.unresolvedSymlinkTarget, + rootInfo.metadata)); } else { return RecursiveFilesystemTraversalValue.EMPTY; } @@ -248,6 +255,9 @@ // trying to get a package lookup value may have failed due to a symlink cycle. RecursiveFilesystemTraversalException.Type exceptionType = RecursiveFilesystemTraversalException.Type.FILE_OPERATION_FAILURE; + if (e instanceof InconsistentFilesystemException) { + exceptionType = RecursiveFilesystemTraversalException.Type.INCONSISTENT_FILESYSTEM; + } if (e instanceof FileSymlinkException) { exceptionType = RecursiveFilesystemTraversalException.Type.SYMLINK_CYCLE_OR_INFINITE_EXPANSION; @@ -570,27 +580,19 @@ } /** - * Creates result for a dangling symlink. - * - * @param linkName path to the symbolic link - * @param info the {@link FileInfo} associated with the link file - */ - private static RecursiveFilesystemTraversalValue resultForDanglingSymlink( - RootedPath linkName, FileInfo info) { - checkState(info.type.isSymlink() && !info.type.exists(), "{%s} {%s}", linkName, info.type); - return RecursiveFilesystemTraversalValue.of( - ResolvedFileFactory.danglingSymlink(linkName, info.unresolvedSymlinkTarget, info.metadata)); - } - - /** * Creates results for a file or for a symlink that points to one. * * <p>A symlink may be direct (points to a file) or transitive (points at a direct or transitive * symlink). */ - private static RecursiveFilesystemTraversalValue resultForFileRoot( - RootedPath path, FileInfo info) { - checkState(info.type.isFile() && info.type.exists(), "{%s} {%s}", path, info.type); + private static RecursiveFilesystemTraversalValue resultForFileRoot(RootedPath path, FileInfo info) + throws InconsistentFilesystemException { + if (!info.type.isFile() || !info.type.exists()) { + throw new InconsistentFilesystemException( + String.format( + "We were previously told %s was an existing file but it's actually %s", path, info)); + } + if (info.type.isSymlink()) { return RecursiveFilesystemTraversalValue.of( ResolvedFileFactory.symlinkToFile(