14#include "llvm/Support/AdvisoryLock.h"
15#include "llvm/Support/Chrono.h"
16#include "llvm/Support/Error.h"
17#include "llvm/Support/FileSystem.h"
18#include "llvm/Support/IOSandbox.h"
19#include "llvm/Support/MemoryBuffer.h"
20#include "llvm/Support/Path.h"
28 assert(llvm::sys::path::is_absolute(Path) &&
29 !llvm::sys::path::remove_dots(Canonical,
true) &&
30 "invalidated paths must be spelled like ModuleDeps::DirectoryDeps");
33 std::lock_guard<std::mutex> Lock(InvalidatedPathsMutex);
34 InvalidatedPaths.insert(Path);
36 AnyInvalidatedPaths.store(
true, std::memory_order_release);
43 if (!AnyInvalidatedPaths.load(std::memory_order_acquire))
45 std::lock_guard<std::mutex> Lock(InvalidatedPathsMutex);
46 return InvalidatedPaths.contains(Directory);
50 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
51 for (
auto &[Path, Entry] :
Map) {
53 assert(Entry->WrittenBuffer &&
"Wrote PCM with no contents");
60 (void)
writeImpl(Path, *Entry->WrittenBuffer, Size, ModTime);
66class ReaderWriterLock :
public llvm::AdvisoryLock {
68 std::optional<unsigned> OwnedGeneration;
74 std::lock_guard<std::mutex> Lock(Entry.
Mutex);
82 llvm::WaitForUnlockResult
83 waitForUnlockFor(std::chrono::seconds MaxSeconds)
override {
84 assert(!OwnedGeneration);
85 std::unique_lock<std::mutex> Lock(Entry.
Mutex);
92 return Success ? llvm::WaitForUnlockResult::Success
93 : llvm::WaitForUnlockResult::Timeout;
96 std::error_code unsafeUnlock()
override {
98 std::lock_guard<std::mutex> Lock(Entry.
Mutex);
106 ~ReaderWriterLock()
override {
107 if (OwnedGeneration) {
109 std::lock_guard<std::mutex> Lock(Entry.
Mutex);
120class InProcessModuleCache :
public ModuleCache {
121 ModuleCacheEntries &Entries;
127 InMemoryModuleCache InMemory;
129 ModuleCacheEntry &getOrCreateEntry(StringRef Filename) {
130 std::lock_guard<std::mutex> Lock(Entries.
Mutex);
131 auto &Entry = Entries.
Map[Filename];
133 Entry = std::make_unique<ModuleCacheEntry>();
138 InProcessModuleCache(ModuleCacheEntries &Entries, AtomicLineLogger &Logger)
139 : ModuleCache(Logger), Entries(Entries), InMemory(Logger) {}
141 std::unique_ptr<llvm::AdvisoryLock> getLock(StringRef Filename)
override {
142 auto &Entry = getOrCreateEntry(Filename);
143 return std::make_unique<ReaderWriterLock>(Entry);
146 std::time_t getModuleTimestamp(StringRef Filename)
override {
147 auto &Timestamp = getOrCreateEntry(Filename).Timestamp;
149 Logger.log() <<
"timestamp_read: " << Filename;
150 return Timestamp.load();
153 void updateModuleTimestamp(StringRef Filename)
override {
155 auto &Timestamp = getOrCreateEntry(Filename).Timestamp;
157 Logger.log() <<
"timestamp_write: " << Filename;
158 Timestamp.store(llvm::sys::toTimeT(std::chrono::system_clock::now()));
161 std::optional<bool> isDirectoryInvalidated(StringRef Directory)
override {
165 void maybePrune(StringRef Path, time_t PruneInterval,
166 time_t PruneAfter)
override {
172 InMemoryModuleCache &getInMemoryModuleCache()
override {
return InMemory; }
173 const InMemoryModuleCache &getInMemoryModuleCache()
const override {
177 std::error_code write(StringRef Path, llvm::MemoryBufferRef Buffer,
178 off_t &Size, time_t &ModTime)
override {
179 ModuleCacheEntry &Entry = getOrCreateEntry(Path);
180 std::lock_guard<std::mutex> Lock(Entry.
Mutex);
181 Logger.log() <<
"pcm_write: " << Path;
184 assert(Entry.
WrittenBuffer->getBuffer() == Buffer.getBuffer() &&
185 "Wrote the same PCM with different contents");
191 llvm::MemoryBuffer::getMemBufferCopy(Buffer.getBuffer(), Path);
192 Entry.
ModTime = llvm::sys::toTimeT(std::chrono::system_clock::now());
199 Expected<std::unique_ptr<llvm::MemoryBuffer>>
200 read(StringRef
FileName, off_t &Size, time_t &ModTime)
override {
201 Logger.log() <<
"pcm_read_disk: " <<
FileName;
202 ModuleCacheEntry &Entry = getOrCreateEntry(
FileName);
203 std::lock_guard<std::mutex> Lock(Entry.
Mutex);
206 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
211 return ReadBuffer.takeError();
219 Size = Buffer->getBufferSize();
222 return llvm::MemoryBuffer::getMemBuffer(*Buffer,
228std::shared_ptr<ModuleCache>
231 return std::make_shared<InProcessModuleCache>(Entries, Logger);
Defines a logger where each line is written atomically to the file.
std::shared_ptr< ModuleCache > makeInProcessModuleCache(ModuleCacheEntries &Entries, AtomicLineLogger &Logger)
Top level wrappers for InstallAPI frontend operations.
Expected< std::unique_ptr< llvm::MemoryBuffer > > readImpl(StringRef FileName, off_t &Size, time_t &ModTime)
Shared implementation of ModuleCache::read().
@ Success
Annotation was successful.
std::error_code writeImpl(StringRef Path, llvm::MemoryBufferRef Buffer, off_t &Size, time_t &ModTime)
Shared implementation of ModuleCache::write().
void maybePruneImpl(StringRef Path, time_t PruneInterval, time_t PruneAfter, bool PruneTopLevel=false, llvm::function_ref< void(StringRef)> OnPrune={})
Shared implementation of ModuleCache::maybePrune().
llvm::StringMap< std::unique_ptr< ModuleCacheEntry > > Map
void flush()
Flushes all PCMs built in-process to disk.
std::optional< bool > isDirectoryInvalidated(StringRef Directory) const
void addInvalidatedPath(StringRef Path)
bool ValidateAgainstInvalidatedPaths
enum clang::dependencies::ModuleCacheEntry::@010254116217305143125116322142262271134241253225 State
std::condition_variable CondVar
time_t ModTime
The modification time of the entry.
std::unique_ptr< llvm::MemoryBuffer > WrittenBuffer
The buffer we've written to module cache, if any.
std::unique_ptr< llvm::MemoryBuffer > ReadBuffer
The buffer we've read from disk, if any.