From d4f1cfbb84de69a56f1fe854cfe142a844754e70 Mon Sep 17 00:00:00 2001 From: Bob Haarman Date: Fri, 10 Nov 2017 17:08:21 +0000 Subject: LTO: don't fatal when value for cache key already exists Summary: LTO/Caching.cpp uses file rename to atomically set the value for a cache key. On Windows, this fails when the destination file already exists. Previously, LLVM would report_fatal_error in such cases. However, because the old and the new value for the cache key are supposed to be equivalent, it actually doesn't matter which one we keep. This change makes it so that failing the rename when an openable file with the desired name already exists causes us to report success instead of fataling. Reviewers: pcc, hans Subscribers: mehdi_amini, llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D39874 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317899 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/LTO/Caching.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'lib/LTO/Caching.cpp') diff --git a/lib/LTO/Caching.cpp b/lib/LTO/Caching.cpp index 1708ab4c5c7..32fdd422187 100644 --- a/lib/LTO/Caching.cpp +++ b/lib/LTO/Caching.cpp @@ -14,9 +14,9 @@ #include "llvm/LTO/Caching.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Errc.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -72,10 +72,23 @@ Expected lto::localCache(StringRef CacheDirectoryPath, MBOrErr.getError().message() + "\n"); // This is atomic on POSIX systems. - if (auto EC = sys::fs::rename(TempFilename, EntryPath)) + // On Windows, it can fail with permission denied if the destination + // file already exists. Since the existing file should be semantically + // equivalent to the one we are trying to write, we give AddBuffer + // a copy of the bytes we wrote in that case. We do this instead of + // just using the existing file, because the pruner might delete the + // file before we get a chance to use it. + auto EC = sys::fs::rename(TempFilename, EntryPath); + if (EC == errc::permission_denied) { + auto MBCopy = MemoryBuffer::getMemBufferCopy( + (*MBOrErr)->getBuffer(), EntryPath); + MBOrErr = std::move(MBCopy); + sys::fs::remove(TempFilename); + } else if (EC) { report_fatal_error(Twine("Failed to rename temporary file ") + TempFilename + " to " + EntryPath + ": " + EC.message() + "\n"); + } AddBuffer(Task, std::move(*MBOrErr), EntryPath); } -- cgit v1.2.3