LLVM 22.0.0git
OnDiskCommon.cpp
Go to the documentation of this file.
1//===- OnDiskCommon.cpp ---------------------------------------------------===//
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#include "OnDiskCommon.h"
10#include "llvm/Support/Error.h"
13#include <mutex>
14#include <thread>
15
16#if __has_include(<sys/file.h>)
17#include <sys/file.h>
18#ifdef LOCK_SH
19#define HAVE_FLOCK 1
20#else
21#define HAVE_FLOCK 0
22#endif
23#endif
24
25#if __has_include(<fcntl.h>)
26#include <fcntl.h>
27#endif
28
29#if __has_include(<sys/mount.h>)
30#include <sys/mount.h> // statfs
31#endif
32
33using namespace llvm;
34
36
38 static std::once_flag Flag;
39 Error Err = Error::success();
40 std::call_once(Flag, [&Err] {
41 ErrorAsOutParameter EAO(&Err);
42 constexpr const char *EnvVar = "LLVM_CAS_MAX_MAPPING_SIZE";
43 auto Value = sys::Process::GetEnv(EnvVar);
44 if (!Value)
45 return;
46
48 if (StringRef(*Value).getAsInteger(/*auto*/ 0, Size))
50 "invalid value for %s: expected integer", EnvVar);
52 });
53
54 if (Err)
55 return std::move(Err);
56
58 return std::nullopt;
59
61}
62
66
67std::error_code cas::ondisk::lockFileThreadSafe(int FD,
68 sys::fs::LockKind Kind) {
69#if HAVE_FLOCK
70 if (flock(FD, Kind == sys::fs::LockKind::Exclusive ? LOCK_EX : LOCK_SH) == 0)
71 return std::error_code();
72 return std::error_code(errno, std::generic_category());
73#elif defined(_WIN32)
74 // On Windows this implementation is thread-safe.
75 return sys::fs::lockFile(FD, Kind);
76#else
77 return make_error_code(std::errc::no_lock_available);
78#endif
79}
80
81std::error_code cas::ondisk::unlockFileThreadSafe(int FD) {
82#if HAVE_FLOCK
83 if (flock(FD, LOCK_UN) == 0)
84 return std::error_code();
85 return std::error_code(errno, std::generic_category());
86#elif defined(_WIN32)
87 // On Windows this implementation is thread-safe.
88 return sys::fs::unlockFile(FD);
89#else
90 return make_error_code(std::errc::no_lock_available);
91#endif
92}
93
94std::error_code
95cas::ondisk::tryLockFileThreadSafe(int FD, std::chrono::milliseconds Timeout,
96 sys::fs::LockKind Kind) {
97#if HAVE_FLOCK
98 auto Start = std::chrono::steady_clock::now();
99 auto End = Start + Timeout;
100 do {
101 if (flock(FD, (Kind == sys::fs::LockKind::Exclusive ? LOCK_EX : LOCK_SH) |
102 LOCK_NB) == 0)
103 return std::error_code();
104 int Error = errno;
105 if (Error == EWOULDBLOCK) {
106 // Match sys::fs::tryLockFile, which sleeps for 1 ms per attempt.
107 std::this_thread::sleep_for(std::chrono::milliseconds(1));
108 continue;
109 }
110 return std::error_code(Error, std::generic_category());
111 } while (std::chrono::steady_clock::now() < End);
112 return make_error_code(std::errc::no_lock_available);
113#elif defined(_WIN32)
114 // On Windows this implementation is thread-safe.
115 return sys::fs::tryLockFile(FD, Timeout, Kind);
116#else
117 return make_error_code(std::errc::no_lock_available);
118#endif
119}
120
122 size_t NewSize) {
123 auto CreateError = [&](std::error_code EC) -> Expected<size_t> {
124 if (EC == std::errc::not_supported)
125 // Ignore ENOTSUP in case the filesystem cannot preallocate.
126 return NewSize;
127#if defined(HAVE_POSIX_FALLOCATE)
128 if (EC == std::errc::invalid_argument && CurrentSize < NewSize && // len > 0
129 NewSize < std::numeric_limits<off_t>::max()) // 0 <= offset, len < max
130 // Prior to 2024, POSIX required EINVAL for cases that should be ENOTSUP,
131 // so handle it the same as above if it is not one of the other ways to
132 // get EINVAL.
133 return NewSize;
134#endif
135 return createStringError(EC,
136 "failed to allocate to CAS file: " + EC.message());
137 };
138#if defined(HAVE_POSIX_FALLOCATE)
139 // Note: posix_fallocate returns its error directly, not via errno.
140 if (int Err = posix_fallocate(FD, CurrentSize, NewSize - CurrentSize))
141 return CreateError(std::error_code(Err, std::generic_category()));
142 return NewSize;
143#elif defined(__APPLE__)
144 fstore_t FAlloc;
145 FAlloc.fst_flags = F_ALLOCATEALL;
146#if defined(F_ALLOCATEPERSIST) && \
147 defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
148 __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 130000
149 // F_ALLOCATEPERSIST is introduced in macOS 13.
150 FAlloc.fst_flags |= F_ALLOCATEPERSIST;
151#endif
152 FAlloc.fst_posmode = F_PEOFPOSMODE;
153 FAlloc.fst_offset = 0;
154 FAlloc.fst_length = NewSize - CurrentSize;
155 FAlloc.fst_bytesalloc = 0;
156 if (fcntl(FD, F_PREALLOCATE, &FAlloc))
157 return CreateError(errnoAsErrorCode());
158 assert(CurrentSize + FAlloc.fst_bytesalloc >= NewSize);
159 return CurrentSize + FAlloc.fst_bytesalloc;
160#else
161 (void)CreateError; // Silence unused variable.
162 return NewSize; // Pretend it worked.
163#endif
164}
165
167 // Add exceptions to use small database file here.
168#if defined(__APPLE__) && __has_include(<sys/mount.h>)
169 // macOS tmpfs does not support sparse tails.
170 SmallString<128> PathStorage;
171 StringRef Path = P.toNullTerminatedStringRef(PathStorage);
172 struct statfs StatFS;
173 if (statfs(Path.data(), &StatFS) != 0)
174 return false;
175
176 if (strcmp(StatFS.f_fstypename, "tmpfs") == 0)
177 return true;
178#endif
179 // Default to use regular database file.
180 return false;
181}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static uint64_t OnDiskCASMaxMappingSize
#define P(N)
Provides a library for accessing information about this process and other processes on the operating ...
Helper for Errors used as out-parameters.
Definition Error.h:1144
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
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
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
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
LLVM Value Representation.
Definition Value.h:75
static LLVM_ABI std::optional< std::string > GetEnv(StringRef name)
void setMaxMappingSize(uint64_t Size)
Set MaxMappingSize for ondisk CAS.
Expected< std::optional< uint64_t > > getOverriddenMaxMappingSize()
Retrieves an overridden maximum mapping size for CAS files, if any, speicified by LLVM_CAS_MAX_MAPPIN...
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< size_t > preallocateFileTail(int FD, size_t CurrentSize, size_t NewSize)
Allocate space for the file FD on disk, if the filesystem supports it.
bool useSmallMappingSize(const Twine &Path)
Whether to use a small file mapping for ondisk databases created in Path.
LLVM_ABI std::error_code lockFile(int FD, LockKind Kind=LockKind::Exclusive)
Lock the file.
LLVM_ABI std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout=std::chrono::milliseconds(0), LockKind Kind=LockKind::Exclusive)
Try to locks the file during the specified time.
LockKind
An enumeration for the lock kind.
LLVM_ABI std::error_code unlockFile(int FD)
Unlock the file.
This is an optimization pass for GlobalISel generic memory operations.
std::error_code make_error_code(BitcodeError E)
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:98
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1305
@ Timeout
Reached timeout while waiting for the owner to release the lock.
std::error_code errnoAsErrorCode()
Helper to get errno as an std::error_code.
Definition Error.h:1240