From 6e1e9449b805fcc47466a2cdc13958e8d92b3f05 Mon Sep 17 00:00:00 2001 From: azad Date: Thu, 2 Jul 2026 01:41:13 +0000 Subject: [PATCH] [Android] Backport action cache cleanup fix from Bazel 9 Backport of the fix for https://github.com/bazelbuild/bazel/issues/26818 which causes Bazel 8 to corrupt the output base for Bazel 7 when alternating between versions on the same workspace. The fix deletes unrecognized files from the action cache on-disk directory when loading it into memory. This prevents spurious cache hits for stale runfiles trees when the runfiles output manifest (a symlink to the input manifest) appears valid but the underlying tree was updated by an intervening build with a different Bazel version. Original fix: https://github.com/bazelbuild/bazel/pull/27525 Original commit: 912099e4e7f80db291e3a67e8e445a9de9c90d6c Co-Authored-By: Claude Opus 4.6 (1M context) --- .../cache/CompactPersistentActionCache.java | 29 +++++++++++++++++++ .../CompactPersistentActionCacheTest.java | 9 ++++++ 2 files changed, 38 insertions(+) diff --git a/src/main/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCache.java b/src/main/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCache.java index 8c936db5eb7059..810fa7c5b33f95 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCache.java +++ b/src/main/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCache.java @@ -18,6 +18,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.flogger.GoogleLogger; import com.google.devtools.build.lib.actions.FileArtifactValue.RemoteFileArtifactValue; @@ -253,9 +254,37 @@ private static CompactPersistentActionCache create( } misses.put(reason, new AtomicInteger(0)); } + deleteUnrecognizedFiles(cacheRoot); return new CompactPersistentActionCache(indexer, map, Maps.immutableEnumMap(misses)); } + /** + * Deletes unrecognized files from the action cache on-disk directory. + * + *

This works around an incrementality bug when building a runfiles tree while alternating + * between Bazel versions. Specifically, because the runfiles output manifest is a symlink to the + * input manifest (and therefore always appears to have the contents of the latter), one can get a + * spurious cache hit for a stale runfiles tree if the tree was updated in an intervening build + * without the action cache being updated accordingly. + * + *

Backported from https://github.com/bazelbuild/bazel/pull/27525 (Bazel 9.0.0). + */ + private static void deleteUnrecognizedFiles(Path cacheRoot) throws IOException { + Path indexFile = cacheRoot.getChild("filename_index_v" + VERSION + ".blaze"); + Path indexJournalFile = cacheRoot.getChild("filename_index_v" + VERSION + ".journal"); + ImmutableSet knownFiles = + ImmutableSet.of( + cacheFile(cacheRoot), + journalFile(cacheRoot), + indexFile, + indexJournalFile); + for (Path child : cacheRoot.getDirectoryEntries()) { + if (!knownFiles.contains(child)) { + child.delete(); + } + } + } + private static CompactPersistentActionCache logAndThrowOrRecurse( Path cacheRoot, Clock clock, diff --git a/src/test/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCacheTest.java b/src/test/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCacheTest.java index 838af5eda54dee..3c6eafd6ccb347 100644 --- a/src/test/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCacheTest.java +++ b/src/test/java/com/google/devtools/build/lib/actions/cache/CompactPersistentActionCacheTest.java @@ -451,6 +451,15 @@ public void putAndGet_treeMetadata_savesMaterializationExecPath() { Optional.of(materializationExecPath))); } + @Test + public void testDeleteUnrecognizedFiles() throws Exception { + Path unrecognizedFile = dataRoot.getChild("unrecognized_file"); + FileSystemUtils.writeContentAsLatin1(unrecognizedFile, "content"); + assertThat(unrecognizedFile.exists()).isTrue(); + CompactPersistentActionCache.create(dataRoot, clock, NullEventHandler.INSTANCE); + assertThat(unrecognizedFile.exists()).isFalse(); + } + private static void assertKeyEquals(ActionCache cache1, ActionCache cache2, String key) { Object entry = cache1.get(key); assertThat(entry).isNotNull();