Don't unconditionally update ExternalFilesHelper tracking data at the end of handleDiffsWithMissingDiffInformation: we may skip a full-graph traversal in various circumstances. If that happens, we must preserve existing knowledge for next time. This doesn't have a severe impact on performance because the original goal, of not doing repeated scans when a file had fallen out of the graph, is still met.
PiperOrigin-RevId: 420154787
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
index 844093a..6b1416b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
@@ -471,19 +471,19 @@
int fsvcThreads)
throws InterruptedException {
- // We freshly compute knowledge of the presence of external files in the skyframe graph. We use
- // a fresh ExternalFilesHelper instance and only set the real instance's knowledge *after* we
- // are done with the graph scan, lest an interrupt during the graph scan causes us to
- // incorrectly think there are no longer any external files.
- ExternalFilesHelper tmpExternalFilesHelper =
- externalFilesHelper.cloneWithFreshExternalFilesKnowledge();
-
ExternalFilesKnowledge externalFilesKnowledge = externalFilesHelper.getExternalFilesKnowledge();
if (!pathEntriesWithoutDiffInformation.isEmpty()
|| (externalFilesKnowledge.anyOutputFilesSeen && checkOutputFiles)
|| repositoryHelpersHolder != null
|| externalFilesKnowledge.anyFilesInExternalReposSeen
|| externalFilesKnowledge.tooManyNonOutputExternalFilesSeen) {
+ // We freshly compute knowledge of the presence of external files in the skyframe graph. We
+ // use
+ // a fresh ExternalFilesHelper instance and only set the real instance's knowledge *after* we
+ // are done with the graph scan, lest an interrupt during the graph scan causes us to
+ // incorrectly think there are no longer any external files.
+ ExternalFilesHelper tmpExternalFilesHelper =
+ externalFilesHelper.cloneWithFreshExternalFilesKnowledge();
// Before running the FilesystemValueChecker, ensure that all values marked for invalidation
// have actually been invalidated (recall that invalidation happens at the beginning of the
@@ -514,7 +514,8 @@
if (checkOutputFiles) {
fileTypesToCheck.add(FileType.OUTPUT);
}
- if (externalFilesKnowledge.tooManyNonOutputExternalFilesSeen) {
+ if (externalFilesKnowledge.tooManyNonOutputExternalFilesSeen
+ || !externalFilesKnowledge.nonOutputExternalFilesSeen.isEmpty()) {
fileTypesToCheck.add(FileType.EXTERNAL);
}
logger.atInfo().log(
@@ -540,9 +541,12 @@
batchDirtyResult,
/*numSourceFilesCheckedIfDiffWasMissing=*/ batchDirtyResult.getNumKeysChecked(),
managedDirectoriesChanged);
- }
- if (!externalFilesKnowledge.nonOutputExternalFilesSeen.isEmpty()
- && !externalFilesKnowledge.tooManyNonOutputExternalFilesSeen) {
+ // We use the knowledge gained during the graph scan that just completed. Otherwise, naively,
+ // once an external file gets into the Skyframe graph, we'll overly-conservatively always
+ // think the graph needs to be scanned.
+ externalFilesHelper.setExternalFilesKnowledge(
+ tmpExternalFilesHelper.getExternalFilesKnowledge());
+ } else if (!externalFilesKnowledge.nonOutputExternalFilesSeen.isEmpty()) {
logger.atInfo().log(
"About to scan %d external files",
externalFilesKnowledge.nonOutputExternalFilesSeen.size());
@@ -566,8 +570,7 @@
batchDirtyResult =
fsvc.getDirtyKeys(
externalDirtyNodes,
- new ExternalDirtinessChecker(
- tmpExternalFilesHelper, EnumSet.of(FileType.EXTERNAL)));
+ new ExternalDirtinessChecker(externalFilesHelper, EnumSet.of(FileType.EXTERNAL)));
}
handleChangedFiles(
ImmutableList.of(),
@@ -579,11 +582,6 @@
pathEntriesWithoutDiffInformation) {
pair.getSecond().markProcessed();
}
- // We use the knowledge gained during the graph scan that just completed. Otherwise, naively,
- // once an external file gets into the Skyframe graph, we'll overly-conservatively always think
- // the graph needs to be scanned.
- externalFilesHelper.setExternalFilesKnowledge(
- tmpExternalFilesHelper.getExternalFilesKnowledge());
}
private void handleChangedFiles(
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/LocalDiffAwarenessIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/LocalDiffAwarenessIntegrationTest.java
index 2129bc2..cebba6f 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/LocalDiffAwarenessIntegrationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/LocalDiffAwarenessIntegrationTest.java
@@ -30,6 +30,7 @@
import com.google.devtools.build.lib.vfs.DelegateFileSystem;
import com.google.devtools.build.lib.vfs.FileStatus;
import com.google.devtools.build.lib.vfs.FileSystem;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.NotifyingHelper;
@@ -127,6 +128,34 @@
}
@Test
+ public void ignoreOutputFilesThenCheckAgainDoesCheck() throws Exception {
+ Path buildFile =
+ write(
+ "foo/BUILD",
+ "genrule(name = 'foo', outs = ['out'], cmd = 'cp $< $@', srcs = ['link'])");
+ Path outputFile = directories.getOutputBase().getChild("linkTarget");
+ FileSystemUtils.writeContentAsLatin1(outputFile, "one");
+ buildFile.getParentDirectory().getChild("link").createSymbolicLink(outputFile.asFragment());
+
+ buildTarget("//foo:foo");
+
+ assertContents("one", "//foo:foo");
+
+ addOptions("--noexperimental_check_output_files");
+ FileSystemUtils.writeContentAsLatin1(outputFile, "two");
+
+ buildTarget("//foo:foo");
+
+ assertContents("one", "//foo:foo");
+
+ addOptions("--experimental_check_output_files");
+
+ buildTarget("//foo:foo");
+
+ assertContents("two", "//foo:foo");
+ }
+
+ @Test
public void externalSymlink_doesNotTriggerFullGraphTraversal() throws Exception {
addOptions("--symlink_prefix=/");
AtomicInteger calledGetValues = new AtomicInteger(0);