clang 22.0.0git
ModuleCache.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
13#include "llvm/Support/FileSystem.h"
14#include "llvm/Support/LockFileManager.h"
15#include "llvm/Support/Path.h"
16
17using namespace clang;
18
19/// Write a new timestamp file with the given path.
20static void writeTimestampFile(StringRef TimestampFile) {
21 std::error_code EC;
22 llvm::raw_fd_ostream Out(TimestampFile.str(), EC, llvm::sys::fs::OF_None);
23}
24
25void clang::maybePruneImpl(StringRef Path, time_t PruneInterval,
26 time_t PruneAfter) {
27 if (PruneInterval <= 0 || PruneAfter <= 0)
28 return;
29
30 llvm::SmallString<128> TimestampFile(Path);
31 llvm::sys::path::append(TimestampFile, "modules.timestamp");
32
33 // Try to stat() the timestamp file.
34 llvm::sys::fs::file_status StatBuf;
35 if (std::error_code EC = llvm::sys::fs::status(TimestampFile, StatBuf)) {
36 // If the timestamp file wasn't there, create one now.
37 if (EC == std::errc::no_such_file_or_directory)
38 writeTimestampFile(TimestampFile);
39 return;
40 }
41
42 // Check whether the time stamp is older than our pruning interval.
43 // If not, do nothing.
44 time_t TimestampModTime =
45 llvm::sys::toTimeT(StatBuf.getLastModificationTime());
46 time_t CurrentTime = time(nullptr);
47 if (CurrentTime - TimestampModTime <= PruneInterval)
48 return;
49
50 // Write a new timestamp file so that nobody else attempts to prune.
51 // There is a benign race condition here, if two Clang instances happen to
52 // notice at the same time that the timestamp is out-of-date.
53 writeTimestampFile(TimestampFile);
54
55 // Walk the entire module cache, looking for unused module files and module
56 // indices.
57 std::error_code EC;
58 for (llvm::sys::fs::directory_iterator Dir(Path, EC), DirEnd;
59 Dir != DirEnd && !EC; Dir.increment(EC)) {
60 // If we don't have a directory, there's nothing to look into.
61 if (!llvm::sys::fs::is_directory(Dir->path()))
62 continue;
63
64 // Walk all the files within this directory.
65 for (llvm::sys::fs::directory_iterator File(Dir->path(), EC), FileEnd;
66 File != FileEnd && !EC; File.increment(EC)) {
67 // We only care about module and global module index files.
68 StringRef Extension = llvm::sys::path::extension(File->path());
69 if (Extension != ".pcm" && Extension != ".timestamp" &&
70 llvm::sys::path::filename(File->path()) != "modules.idx")
71 continue;
72
73 // Look at this file. If we can't stat it, there's nothing interesting
74 // there.
75 if (llvm::sys::fs::status(File->path(), StatBuf))
76 continue;
77
78 // If the file has been used recently enough, leave it there.
79 time_t FileAccessTime = llvm::sys::toTimeT(StatBuf.getLastAccessedTime());
80 if (CurrentTime - FileAccessTime <= PruneAfter)
81 continue;
82
83 // Remove the file.
84 llvm::sys::fs::remove(File->path());
85
86 // Remove the timestamp file.
87 std::string TimpestampFilename = File->path() + ".timestamp";
88 llvm::sys::fs::remove(TimpestampFilename);
89 }
90
91 // If we removed all the files in the directory, remove the directory
92 // itself.
93 if (llvm::sys::fs::directory_iterator(Dir->path(), EC) ==
94 llvm::sys::fs::directory_iterator() &&
95 !EC)
96 llvm::sys::fs::remove(Dir->path());
97 }
98}
99
100namespace {
101class CrossProcessModuleCache : public ModuleCache {
102 InMemoryModuleCache InMemory;
103
104public:
105 void prepareForGetLock(StringRef ModuleFilename) override {
106 // FIXME: Do this in LockFileManager and only if the directory doesn't
107 // exist.
108 StringRef Dir = llvm::sys::path::parent_path(ModuleFilename);
109 llvm::sys::fs::create_directories(Dir);
110 }
111
112 std::unique_ptr<llvm::AdvisoryLock>
113 getLock(StringRef ModuleFilename) override {
114 return std::make_unique<llvm::LockFileManager>(ModuleFilename);
115 }
116
117 std::time_t getModuleTimestamp(StringRef ModuleFilename) override {
118 std::string TimestampFilename =
120 llvm::sys::fs::file_status Status;
121 if (llvm::sys::fs::status(TimestampFilename, Status) != std::error_code{})
122 return 0;
123 return llvm::sys::toTimeT(Status.getLastModificationTime());
124 }
125
126 void updateModuleTimestamp(StringRef ModuleFilename) override {
127 // Overwrite the timestamp file contents so that file's mtime changes.
128 std::error_code EC;
129 llvm::raw_fd_ostream OS(
131 llvm::sys::fs::OF_TextWithCRLF);
132 if (EC)
133 return;
134 OS << "Timestamp file\n";
135 OS.close();
136 OS.clear_error(); // Avoid triggering a fatal error.
137 }
138
139 void maybePrune(StringRef Path, time_t PruneInterval,
140 time_t PruneAfter) override {
141 maybePruneImpl(Path, PruneInterval, PruneAfter);
142 }
143
144 InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; }
145 const InMemoryModuleCache &getInMemoryModuleCache() const override {
146 return InMemory;
147 }
148};
149} // namespace
150
152 return llvm::makeIntrusiveRefCnt<CrossProcessModuleCache>();
153}
static void writeTimestampFile(StringRef TimestampFile)
Write a new timestamp file with the given path.
In-memory cache for modules.
The module cache used for compiling modules implicitly.
Definition ModuleCache.h:26
static std::string getTimestampFilename(StringRef FileName)
Definition ModuleFile.h:153
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
IntrusiveRefCntPtr< ModuleCache > createCrossProcessModuleCache()
Creates new ModuleCache backed by a file system directory that may be operated on by multiple process...
void maybePruneImpl(StringRef Path, time_t PruneInterval, time_t PruneAfter)
Shared implementation of ModuleCache::maybePrune().