14#include "llvm/ADT/ScopeExit.h"
15#include "llvm/Support/Error.h"
16#include "llvm/Support/FileSystem.h"
17#include "llvm/Support/IOSandbox.h"
18#include "llvm/Support/LockFileManager.h"
19#include "llvm/Support/Path.h"
26 auto [ByNameIt, ByNameInserted] = ByPath.insert({Path,
nullptr});
27 if (!ByNameIt->second) {
29 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
33 llvm::sys::fs::file_status Status;
34 if (std::error_code EC = llvm::sys::fs::status(Path, Status)) {
36 if (EC != std::errc::no_such_file_or_directory)
39 if (llvm::sys::fs::create_directories(Path))
42 if (llvm::sys::fs::status(Path, Status))
46 llvm::sys::fs::UniqueID UID = Status.getUniqueID();
47 auto [ByUIDIt, ByUIDInserted] = ByUID.insert({UID,
nullptr});
49 ByUIDIt->second = std::make_unique<ModuleCacheDirectory>();
50 ByNameIt->second = ByUIDIt->second.get();
52 return ByNameIt->second;
58 llvm::raw_fd_ostream Out(TimestampFile.str(), EC, llvm::sys::fs::OF_None);
62 time_t PruneAfter,
bool PruneTopLevel,
63 llvm::function_ref<
void(StringRef)> OnPrune) {
64 if (PruneInterval <= 0 || PruneAfter <= 0)
68 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
71 (void)llvm::sys::fs::make_absolute(RootPath);
74 llvm::sys::path::append(TimestampFile,
"modules.timestamp");
77 llvm::sys::fs::file_status StatBuf;
78 if (std::error_code EC = llvm::sys::fs::status(TimestampFile, StatBuf)) {
80 if (EC == std::errc::no_such_file_or_directory)
87 time_t TimestampModTime =
88 llvm::sys::toTimeT(StatBuf.getLastModificationTime());
89 time_t CurrentTime = time(
nullptr);
90 if (CurrentTime - TimestampModTime <= PruneInterval)
98 auto NotifyPruned = [&](StringRef RemovedPath) {
100 OnPrune(RemovedPath);
106 auto TryPruneFile = [&](StringRef FilePath) {
108 StringRef Filename = llvm::sys::path::filename(FilePath);
109 StringRef Extension = llvm::sys::path::extension(FilePath);
110 if (Extension !=
".pcm" && Extension !=
".timestamp" &&
111 Filename !=
"modules.idx")
115 if (Filename ==
"modules.timestamp")
120 if (llvm::sys::fs::status(FilePath, StatBuf))
124 time_t FileAccessTime = llvm::sys::toTimeT(StatBuf.getLastAccessedTime());
125 if (CurrentTime - FileAccessTime <= PruneAfter)
129 if (!llvm::sys::fs::remove(FilePath))
130 NotifyPruned(FilePath);
133 std::string TimestampFilename = FilePath.str() +
".timestamp";
134 if (!llvm::sys::fs::remove(TimestampFilename))
135 NotifyPruned(TimestampFilename);
138 for (llvm::sys::fs::directory_iterator Dir(RootPath, EC), DirEnd;
139 Dir != DirEnd && !EC; Dir.increment(EC)) {
141 if (!llvm::sys::fs::is_directory(Dir->path())) {
143 TryPruneFile(Dir->path());
148 for (llvm::sys::fs::directory_iterator
File(Dir->path(), EC), FileEnd;
149 File != FileEnd && !EC;
File.increment(EC))
150 TryPruneFile(
File->path());
154 if (llvm::sys::fs::directory_iterator(Dir->path(), EC) ==
155 llvm::sys::fs::directory_iterator() &&
157 if (!llvm::sys::fs::remove(Dir->path()))
158 NotifyPruned(Dir->path());
164 off_t &Size, time_t &ModTime) {
165 StringRef Extension = llvm::sys::path::extension(Path);
167 ModelPath +=
"-%%%%%%%%";
168 ModelPath += Extension;
174 if ((EC = llvm::sys::fs::createUniqueFile(ModelPath, FD, TmpPath))) {
175 if (EC != std::errc::no_such_file_or_directory)
178 StringRef Dir = llvm::sys::path::parent_path(Path);
179 if (std::error_code InnerEC = llvm::sys::fs::create_directories(Dir))
182 if ((EC = llvm::sys::fs::createUniqueFile(ModelPath, FD, TmpPath)))
186 llvm::sys::fs::file_status Status;
188 llvm::raw_fd_ostream OS(FD,
true);
189 OS << Buffer.getBuffer();
193 if ((EC = llvm::sys::fs::status(FD, Status)))
197 Size = Status.getSize();
198 ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
201 if ((EC = llvm::sys::fs::rename(TmpPath, Path)))
217 [[maybe_unused]]
const llvm::sys::fs::file_status &Status) {
221 llvm::sys::TimePoint<> Now = std::chrono::system_clock::now();
228 (void)llvm::sys::fs::setLastAccessAndModificationTime(
229 FD.get(), Now, Status.getLastModificationTime());
236 llvm::sys::fs::openNativeFileForRead(
FileName);
238 return FD.takeError();
239 llvm::scope_exit CloseFD([&FD]() { llvm::sys::fs::closeFile(*FD); });
240 llvm::sys::fs::file_status Status;
241 if (std::error_code EC = llvm::sys::fs::status(*FD, Status))
242 return llvm::errorCodeToError(EC);
243 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf =
244 llvm::MemoryBuffer::getOpenFile(*FD,
FileName, Status.getSize(),
247 return llvm::errorCodeToError(Buf.getError());
248 Size = Status.getSize();
249 ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
251 return std::move(*Buf);
257class CrossProcessModuleCache :
public ModuleCache {
261 explicit CrossProcessModuleCache()
264 std::unique_ptr<llvm::AdvisoryLock>
265 getLock(StringRef ModuleFilename)
override {
266 return std::make_unique<llvm::LockFileManager>(ModuleFilename);
269 std::time_t getModuleTimestamp(StringRef ModuleFilename)
override {
271 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
273 std::string TimestampFilename =
275 llvm::sys::fs::file_status Status;
276 if (llvm::sys::fs::status(TimestampFilename, Status) != std::error_code{})
278 return llvm::sys::toTimeT(Status.getLastModificationTime());
281 void updateModuleTimestamp(StringRef ModuleFilename)
override {
283 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
287 llvm::raw_fd_ostream
OS(
289 llvm::sys::fs::OF_TextWithCRLF);
292 OS <<
"Timestamp file\n";
297 void maybePrune(StringRef Path, time_t PruneInterval,
298 time_t PruneAfter)
override {
300 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
305 InMemoryModuleCache &getInMemoryModuleCache()
override {
return InMemory; }
306 const InMemoryModuleCache &getInMemoryModuleCache()
const override {
310 std::error_code write(StringRef Path, llvm::MemoryBufferRef Buffer,
311 off_t &Size, time_t &ModTime)
override {
313 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
315 return writeImpl(Path, Buffer, Size, ModTime);
318 Expected<std::unique_ptr<llvm::MemoryBuffer>>
319 read(StringRef
FileName, off_t &Size, time_t &ModTime)
override {
321 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
329 return std::make_shared<CrossProcessModuleCache>();
Defines a logger where each line is written atomically to the file.
static constexpr std::chrono::seconds AccessTimeRefreshInterval(60)
The access time of a module file is only refreshed explicitly when it is older than this interval so ...
static void refreshAccessTime(llvm::sys::fs::file_t FD, const llvm::sys::fs::file_status &Status)
Record that the module file open as FD has just been used by setting its access time to now,...
static void writeTimestampFile(StringRef TimestampFile)
Write a new timestamp file with the given path.
In-memory cache for modules.
The address of an instance of this class represents the identity of a module cache directory.
The module cache used for compiling modules implicitly.
virtual const ModuleCacheDirectory * getDirectoryPtr(StringRef Path)
Returns an opaque pointer representing the module cache directory.
static std::string getTimestampFilename(StringRef FileName)
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
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().
std::shared_ptr< ModuleCache > createCrossProcessModuleCache()
Creates new ModuleCache backed by a file system directory that may be operated on by multiple process...
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().