diff --git a/src/main/java/com/google/devtools/build/lib/actions/cache/DigestUtils.java b/src/main/java/com/google/devtools/build/lib/actions/cache/DigestUtils.java index 8539846e2b957e..7650db046ca496 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/cache/DigestUtils.java +++ b/src/main/java/com/google/devtools/build/lib/actions/cache/DigestUtils.java @@ -244,7 +244,8 @@ public static byte[] manuallyComputeDigest(Path path, long fileSize) throws IOEx Cache cache = globalCache; CacheKey key = null; if (cache != null) { - key = new CacheKey(path, path.stat()); + Path canonicalPath = path.resolveSymbolicLinks(); + key = new CacheKey(canonicalPath, canonicalPath.stat()); digest = cache.getIfPresent(key); if (digest != null) { return digest; diff --git a/src/test/java/com/google/devtools/build/lib/actions/DigestUtilsTest.java b/src/test/java/com/google/devtools/build/lib/actions/DigestUtilsTest.java index eb1ae6cb4f1683..dbe2cff6b2c03b 100644 --- a/src/test/java/com/google/devtools/build/lib/actions/DigestUtilsTest.java +++ b/src/test/java/com/google/devtools/build/lib/actions/DigestUtilsTest.java @@ -213,6 +213,50 @@ protected byte[] getDigest(Path path) throws IOException { assertThat(digest3).isEqualTo(digest1); } + @Test + public void testCacheWithSymlinks_cacheHit() throws Exception { + final AtomicInteger getFastDigestCounter = new AtomicInteger(0); + final AtomicInteger getDigestCounter = new AtomicInteger(0); + + FileSystem tracingFileSystem = + new InMemoryFileSystem(BlazeClock.instance()) { + @Override + protected byte[] getFastDigest(Path path) { + getFastDigestCounter.incrementAndGet(); + return null; + } + + @Override + protected byte[] getDigest(Path path) throws IOException { + getDigestCounter.incrementAndGet(); + return super.getDigest(path); + } + }; + + DigestUtils.configureCache(2); + + final Path file1 = tracingFileSystem.getPath("/file1.txt"); + FileSystemUtils.writeContentAsLatin1(file1, "some contents"); + // Create a symlink to file1 + final Path directory = tracingFileSystem.getPath("/dir"); + directory.createDirectory(); + final Path symlink = tracingFileSystem.getPath("/dir/symlink_to_file1.txt"); + symlink.createSymbolicLink(file1); + + byte[] digest1 = DigestUtils.getDigestWithManualFallback(file1, file1.getFileSize()); + assertThat(getFastDigestCounter.get()).isEqualTo(1); + assertThat(getDigestCounter.get()).isEqualTo(1); + new CacheStatsChecker().evictionCount(0).hitCount(0).missCount(1).check(); + + // Check that there is a cache hit for the symlink + byte[] digest2 = DigestUtils.getDigestWithManualFallback(symlink, symlink.getFileSize()); + assertThat(getFastDigestCounter.get()).isEqualTo(2); + assertThat(getDigestCounter.get()).isEqualTo(1); + new CacheStatsChecker().evictionCount(0).hitCount(1).missCount(1).check(); + + assertThat(digest1).isEqualTo(digest2); + } + @Test public void manuallyComputeDigest() throws Exception { byte[] digest = {1, 2, 3};