LLVM: lib/CAS/UnifiedOnDiskCache.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
89#include
90
91#if __has_include(<sys/sysctl.h>)
92#include <sys/sysctl.h>
93#endif
94
95using namespace llvm;
98
99
100
101
103
106
112
115
117 static_assert(ValBytes.size() == sizeof(ID.getOpaqueData()));
119 return ValBytes;
120}
121
124 assert(UpstreamGraphDB);
125 assert(UpstreamKVDB);
126
127 std::optional<ArrayRef> UpstreamValue;
128 if (Error E = UpstreamKVDB->get(Key).moveInto(UpstreamValue))
129 return std::move(E);
130 if (!UpstreamValue)
131 return std::nullopt;
132
133
134
135
137 auto PrimaryID =
138 PrimaryGraphDB->getReference(UpstreamGraphDB->getDigest(UpstreamID));
140 return PrimaryID.takeError();
142}
143
144
145
146
149 struct DBDir {
151 std::string Name;
152 };
154
155 std::error_code EC;
157 DirI.increment(EC)) {
159 continue;
162 FoundDBDirs.push_back({0, std::string(SubDir)});
163 continue;
164 }
166 continue;
170 "unexpected directory " + DirI->path());
171 FoundDBDirs.push_back({Order, std::string(SubDir)});
172 }
173 if (EC)
175
176 llvm::sort(FoundDBDirs, [](const DBDir &LHS, const DBDir &RHS) -> bool {
177 return LHS.Order < RHS.Order;
178 });
179
181 for (DBDir &Dir : FoundDBDirs)
182 DBDirs.push_back(std::move(Dir.Name));
183 return DBDirs;
184}
185
187 auto DBDirs = getAllDBDirs(Path, true);
188 if (!DBDirs)
189 return DBDirs.takeError();
190
191
192
193
194 for (unsigned Keep = 2; Keep > 0 && !DBDirs->empty(); --Keep) {
197 break;
198 DBDirs->pop_back();
199 }
200 return *DBDirs;
201}
202
203
204
213
215 bool CheckHash) {
217 if (CheckHash)
218 Args.push_back("-check-hash");
219
221 int StdErrFD = -1;
223 "llvm-cas-validate-stderr", "txt", StdErrFD, StdErrPath,
227
228 std::optionalllvm::StringRef Redirects[] = {
229 {""},
230 {""},
231 StdErrPath.str(),
232 };
233
234 std::string ErrMsg;
235 int Result =
236 sys::ExecuteAndWait(LLVMCasBinary, Args, std::nullopt, Redirects,
237 120, 0, &ErrMsg);
238
239 if (Result == -1)
241 ErrMsg);
242 if (Result != 0) {
244 if (!ErrMsg.empty()) {
245 Err += ": ";
246 Err += ErrMsg;
247 }
249 if (StdErrBuf && !(*StdErrBuf)->getBuffer().empty()) {
250 Err += ": ";
251 Err += (*StdErrBuf)->getBuffer();
252 }
254 }
256}
257
259 unsigned HashByteSize, bool CheckHash) {
260 std::shared_ptr UniDB;
262 HashByteSize)
263 .moveInto(UniDB))
264 return E;
266 if (Error E = CAS->validate(CheckHash))
267 return E;
269 if (Error E = Cache->validate())
270 return E;
272}
273
275#if __has_include(<sys/sysctl.h>) && defined(KERN_BOOTTIME)
276 struct timeval TV;
277 size_t TVLen = sizeof(TV);
278 int KernBoot[2] = {CTL_KERN, KERN_BOOTTIME};
279 if (sysctl(KernBoot, 2, &TV, &TVLen, nullptr, 0) < 0)
281 "failed to get boottime");
282 if (TVLen != sizeof(TV))
283 return createStringError("sysctl kern.boottime unexpected format");
284 return TV.tv_sec;
285#elif defined(__linux__)
286
287
291 return Status.getLastModificationTime().time_since_epoch().count();
292#else
294#endif
295}
296
299 bool CheckHash, bool AllowRecovery, bool ForceValidation,
300 std::optional LLVMCasBinaryPath) {
303
306 int FD = -1;
311
314
318
322
323 uint64_t ValidationBootTime = 0;
324 if (!Bytes.empty() &&
325 StringRef(Bytes).trim().getAsInteger(10, ValidationBootTime))
327 "expected integer");
328
329 static uint64_t BootTime = 0;
330 if (BootTime == 0)
332 return std::move(E);
333
334 if (ValidationBootTime == BootTime && !ForceValidation)
336
337
338 bool NeedsRecovery = false;
340 LLVMCasBinaryPath
343 CheckHash)) {
344 if (AllowRecovery) {
346 NeedsRecovery = true;
347 } else {
348 return std::move(E);
349 }
350 }
351
352 if (NeedsRecovery) {
355
356 int LockFD = -1;
363 if (EC == std::errc::no_lock_available)
365 PathBuf, EC,
366 "CAS validation requires exclusive access but CAS was in use");
368 }
370
372 if (!DBDirs)
373 return DBDirs.takeError();
374
375 for (StringRef DBDir : *DBDirs) {
378 std::error_code EC;
379 int Attempt = 0, MaxAttempts = 100;
381 for (; Attempt < MaxAttempts; ++Attempt) {
382 GCPath.assign(RootPath);
384 "." + DBDir);
386
388 break;
389 }
390 if (Attempt == MaxAttempts)
392 EC, "rename " + PathBuf +
393 " failed: too many CAS directories awaiting pruning");
394 if (EC)
395 return createStringError(EC, "rename " + PathBuf + " to " + GCPath +
396 " failed: " + EC.message());
397 }
398 }
399
400 if (ValidationBootTime != BootTime) {
401
407 OS.seek(0);
408 OS << BootTime << '\n';
411 }
412
414}
415
418 StringRef HashName, unsigned HashByteSize,
422
425 int LockFD = -1;
429 assert(LockFD != -1);
430
431
432
433
434 if (std::error_code EC =
437
439 if (!DBDirs)
440 return DBDirs.takeError();
441 if (DBDirs->empty())
443
444 assert(!DBDirs->empty());
445
446
447
448
449
450 auto UniDB = std::unique_ptr(new UnifiedOnDiskCache());
451 std::unique_ptr UpstreamGraphDB;
452 std::unique_ptr UpstreamKVDB;
453 if (DBDirs->size() > 1) {
454 StringRef UpstreamDir = *(DBDirs->end() - 2);
455 PathBuf = RootPath;
458 nullptr, FaultInPolicy)
459 .moveInto(UpstreamGraphDB))
460 return std::move(E);
462 "objectid",
463 sizeof(uint64_t))
464 .moveInto(UpstreamKVDB))
465 return std::move(E);
466 }
467
468 StringRef PrimaryDir = *(DBDirs->end() - 1);
469 PathBuf = RootPath;
471 std::unique_ptr PrimaryGraphDB;
473 UpstreamGraphDB.get(), FaultInPolicy)
474 .moveInto(PrimaryGraphDB))
475 return std::move(E);
476 std::unique_ptr PrimaryKVDB;
477
478
481 "objectid",
482 sizeof(uint64_t), UniDB.get())
483 .moveInto(PrimaryKVDB))
484 return std::move(E);
485
486 UniDB->RootPath = RootPath;
487 UniDB->SizeLimit = SizeLimit.value_or(0);
488 UniDB->LockFD = LockFD;
489 UniDB->NeedsGarbageCollection = DBDirs->size() > 2;
490 UniDB->PrimaryDBDir = PrimaryDir;
491 UniDB->UpstreamGraphDB = std::move(UpstreamGraphDB);
492 UniDB->PrimaryGraphDB = std::move(PrimaryGraphDB);
493 UniDB->UpstreamKVDB = std::move(UpstreamKVDB);
494 UniDB->PrimaryKVDB = std::move(PrimaryKVDB);
495
496 return std::move(UniDB);
497}
498
500 this->SizeLimit = SizeLimit.value_or(0);
501}
502
504 uint64_t TotalSize = getPrimaryStorageSize();
505 if (UpstreamGraphDB)
506 TotalSize += UpstreamGraphDB->getStorageSize();
507 if (UpstreamKVDB)
508 TotalSize += UpstreamKVDB->getStorageSize();
509 return TotalSize;
510}
511
512uint64_t UnifiedOnDiskCache::getPrimaryStorageSize() const {
513 return PrimaryGraphDB->getStorageSize() + PrimaryKVDB->getStorageSize();
514}
515
517 uint64_t CurSizeLimit = SizeLimit;
518 if (!CurSizeLimit)
519 return false;
520
521
522 unsigned CurrentPercent =
523 std::max(PrimaryGraphDB->getHardStorageLimitUtilization(),
524 PrimaryKVDB->getHardStorageLimitUtilization());
525 if (CurrentPercent > 85)
526 return true;
527
528
529
530
531
532
533
534
535
536
537
538 return (CurSizeLimit / 2) < getPrimaryStorageSize();
539}
540
542 if (LockFD == -1)
548 LockFD = -1;
549 });
550
552 UpstreamKVDB.reset();
553 PrimaryKVDB.reset();
554 UpstreamGraphDB.reset();
555 PrimaryGraphDB.reset();
558
559 if (!ExceededSizeLimit)
561
562
563
564
565
569 return Error::success();
571 }
573
574
575
576
577
578
579
580
587
588 NeedsGarbageCollection = true;
590}
591
592UnifiedOnDiskCache::UnifiedOnDiskCache() = default;
593
595
598 if (!DBDirs)
599 return DBDirs.takeError();
600
602 for (StringRef UnusedSubDir : *DBDirs) {
607 }
609}
610
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declaration of the ActionCache class, which is the base class for ActionCache ...
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_UNLIKELY(EXPR)
This declares OnDiskGraphDB, an ondisk CAS database with a fixed length hash.
This declares OnDiskKeyValueDB, a key value storage database of fixed size key and value.
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
This file defines the SmallString class.
This file defines the SmallVector class.
static constexpr StringLiteral DBDirPrefix
FIXME: When the version of DBDirPrefix is bumped up we need to figure out how to handle the leftover ...
Definition UnifiedOnDiskCache.cpp:102
static Error validateInProcess(StringRef RootPath, StringRef HashName, unsigned HashByteSize, bool CheckHash)
Definition UnifiedOnDiskCache.cpp:258
static Expected< SmallVector< std::string, 4 > > getAllGarbageDirs(StringRef Path)
Definition UnifiedOnDiskCache.cpp:186
static constexpr StringLiteral ValidationFilename
Definition UnifiedOnDiskCache.cpp:104
static constexpr StringLiteral CorruptPrefix
Definition UnifiedOnDiskCache.cpp:105
static void getNextDBDirName(StringRef DBDir, llvm::raw_ostream &OS)
Definition UnifiedOnDiskCache.cpp:205
static Error validateOutOfProcess(StringRef LLVMCasBinary, StringRef RootPath, bool CheckHash)
Definition UnifiedOnDiskCache.cpp:214
static Expected< uint64_t > getBootTime()
Definition UnifiedOnDiskCache.cpp:274
static Expected< SmallVector< std::string, 4 > > getAllDBDirs(StringRef Path, bool IncludeCorrupt=false)
Definition UnifiedOnDiskCache.cpp:148
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
FileRemover - This class is a simple object meant to be stack allocated.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void assign(StringRef RHS)
Assign from a StringRef.
StringRef str() const
Explicit conversion to StringRef.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
StringRef - Represent a constant reference to a string, i.e.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
LLVM Value Representation.
static ObjectID fromOpaqueData(uint64_t Opaque)
FaultInPolicy
How to fault-in nodes if an upstream database is used.
static LLVM_ABI_FOR_TEST Expected< std::unique_ptr< OnDiskGraphDB > > open(StringRef Path, StringRef HashName, unsigned HashByteSize, OnDiskGraphDB *UpstreamDB=nullptr, FaultInPolicy Policy=FaultInPolicy::FullTree)
Open the on-disk store from a directory.
static LLVM_ABI_FOR_TEST Expected< std::unique_ptr< OnDiskKeyValueDB > > open(StringRef Path, StringRef HashName, unsigned KeySize, StringRef ValueName, size_t ValueSize, UnifiedOnDiskCache *UnifiedCache=nullptr)
Open the on-disk store from a directory.
LLVM_ABI_FOR_TEST uint64_t getStorageSize() const
Definition UnifiedOnDiskCache.cpp:503
static LLVM_ABI_FOR_TEST ValueBytes getValueFromObjectID(ObjectID ID)
Definition UnifiedOnDiskCache.cpp:114
static LLVM_ABI_FOR_TEST Expected< std::unique_ptr< UnifiedOnDiskCache > > open(StringRef Path, std::optional< uint64_t > SizeLimit, StringRef HashName, unsigned HashByteSize, OnDiskGraphDB::FaultInPolicy FaultInPolicy=OnDiskGraphDB::FaultInPolicy::FullTree)
Open a UnifiedOnDiskCache instance for a directory.
Definition UnifiedOnDiskCache.cpp:417
LLVM_ABI_FOR_TEST Error close(bool CheckSizeLimit=true)
This is called implicitly at destruction time, so it is not required for a client to call this.
Definition UnifiedOnDiskCache.cpp:541
static LLVM_ABI_FOR_TEST ObjectID getObjectIDFromValue(ArrayRef< char > Value)
Helper function to convert the value stored in KeyValueDB and ObjectID.
Definition UnifiedOnDiskCache.cpp:107
static Expected< ValidationResult > validateIfNeeded(StringRef Path, StringRef HashName, unsigned HashByteSize, bool CheckHash, bool AllowRecovery, bool ForceValidation, std::optional< StringRef > LLVMCasBinary)
Validate the data in Path, if needed to ensure correctness.
Definition UnifiedOnDiskCache.cpp:297
LLVM_ABI_FOR_TEST bool hasExceededSizeLimit() const
Definition UnifiedOnDiskCache.cpp:516
LLVM_ABI_FOR_TEST ~UnifiedOnDiskCache()
Definition UnifiedOnDiskCache.cpp:594
std::array< char, sizeof(uint64_t)> ValueBytes
Error collectGarbage()
Remove unused data from the current UnifiedOnDiskCache.
Definition UnifiedOnDiskCache.cpp:611
LLVM_ABI_FOR_TEST void setSizeLimit(std::optional< uint64_t > SizeLimit)
Set the size for limiting growth.
Definition UnifiedOnDiskCache.cpp:499
A raw_ostream that writes to a file descriptor.
bool has_error() const
Return the value of the flag in this raw_fd_ostream indicating whether an output error has been encou...
std::error_code error() const
uint64_t seek(uint64_t off)
Flushes the stream and repositions the underlying file descriptor position to the offset specified fr...
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an SmallVector or SmallString.
directory_iterator - Iterates through the entries in path.
Represents the result of a call to sys::fs::status().
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
std::unique_ptr< ObjectStore > createObjectStoreFromUnifiedOnDiskCache(std::shared_ptr< ondisk::UnifiedOnDiskCache > UniDB)
std::unique_ptr< ActionCache > createActionCacheFromUnifiedOnDiskCache(std::shared_ptr< ondisk::UnifiedOnDiskCache > UniDB)
std::error_code lockFileThreadSafe(int FD, llvm::sys::fs::LockKind Kind)
Thread-safe alternative to sys::fs::lockFile.
std::error_code unlockFileThreadSafe(int FD)
Thread-safe alternative to sys::fs::unlockFile.
std::error_code tryLockFileThreadSafe(int FD, std::chrono::milliseconds Timeout=std::chrono::milliseconds(0), llvm::sys::fs::LockKind Kind=llvm::sys::fs::LockKind::Exclusive)
Thread-safe alternative to sys::fs::tryLockFile.
@ Valid
The data is already valid.
@ Recovered
The data was invalid, but was recovered.
@ Skipped
Validation was skipped, as it was not needed.
uint64_t read64le(const void *P)
void write64le(void *P, uint64_t V)
LLVM_ABI std::error_code closeFile(file_t &F)
Close the file object.
std::error_code openFileForReadWrite(const Twine &Name, int &ResultFD, CreationDisposition Disp, OpenFlags Flags, unsigned Mode=0666)
Opens the file with the given name in a write-only or read-write mode, returning its open file descri...
LLVM_ABI std::error_code rename(const Twine &from, const Twine &to)
Rename from to to.
LLVM_ABI Error readNativeFileToEOF(file_t FileHandle, SmallVectorImpl< char > &Buffer, ssize_t ChunkSize=DefaultReadChunkSize)
Reads from FileHandle until EOF, appending to Buffer in chunks of size ChunkSize.
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
@ CD_OpenAlways
CD_OpenAlways - When opening a file:
LLVM_ABI std::error_code create_directories(const Twine &path, bool IgnoreExisting=true, perms Perms=owner_all|group_all)
Create all the non-existent directories in path.
LLVM_ABI std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, SmallVectorImpl< char > &ResultPath, OpenFlags Flags=OF_None)
Create a file in the system temporary directory.
LLVM_ABI std::error_code resize_file(int FD, uint64_t Size)
Resize path to size.
LLVM_ABI file_t convertFDToNativeFile(int FD)
Converts from a Posix file descriptor number to a native file handle.
LLVM_ABI std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
LLVM_ABI std::error_code create_directory(const Twine &path, bool IgnoreExisting=true, perms Perms=owner_all|group_all)
Create the directory in path.
LLVM_ABI std::error_code remove_directories(const Twine &path, bool IgnoreErrors=true)
Recursively delete a directory.
LLVM_ABI StringRef get_separator(Style style=Style::native)
Return the preferred separator for this platform.
LLVM_ABI void remove_filename(SmallVectorImpl< char > &path, Style style=Style::native)
Remove the last component from path unless it is the root dir.
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
LLVM_ABI int ExecuteAndWait(StringRef Program, ArrayRef< StringRef > Args, std::optional< ArrayRef< StringRef > > Env=std::nullopt, ArrayRef< std::optional< StringRef > > Redirects={}, unsigned SecondsToWait=0, unsigned MemoryLimit=0, std::string *ErrMsg=nullptr, bool *ExecutionFailed=nullptr, std::optional< ProcessStatistics > *ProcStat=nullptr, BitVector *AffinityMask=nullptr)
This function executes the program using the arguments provided.
This is an optimization pass for GlobalISel generic memory operations.
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
detail::scope_exit< std::decay_t< Callable > > make_scope_exit(Callable &&F)
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
testing::Matcher< const detail::ErrorHolder & > Failed()
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
FunctionAddr VTableAddr Count
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
std::string join(IteratorT Begin, IteratorT End, StringRef Separator)
Joins the strings in the range [Begin, End), adding Separator between the elements.
std::error_code errnoAsErrorCode()
Helper to get errno as an std::error_code.
void consumeError(Error Err)
Consume a Error without doing anything.
@ Keep
No function return thunk.