diff --git a/llvm/include/llvm/Support/Caching.h b/llvm/include/llvm/Support/Caching.h --- a/llvm/include/llvm/Support/Caching.h +++ b/llvm/include/llvm/Support/Caching.h @@ -62,10 +62,11 @@ std::function MB)>; /// Create a local file system cache which uses the given cache name, temporary -/// file prefix, cache directory and file callback. This function also creates -/// the cache directory if it does not already exist. The cache name appears in -/// error messages for errors during caching. The temporary file prefix is used -/// in the temporary file naming scheme used when writing files atomically. +/// file prefix, cache directory and file callback. This function does not +/// immediately create the cache directory if it does not yet exist; this is +/// done lazily the first time a file is added. The cache name appears in error +/// messages for errors during caching. The temporary file prefix is used in the +/// temporary file naming scheme used when writing files atomically. Expected localCache( Twine CacheNameRef, Twine TempFilePrefixRef, Twine CacheDirectoryPathRef, AddBufferFn AddBuffer = [](size_t Task, std::unique_ptr MB) { diff --git a/llvm/lib/Support/Caching.cpp b/llvm/lib/Support/Caching.cpp --- a/llvm/lib/Support/Caching.cpp +++ b/llvm/lib/Support/Caching.cpp @@ -30,8 +30,6 @@ Twine TempFilePrefixRef, Twine CacheDirectoryPathRef, AddBufferFn AddBuffer) { - if (std::error_code EC = sys::fs::create_directories(CacheDirectoryPathRef)) - return errorCodeToError(EC); // Create local copies which are safely captured-by-copy in lambdas SmallString<64> CacheName, TempFilePrefix, CacheDirectoryPath; @@ -140,6 +138,12 @@ }; return [=](size_t Task) -> Expected> { + // Create the cache directory if not already done. Doing this lazily + // ensures the filesystem isn't mutated until the cache is. + if (std::error_code EC = sys::fs::create_directories( + CacheDirectoryPath, /*IgnoreExisting=*/true)) + return errorCodeToError(EC); + // Write to a temporary to avoid race condition SmallString<64> TempFilenameModel; sys::path::append(TempFilenameModel, CacheDirectoryPath, diff --git a/llvm/test/ThinLTO/X86/cache.ll b/llvm/test/ThinLTO/X86/cache.ll --- a/llvm/test/ThinLTO/X86/cache.ll +++ b/llvm/test/ThinLTO/X86/cache.ll @@ -20,7 +20,7 @@ ; RUN: -r=%t2.bc,_main,plx \ ; RUN: -r=%t2.bc,_globalfunc,lx \ ; RUN: -r=%t.bc,_globalfunc,plx -; RUN: ls %t.cache.noindex | count 0 +; RUN: not ls %t.cache.noindex ; Repeat again, *with* hash this time. diff --git a/llvm/test/ThinLTO/X86/empty_module_with_cache.ll b/llvm/test/ThinLTO/X86/empty_module_with_cache.ll --- a/llvm/test/ThinLTO/X86/empty_module_with_cache.ll +++ b/llvm/test/ThinLTO/X86/empty_module_with_cache.ll @@ -28,7 +28,7 @@ ; RUN: rm -Rf %t.cache ; RUN: llvm-lto2 run -o %t.o %t2.bc %t.bc -cache-dir %t.cache \ ; RUN: -r=%t2.bc,_main,plx -; RUN: ls %t.cache | count 0 +; RUN: not ls %t.cache target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" diff --git a/llvm/unittests/Debuginfod/DebuginfodTests.cpp b/llvm/unittests/Debuginfod/DebuginfodTests.cpp --- a/llvm/unittests/Debuginfod/DebuginfodTests.cpp +++ b/llvm/unittests/Debuginfod/DebuginfodTests.cpp @@ -17,6 +17,17 @@ #define setenv(name, var, ignore) _putenv_s(name, var) #endif +#define ASSERT_NO_ERROR(x) \ + if (std::error_code ASSERT_NO_ERROR_ec = x) { \ + SmallString<128> MessageStorage; \ + raw_svector_ostream Message(MessageStorage); \ + Message << #x ": did not return errc::success.\n" \ + << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \ + << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \ + GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \ + } else { \ + } + using namespace llvm; // Check that the Debuginfod client can find locally cached artifacts. @@ -40,11 +51,12 @@ // Check that the Debuginfod client returns an Error when it fails to find an // artifact. TEST(DebuginfodClient, CacheMiss) { - // Set the cache path to a temp directory to avoid permissions issues if $HOME - // is not writable. - SmallString<32> TempDir; - sys::path::system_temp_directory(true, TempDir); - setenv("DEBUGINFOD_CACHE_PATH", TempDir.c_str(), + SmallString<32> CacheDir; + ASSERT_NO_ERROR( + sys::fs::createUniqueDirectory("debuginfod-unittest", CacheDir)); + sys::path::append(CacheDir, "cachedir"); + ASSERT_FALSE(sys::fs::exists(CacheDir)); + setenv("DEBUGINFOD_CACHE_PATH", CacheDir.c_str(), /*replace=*/1); // Ensure there are no urls to guarantee a cache miss. setenv("DEBUGINFOD_URLS", "", /*replace=*/1); @@ -52,4 +64,6 @@ Expected PathOrErr = getCachedOrDownloadArtifact( /*UniqueKey=*/"nonexistent-key", /*UrlPath=*/"/null"); EXPECT_THAT_EXPECTED(PathOrErr, Failed()); + // A cache miss with no possible URLs should not create the cache directory. + EXPECT_FALSE(sys::fs::exists(CacheDir)); }