LLVM 23.0.0git
UnifiedOnDiskCache.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//
9/// \file
10/// Encapsulates \p OnDiskGraphDB and \p OnDiskKeyValueDB instances within one
11/// directory while also restricting storage growth with a scheme of chaining
12/// the two most recent directories (primary & upstream), where the primary
13/// "faults-in" data from the upstream one. When the primary (most recent)
14/// directory exceeds its intended limit a new empty directory becomes the
15/// primary one.
16///
17/// Within the top-level directory (the path that \p UnifiedOnDiskCache::open
18/// receives) there are directories named like this:
19///
20/// 'v<version>.<x>'
21/// 'v<version>.<x+1>'
22/// 'v<version>.<x+2>'
23/// ...
24///
25/// 'version' is the version integer for this \p UnifiedOnDiskCache's scheme and
26/// the part after the dot is an increasing integer. The primary directory is
27/// the one with the highest integer and the upstream one is the directory
28/// before it. For example, if the sub-directories contained are:
29///
30/// 'v1.5', 'v1.6', 'v1.7', 'v1.8'
31///
32/// Then the primary one is 'v1.8', the upstream one is 'v1.7', and the rest are
33/// unused directories that can be safely deleted at any time and by any
34/// process.
35///
36/// Contained within the top-level directory is a file named "lock" which is
37/// used for processes to take shared or exclusive locks for the contents of the
38/// top directory. While a \p UnifiedOnDiskCache is open it keeps a shared lock
39/// for the top-level directory; when it closes, if the primary sub-directory
40/// exceeded its limit, it attempts to get an exclusive lock in order to create
41/// a new empty primary directory; if it can't get the exclusive lock it gives
42/// up and lets the next \p UnifiedOnDiskCache instance that closes to attempt
43/// again.
44///
45/// The downside of this scheme is that while \p UnifiedOnDiskCache is open on a
46/// directory, by any process, the storage size in that directory will keep
47/// growing unrestricted. But the major benefit is that garbage-collection can
48/// be triggered on a directory concurrently, at any time and by any process,
49/// without affecting any active readers/writers in the same process or other
50/// processes.
51///
52/// The \c UnifiedOnDiskCache also provides validation and recovery on top of
53/// the underlying on-disk storage. The low-level storage is designed to remain
54/// coherent across regular process crashes, but may be invalid after power loss
55/// or similar system failures. \c UnifiedOnDiskCache::validateIfNeeded allows
56/// validating the contents once per boot and can recover by marking invalid
57/// data for garbage collection.
58///
59/// The data recovery described above requires exclusive access to the CAS, and
60/// it is an error to attempt recovery if the CAS is open in any process/thread.
61/// In order to maximize backwards compatibility with tools that do not perform
62/// validation before opening the CAS, we do not attempt to get exclusive access
63/// until recovery is actually performed, meaning as long as the data is valid
64/// it will not conflict with concurrent use.
65//
66//===----------------------------------------------------------------------===//
67
69#include "OnDiskCommon.h"
70#include "llvm/ADT/STLExtras.h"
71#include "llvm/ADT/ScopeExit.h"
75#include "llvm/ADT/StringRef.h"
80#include "llvm/Support/Errc.h"
81#include "llvm/Support/Error.h"
86#include "llvm/Support/Path.h"
89#include <optional>
90
91using namespace llvm;
92using namespace llvm::cas;
93using namespace llvm::cas::ondisk;
94
95/// FIXME: When the version of \p DBDirPrefix is bumped up we need to figure out
96/// how to handle the leftover sub-directories of the previous version, within
97/// the \p UnifiedOnDiskCache::collectGarbage function.
98static constexpr StringLiteral DBDirPrefix = "v1.";
99
100static constexpr StringLiteral ValidationFilename = "v1.validation";
101static constexpr StringLiteral CorruptPrefix = "corrupt.";
102
108
111 // little endian encoded.
113 static_assert(ValBytes.size() == sizeof(ID.getOpaqueData()));
114 support::endian::write64le(ValBytes.data(), ID.getOpaqueData());
115 return ValBytes;
116}
117
119UnifiedOnDiskCache::faultInFromUpstreamKV(ArrayRef<uint8_t> Key) {
120 assert(UpstreamGraphDB);
121 assert(UpstreamKVDB);
122
123 std::optional<ArrayRef<char>> UpstreamValue;
124 if (Error E = UpstreamKVDB->get(Key).moveInto(UpstreamValue))
125 return std::move(E);
126 if (!UpstreamValue)
127 return std::nullopt;
128
129 // The value is the \p ObjectID in the context of the upstream
130 // \p OnDiskGraphDB instance. Translate it to the context of the primary
131 // \p OnDiskGraphDB instance.
132 ObjectID UpstreamID = getObjectIDFromValue(*UpstreamValue);
133 auto PrimaryID =
134 PrimaryGraphDB->getReference(UpstreamGraphDB->getDigest(UpstreamID));
135 if (LLVM_UNLIKELY(!PrimaryID))
136 return PrimaryID.takeError();
137 return PrimaryKVDB->put(Key, getValueFromObjectID(*PrimaryID));
138}
139
140/// \returns all the 'v<version>.<x>' names of sub-directories, sorted with
141/// ascending order of the integer after the dot. Corrupt directories, if
142/// included, will come first.
144getAllDBDirs(StringRef Path, bool IncludeCorrupt = false) {
145 struct DBDir {
146 uint64_t Order;
147 std::string Name;
148 };
149 SmallVector<DBDir> FoundDBDirs;
150
151 std::error_code EC;
152 for (sys::fs::directory_iterator DirI(Path, EC), DirE; !EC && DirI != DirE;
153 DirI.increment(EC)) {
154 if (DirI->type() != sys::fs::file_type::directory_file)
155 continue;
156 StringRef SubDir = sys::path::filename(DirI->path());
157 if (IncludeCorrupt && SubDir.starts_with(CorruptPrefix)) {
158 FoundDBDirs.push_back({0, std::string(SubDir)});
159 continue;
160 }
161 if (!SubDir.starts_with(DBDirPrefix))
162 continue;
163 uint64_t Order;
164 if (SubDir.substr(DBDirPrefix.size()).getAsInteger(10, Order))
166 "unexpected directory " + DirI->path());
167 FoundDBDirs.push_back({Order, std::string(SubDir)});
168 }
169 if (EC)
170 return createFileError(Path, EC);
171
172 llvm::sort(FoundDBDirs, [](const DBDir &LHS, const DBDir &RHS) -> bool {
173 return LHS.Order < RHS.Order;
174 });
175
177 for (DBDir &Dir : FoundDBDirs)
178 DBDirs.push_back(std::move(Dir.Name));
179 return DBDirs;
180}
181
183 auto DBDirs = getAllDBDirs(Path, /*IncludeCorrupt=*/true);
184 if (!DBDirs)
185 return DBDirs.takeError();
186
187 // FIXME: When the version of \p DBDirPrefix is bumped up we need to figure
188 // out how to handle the leftover sub-directories of the previous version.
189
190 for (unsigned Keep = 2; Keep > 0 && !DBDirs->empty(); --Keep) {
191 StringRef Back(DBDirs->back());
192 if (Back.starts_with(CorruptPrefix))
193 break;
194 DBDirs->pop_back();
195 }
196 return *DBDirs;
197}
198
199/// \returns Given a sub-directory named 'v<version>.<x>', it outputs the
200/// 'v<version>.<x+1>' name.
204 bool Failed = DBDir.substr(DBDirPrefix.size()).getAsInteger(10, Count);
205 assert(!Failed);
206 (void)Failed;
207 OS << DBDirPrefix << Count + 1;
208}
209
210static Error validateOutOfProcess(StringRef LLVMCasBinary, StringRef RootPath,
211 bool CheckHash) {
212 SmallVector<StringRef> Args{LLVMCasBinary, "-cas", RootPath, "-validate"};
213 if (CheckHash)
214 Args.push_back("-check-hash");
215
216 llvm::SmallString<128> StdErrPath;
217 int StdErrFD = -1;
218 if (std::error_code EC = sys::fs::createTemporaryFile(
219 "llvm-cas-validate-stderr", "txt", StdErrFD, StdErrPath,
221 return createStringError(EC, "failed to create temporary file");
222 FileRemover OutputRemover(StdErrPath.c_str());
223
224 std::optional<llvm::StringRef> Redirects[] = {
225 {""}, // stdin = /dev/null
226 {""}, // stdout = /dev/null
227 StdErrPath.str(),
228 };
229
230 std::string ErrMsg;
231 int Result =
232 sys::ExecuteAndWait(LLVMCasBinary, Args, /*Env=*/std::nullopt, Redirects,
233 /*SecondsToWait=*/120, /*MemoryLimit=*/0, &ErrMsg);
234
235 if (Result == -1)
236 return createStringError("failed to exec " + join(Args, " ") + ": " +
237 ErrMsg);
238 if (Result != 0) {
239 llvm::SmallString<64> Err("cas contents invalid");
240 if (!ErrMsg.empty()) {
241 Err += ": ";
242 Err += ErrMsg;
243 }
244 auto StdErrBuf = MemoryBuffer::getFile(StdErrPath.c_str());
245 if (StdErrBuf && !(*StdErrBuf)->getBuffer().empty()) {
246 Err += ": ";
247 Err += (*StdErrBuf)->getBuffer();
248 }
249 return createStringError(Err);
250 }
251 return Error::success();
252}
253
255 auto ValidateRef = [this](FileOffset Offset, ArrayRef<char> Value) -> Error {
257 auto formatError = [&](Twine Msg) {
258 return createStringError(
260 "bad record at 0x" +
261 utohexstr((unsigned)Offset.get(), /*LowerCase=*/true) + ": " +
262 Msg.str());
263 };
264 if (Error E = this->getGraphDB().validateObjectID(ID))
265 return formatError(llvm::toString(std::move(E)));
266 return Error::success();
267 };
268 return getKeyValueDB().validate(ValidateRef);
269}
270
271static Error validateInProcess(StringRef RootPath, StringRef HashName,
272 unsigned HashByteSize, bool CheckHash,
274 std::shared_ptr<UnifiedOnDiskCache> UniDB;
275 if (Error E = UnifiedOnDiskCache::open(RootPath, std::nullopt, HashName,
276 HashByteSize)
277 .moveInto(UniDB))
278 return E;
279 if (Error E = UniDB->getGraphDB().validate(CheckHash, HashFn))
280 return E;
281 if (Error E = UniDB->validateActionCache())
282 return E;
283 return Error::success();
284}
285
287 StringRef RootPath, StringRef HashName, unsigned HashByteSize,
288 bool CheckHash, OnDiskGraphDB::HashingFuncT HashFn, bool AllowRecovery,
289 bool ForceValidation, std::optional<StringRef> LLVMCasBinaryPath) {
290 if (std::error_code EC = sys::fs::create_directories(RootPath))
291 return createFileError(RootPath, EC);
292
293 SmallString<256> PathBuf(RootPath);
295 int FD = -1;
296 if (std::error_code EC = sys::fs::openFileForReadWrite(
298 return createFileError(PathBuf, EC);
299 assert(FD != -1);
300
302 llvm::scope_exit CloseFile([&]() { sys::fs::closeFile(File); });
303
304 if (std::error_code EC = lockFileThreadSafe(FD, sys::fs::LockKind::Exclusive))
305 return createFileError(PathBuf, EC);
306 llvm::scope_exit UnlockFD([&]() { unlockFileThreadSafe(FD); });
307
308 std::shared_ptr<ondisk::OnDiskCASLogger> Logger;
309#ifndef _WIN32
310 if (Error E =
311 ondisk::OnDiskCASLogger::openIfEnabled(RootPath).moveInto(Logger))
312 return std::move(E);
313#endif
314
315 SmallString<8> Bytes;
316 if (Error E = sys::fs::readNativeFileToEOF(File, Bytes))
317 return createFileError(PathBuf, std::move(E));
318
319 uint64_t ValidationBootTime = 0;
320 if (!Bytes.empty() &&
321 StringRef(Bytes).trim().getAsInteger(10, ValidationBootTime))
323 "expected integer");
324
325 static uint64_t BootTime = 0;
326 if (BootTime == 0)
327 if (Error E = getBootTime().moveInto(BootTime))
328 return std::move(E);
329
330 bool Recovered = false;
331 bool Skipped = false;
332 std::string LogValidationError;
333
334 llvm::scope_exit Log([&] {
335 if (!Logger)
336 return;
337 Logger->logUnifiedOnDiskCacheValidateIfNeeded(
338 RootPath, BootTime, ValidationBootTime, CheckHash, AllowRecovery,
339 ForceValidation, LLVMCasBinaryPath, LogValidationError, Skipped,
340 Recovered);
341 });
342
343 if (ValidationBootTime == BootTime && !ForceValidation) {
344 Skipped = true;
346 }
347
348 // Validate!
349 bool NeedsRecovery = false;
350 Error E = LLVMCasBinaryPath
351 ? validateOutOfProcess(*LLVMCasBinaryPath, RootPath, CheckHash)
352 : validateInProcess(RootPath, HashName, HashByteSize, CheckHash,
353 HashFn);
354 if (E) {
355 if (Logger)
356 LogValidationError = toStringWithoutConsuming(E);
357 if (AllowRecovery) {
358 consumeError(std::move(E));
359 NeedsRecovery = true;
360 } else {
361 return std::move(E);
362 }
363 }
364
365 if (NeedsRecovery) {
367 sys::path::append(PathBuf, "lock");
368
369 int LockFD = -1;
370 if (std::error_code EC = sys::fs::openFileForReadWrite(
371 PathBuf, LockFD, sys::fs::CD_OpenAlways, sys::fs::OF_None))
372 return createFileError(PathBuf, EC);
374 llvm::scope_exit CloseLock([&]() { sys::fs::closeFile(LockFile); });
375 if (std::error_code EC = tryLockFileThreadSafe(LockFD)) {
376 if (EC == std::errc::no_lock_available)
377 return createFileError(
378 PathBuf, EC,
379 "CAS validation requires exclusive access but CAS was in use");
380 return createFileError(PathBuf, EC);
381 }
382 llvm::scope_exit UnlockFD([&]() { unlockFileThreadSafe(LockFD); });
383
384 auto DBDirs = getAllDBDirs(RootPath);
385 if (!DBDirs)
386 return DBDirs.takeError();
387
388 for (StringRef DBDir : *DBDirs) {
390 sys::path::append(PathBuf, DBDir);
391 std::error_code EC;
392 int Attempt = 0, MaxAttempts = 100;
393 SmallString<128> GCPath;
394 for (; Attempt < MaxAttempts; ++Attempt) {
395 GCPath.assign(RootPath);
396 sys::path::append(GCPath, CorruptPrefix + std::to_string(Attempt) +
397 "." + DBDir);
398 EC = sys::fs::rename(PathBuf, GCPath);
399 // Darwin uses ENOTEMPTY. Linux may return either ENOTEMPTY or EEXIST.
401 break;
402 }
403 if (Attempt == MaxAttempts)
404 return createStringError(
405 EC, "rename " + PathBuf +
406 " failed: too many CAS directories awaiting pruning");
407 if (EC)
408 return createStringError(EC, "rename " + PathBuf + " to " + GCPath +
409 " failed: " + EC.message());
410 }
411 Recovered = true;
412 }
413
414 if (ValidationBootTime != BootTime) {
415 // Fix filename in case we have error to report.
418 if (std::error_code EC = sys::fs::resize_file(FD, 0))
419 return createFileError(PathBuf, EC);
420 raw_fd_ostream OS(FD, /*shouldClose=*/false);
421 OS.seek(0); // resize does not reset position
422 OS << BootTime << '\n';
423 if (OS.has_error())
424 return createFileError(PathBuf, OS.error());
425 }
426
428}
429
431UnifiedOnDiskCache::open(StringRef RootPath, std::optional<uint64_t> SizeLimit,
432 StringRef HashName, unsigned HashByteSize,
433 OnDiskGraphDB::FaultInPolicy FaultInPolicy) {
434 auto BypassSandbox = sys::sandbox::scopedDisable();
435
436 if (std::error_code EC = sys::fs::create_directories(RootPath))
437 return createFileError(RootPath, EC);
438
439 SmallString<256> PathBuf(RootPath);
440 sys::path::append(PathBuf, "lock");
441 int LockFD = -1;
442 if (std::error_code EC = sys::fs::openFileForReadWrite(
443 PathBuf, LockFD, sys::fs::CD_OpenAlways, sys::fs::OF_None))
444 return createFileError(PathBuf, EC);
445 assert(LockFD != -1);
446 // Locking the directory using shared lock, which will prevent other processes
447 // from creating a new chain (essentially while a \p UnifiedOnDiskCache
448 // instance holds a shared lock the storage for the primary directory will
449 // grow unrestricted).
450 if (std::error_code EC =
452 return createFileError(PathBuf, EC);
453
454 auto DBDirs = getAllDBDirs(RootPath);
455 if (!DBDirs)
456 return DBDirs.takeError();
457 if (DBDirs->empty())
458 DBDirs->push_back((Twine(DBDirPrefix) + "1").str());
459
460 std::shared_ptr<ondisk::OnDiskCASLogger> Logger;
461#ifndef _WIN32
462 if (Error E =
463 ondisk::OnDiskCASLogger::openIfEnabled(RootPath).moveInto(Logger))
464 return std::move(E);
465#endif
466
467 /// If there is only one directory open databases on it. If there are 2 or
468 /// more directories, get the most recent directories and chain them, with the
469 /// most recent being the primary one. The remaining directories are unused
470 /// data than can be garbage-collected.
471 auto UniDB = std::unique_ptr<UnifiedOnDiskCache>(new UnifiedOnDiskCache());
472 std::unique_ptr<OnDiskGraphDB> UpstreamGraphDB;
473 std::unique_ptr<OnDiskKeyValueDB> UpstreamKVDB;
474 if (DBDirs->size() > 1) {
475 StringRef UpstreamDir = *(DBDirs->end() - 2);
476 PathBuf = RootPath;
477 sys::path::append(PathBuf, UpstreamDir);
478 if (Error E =
479 OnDiskGraphDB::open(PathBuf, HashName, HashByteSize,
480 /*UpstreamDB=*/nullptr, Logger, FaultInPolicy)
481 .moveInto(UpstreamGraphDB))
482 return std::move(E);
483 if (Error E = OnDiskKeyValueDB::open(PathBuf, HashName, HashByteSize,
484 /*ValueName=*/"objectid",
485 /*ValueSize=*/sizeof(uint64_t),
486 /*UnifiedCache=*/nullptr, Logger)
487 .moveInto(UpstreamKVDB))
488 return std::move(E);
489 }
490
491 StringRef PrimaryDir = *(DBDirs->end() - 1);
492 PathBuf = RootPath;
493 sys::path::append(PathBuf, PrimaryDir);
494 std::unique_ptr<OnDiskGraphDB> PrimaryGraphDB;
495 if (Error E =
496 OnDiskGraphDB::open(PathBuf, HashName, HashByteSize,
497 UpstreamGraphDB.get(), Logger, FaultInPolicy)
498 .moveInto(PrimaryGraphDB))
499 return std::move(E);
500 std::unique_ptr<OnDiskKeyValueDB> PrimaryKVDB;
501 // \p UnifiedOnDiskCache does manual chaining for key-value requests,
502 // including an extra translation step of the value during fault-in.
503 if (Error E = OnDiskKeyValueDB::open(PathBuf, HashName, HashByteSize,
504 /*ValueName=*/"objectid",
505 /*ValueSize=*/sizeof(uint64_t),
506 UniDB.get(), Logger)
507 .moveInto(PrimaryKVDB))
508 return std::move(E);
509
510 UniDB->RootPath = RootPath;
511 UniDB->SizeLimit = SizeLimit.value_or(0);
512 UniDB->LockFD = LockFD;
513 UniDB->NeedsGarbageCollection = DBDirs->size() > 2;
514 UniDB->PrimaryDBDir = PrimaryDir;
515 UniDB->UpstreamGraphDB = std::move(UpstreamGraphDB);
516 UniDB->PrimaryGraphDB = std::move(PrimaryGraphDB);
517 UniDB->UpstreamKVDB = std::move(UpstreamKVDB);
518 UniDB->PrimaryKVDB = std::move(PrimaryKVDB);
519 UniDB->Logger = std::move(Logger);
520
521 return std::move(UniDB);
522}
523
524void UnifiedOnDiskCache::setSizeLimit(std::optional<uint64_t> SizeLimit) {
525 this->SizeLimit = SizeLimit.value_or(0);
526}
527
529 uint64_t TotalSize = getPrimaryStorageSize();
530 if (UpstreamGraphDB)
531 TotalSize += UpstreamGraphDB->getStorageSize();
532 if (UpstreamKVDB)
533 TotalSize += UpstreamKVDB->getStorageSize();
534 return TotalSize;
535}
536
537uint64_t UnifiedOnDiskCache::getPrimaryStorageSize() const {
538 return PrimaryGraphDB->getStorageSize() + PrimaryKVDB->getStorageSize();
539}
540
542 uint64_t CurSizeLimit = SizeLimit;
543 if (!CurSizeLimit)
544 return false;
545
546 // If the hard limit is beyond 85%, declare above limit and request clean up.
547 unsigned CurrentPercent =
548 std::max(PrimaryGraphDB->getHardStorageLimitUtilization(),
549 PrimaryKVDB->getHardStorageLimitUtilization());
550 if (CurrentPercent > 85)
551 return true;
552
553 // We allow each of the directories in the chain to reach up to half the
554 // intended size limit. Check whether the primary directory has exceeded half
555 // the limit or not, in order to decide whether we need to start a new chain.
556 //
557 // We could check the size limit against the sum of sizes of both the primary
558 // and upstream directories but then if the upstream is significantly larger
559 // than the intended limit, it would trigger a new chain to be created before
560 // the primary has reached its own limit. Essentially in such situation we
561 // prefer reclaiming the storage later in order to have more consistent cache
562 // hits behavior.
563 return (CurSizeLimit / 2) < getPrimaryStorageSize();
564}
565
566Error UnifiedOnDiskCache::close(bool CheckSizeLimit) {
567 auto BypassSandbox = sys::sandbox::scopedDisable();
568
569 if (LockFD == -1)
570 return Error::success(); // already closed.
571 llvm::scope_exit CloseLock([&]() {
572 assert(LockFD >= 0);
574 sys::fs::closeFile(LockFile);
575 LockFD = -1;
576 });
577
578 bool ExceededSizeLimit = CheckSizeLimit ? hasExceededSizeLimit() : false;
579 UpstreamKVDB.reset();
580 PrimaryKVDB.reset();
581 UpstreamGraphDB.reset();
582 PrimaryGraphDB.reset();
583 if (std::error_code EC = unlockFileThreadSafe(LockFD))
584 return createFileError(RootPath, EC);
585
586 if (!ExceededSizeLimit)
587 return Error::success();
588
589 // The primary directory exceeded its intended size limit. Try to get an
590 // exclusive lock in order to create a new primary directory for next time
591 // this \p UnifiedOnDiskCache path is opened.
592
593 if (std::error_code EC = tryLockFileThreadSafe(
594 LockFD, std::chrono::milliseconds(0), sys::fs::LockKind::Exclusive)) {
595 if (EC == errc::no_lock_available)
596 return Error::success(); // couldn't get exclusive lock, give up.
597 return createFileError(RootPath, EC);
598 }
599 llvm::scope_exit UnlockFile([&]() { unlockFileThreadSafe(LockFD); });
600
601 // Managed to get an exclusive lock which means there are no other open
602 // \p UnifiedOnDiskCache instances for the same path, so we can safely start a
603 // new primary directory. To start a new primary directory we just have to
604 // create a new empty directory with the next consecutive index; since this is
605 // an atomic operation we will leave the top-level directory in a consistent
606 // state even if the process dies during this code-path.
607
608 SmallString<256> PathBuf(RootPath);
609 raw_svector_ostream OS(PathBuf);
611 getNextDBDirName(PrimaryDBDir, OS);
612 if (std::error_code EC = sys::fs::create_directory(PathBuf))
613 return createFileError(PathBuf, EC);
614
615 NeedsGarbageCollection = true;
616 return Error::success();
617}
618
619UnifiedOnDiskCache::UnifiedOnDiskCache() = default;
620
622
624 ondisk::OnDiskCASLogger *Logger) {
625 auto DBDirs = getAllGarbageDirs(Path);
626 if (!DBDirs)
627 return DBDirs.takeError();
628
629 SmallString<256> PathBuf(Path);
630 for (StringRef UnusedSubDir : *DBDirs) {
631 sys::path::append(PathBuf, UnusedSubDir);
632 if (Logger)
633 Logger->logUnifiedOnDiskCacheCollectGarbage(PathBuf);
634 if (std::error_code EC = sys::fs::remove_directories(PathBuf))
635 return createFileError(PathBuf, EC);
637 }
638 return Error::success();
639}
640
642 return collectGarbage(RootPath, Logger.get());
643}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_UNLIKELY(EXPR)
Definition Compiler.h:336
This file declares interface for OnDiskCASLogger, an interface that can be used to log CAS events to ...
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 contains some templates that are useful if you are working with the STL at all.
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.
This file contains some functions that are useful when dealing with strings.
static Error validateInProcess(StringRef RootPath, StringRef HashName, unsigned HashByteSize, bool CheckHash, OnDiskGraphDB::HashingFuncT HashFn)
static constexpr StringLiteral DBDirPrefix
FIXME: When the version of DBDirPrefix is bumped up we need to figure out how to handle the leftover ...
static Expected< SmallVector< std::string, 4 > > getAllGarbageDirs(StringRef Path)
static constexpr StringLiteral ValidationFilename
static constexpr StringLiteral CorruptPrefix
static void getNextDBDirName(StringRef DBDir, llvm::raw_ostream &OS)
static Error validateOutOfProcess(StringRef LLVMCasBinary, StringRef RootPath, bool CheckHash)
static Expected< SmallVector< std::string, 4 > > getAllDBDirs(StringRef Path, bool IncludeCorrupt=false)
Value * RHS
Value * LHS
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
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...
Definition SmallString.h:26
void assign(StringRef RHS)
Assign from a StringRef.
Definition SmallString.h:51
const char * c_str()
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...
Definition StringRef.h:864
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition StringRef.h:472
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition StringRef.h:573
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:261
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
LLVM Value Representation.
Definition Value.h:75
FileOffset is a wrapper around uint64_t to represent the offset of data from the beginning of the fil...
Definition FileOffset.h:24
Reference to a node.
static ObjectID fromOpaqueData(uint64_t Opaque)
Interface for logging low-level on-disk cas operations.
static LLVM_ABI Expected< std::unique_ptr< OnDiskCASLogger > > openIfEnabled(const Twine &Path)
Create or append to a log file inside the given CAS directory Path if logging is enabled by the envir...
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, std::shared_ptr< OnDiskCASLogger > Logger=nullptr, FaultInPolicy Policy=FaultInPolicy::FullTree)
Open the on-disk store from a directory.
function_ref< void( ArrayRef< ArrayRef< uint8_t > >, ArrayRef< char >, SmallVectorImpl< uint8_t > &)> HashingFuncT
Hashing function type for validation.
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, std::shared_ptr< OnDiskCASLogger > Logger=nullptr)
Open the on-disk store from a directory.
LLVM_ABI_FOR_TEST Error validate(CheckValueT CheckValue) const
Validate the storage with a callback CheckValue to check the stored value.
OnDiskGraphDB & getGraphDB()
The OnDiskGraphDB instance for the open directory.
LLVM_ABI_FOR_TEST uint64_t getStorageSize() const
static LLVM_ABI_FOR_TEST ValueBytes getValueFromObjectID(ObjectID ID)
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.
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.
LLVM_ABI_FOR_TEST Error validateActionCache() const
Validate the action cache only.
static LLVM_ABI_FOR_TEST ObjectID getObjectIDFromValue(ArrayRef< char > Value)
Helper function to convert the value stored in KeyValueDB and ObjectID.
static Expected< ValidationResult > validateIfNeeded(StringRef Path, StringRef HashName, unsigned HashByteSize, bool CheckHash, OnDiskGraphDB::HashingFuncT HashFn, bool AllowRecovery, bool ForceValidation, std::optional< StringRef > LLVMCasBinary)
Validate the data in Path, if needed to ensure correctness.
LLVM_ABI_FOR_TEST bool hasExceededSizeLimit() const
OnDiskKeyValueDB & getKeyValueDB()
The OnDiskGraphDB instance for the open directory.
std::array< char, sizeof(uint64_t)> ValueBytes
Error collectGarbage()
Remove unused data from the current UnifiedOnDiskCache.
LLVM_ABI_FOR_TEST void setSizeLimit(std::optional< uint64_t > SizeLimit)
Set the size for limiting growth.
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.
Definition raw_ostream.h:53
A raw_ostream that writes to an SmallVector or SmallString.
directory_iterator - Iterates through the entries in path.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
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.
Expected< uint64_t > getBootTime()
Get boot time for the OS.
@ 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)
Definition Endian.h:435
void write64le(void *P, uint64_t V)
Definition Endian.h:478
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.
Definition Path.cpp:1197
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
Definition FileSystem.h:755
@ CD_OpenAlways
CD_OpenAlways - When opening a file:
Definition FileSystem.h:742
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.
Definition Path.cpp:976
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.
Definition Path.cpp:919
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.
Definition FileSystem.h:991
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.
Definition Path.cpp:610
LLVM_ABI void remove_filename(SmallVectorImpl< char > &path, Style style=Style::native)
Remove the last component from path unless it is the root dir.
Definition Path.cpp:475
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
Definition Path.cpp:578
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition Path.cpp:457
ScopedSetting scopedDisable()
Definition IOSandbox.h:36
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.
Definition Program.cpp:32
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
@ Offset
Definition DWP.cpp:532
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
Definition Error.h:1399
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:94
testing::Matcher< const detail::ErrorHolder & > Failed()
Definition Error.h:198
std::string utohexstr(uint64_t X, bool LowerCase=false, unsigned Width=0)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1305
@ file_exists
Definition Errc.h:48
@ illegal_byte_sequence
Definition Errc.h:52
@ no_lock_available
Definition Errc.h:61
@ directory_not_empty
Definition Errc.h:46
LLVM_ABI std::string toStringWithoutConsuming(const Error &E)
Like toString(), but does not consume the error.
Definition Error.cpp:81
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1634
FunctionAddr VTableAddr Count
Definition InstrProf.h:139
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::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1083
@ Keep
No function return thunk.
Definition CodeGen.h:162