LLVM 24.0.0git
OnDiskCAS.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#include "BuiltinCAS.h"
10#include "OnDiskCommon.h"
11#include "llvm/ADT/ScopeExit.h"
18#include "llvm/Support/Error.h"
21#include "llvm/Support/Path.h"
22
23using namespace llvm;
24using namespace llvm::cas;
25using namespace llvm::cas::builtin;
26
27namespace {
28
29class OnDiskCAS : public BuiltinCAS {
30public:
31 Expected<ObjectRef> storeImpl(ArrayRef<uint8_t> ComputedHash,
33 ArrayRef<char> Data) final;
34
35 Expected<std::optional<ObjectHandle>> loadIfExists(ObjectRef Ref) final;
36
37 CASID getID(ObjectRef Ref) const final;
38
39 std::optional<ObjectRef> getReference(const CASID &ID) const final;
40
41 Expected<bool> isMaterialized(ObjectRef Ref) const final;
42
43 ArrayRef<char> getDataConst(ObjectHandle Node) const final;
44
45 Expected<ObjectRef> storeFromFile(StringRef Path) final;
46
47 Error exportDataToFile(ObjectHandle Node, StringRef Path) const final;
48
49 std::unique_ptr<MemoryBuffer>
50 getStandaloneMemoryBufferImpl(ObjectHandle Node, StringRef Name,
51 bool RequiresNullTerminator) final;
52
53 void print(raw_ostream &OS) const final;
54 Error validate(bool CheckHash) const final;
55
56 static Expected<std::unique_ptr<OnDiskCAS>> open(StringRef Path);
57
58 OnDiskCAS(std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB)
59 : UnifiedDB(std::move(UniDB)), DB(&UnifiedDB->getGraphDB()) {}
60
61private:
62 ObjectHandle convertHandle(ondisk::ObjectHandle Node) const {
63 return makeObjectHandle(Node.getOpaqueData());
64 }
65
66 ondisk::ObjectHandle convertHandle(ObjectHandle Node) const {
67 return ondisk::ObjectHandle(Node.getInternalRef(*this));
68 }
69
70 ObjectRef convertRef(ondisk::ObjectID Ref) const {
71 return makeObjectRef(Ref.getOpaqueData());
72 }
73
74 ondisk::ObjectID convertRef(ObjectRef Ref) const {
75 return ondisk::ObjectID::fromOpaqueData(Ref.getInternalRef(*this));
76 }
77
78 size_t getNumRefs(ObjectHandle Node) const final {
79 auto RefsRange = DB->getObjectRefs(convertHandle(Node));
80 return llvm::size(RefsRange);
81 }
82
83 ObjectRef readRef(ObjectHandle Node, size_t I) const final {
84 auto RefsRange = DB->getObjectRefs(convertHandle(Node));
85 return convertRef(RefsRange.begin()[I]);
86 }
87
88 Error forEachRef(ObjectHandle Node,
89 function_ref<Error(ObjectRef)> Callback) const final;
90
91 Error setSizeLimit(std::optional<uint64_t> SizeLimit) final;
92 Expected<std::optional<uint64_t>> getStorageSize() const final;
93 Error pruneStorageData() final;
94
95 OnDiskCAS(std::unique_ptr<ondisk::OnDiskGraphDB> GraphDB)
96 : OwnedDB(std::move(GraphDB)), DB(OwnedDB.get()) {}
97
98 std::unique_ptr<ondisk::OnDiskGraphDB> OwnedDB;
99 std::shared_ptr<ondisk::UnifiedOnDiskCache> UnifiedDB;
100 ondisk::OnDiskGraphDB *DB;
101};
102
103} // end anonymous namespace
104
105void OnDiskCAS::print(raw_ostream &OS) const { DB->print(OS); }
106Error OnDiskCAS::validate(bool CheckHash) const {
107 if (auto E = DB->validate(CheckHash, builtin::hashingFunc))
108 return E;
109
110 return Error::success();
111}
112
113CASID OnDiskCAS::getID(ObjectRef Ref) const {
114 ArrayRef<uint8_t> Hash = DB->getDigest(convertRef(Ref));
115 return CASID::create(&getContext(), toStringRef(Hash));
116}
117
118std::optional<ObjectRef> OnDiskCAS::getReference(const CASID &ID) const {
119 std::optional<ondisk::ObjectID> ObjID =
120 DB->getExistingReference(ID.getHash());
121 if (!ObjID)
122 return std::nullopt;
123 return convertRef(*ObjID);
124}
125
126Expected<bool> OnDiskCAS::isMaterialized(ObjectRef ExternalRef) const {
127 return DB->isMaterialized(convertRef(ExternalRef));
128}
129
130ArrayRef<char> OnDiskCAS::getDataConst(ObjectHandle Node) const {
131 return DB->getObjectData(convertHandle(Node));
132}
133
134Expected<std::optional<ObjectHandle>>
135OnDiskCAS::loadIfExists(ObjectRef ExternalRef) {
136 Expected<std::optional<ondisk::ObjectHandle>> ObjHnd =
137 DB->load(convertRef(ExternalRef));
138 if (!ObjHnd)
139 return ObjHnd.takeError();
140 if (!*ObjHnd)
141 return std::nullopt;
142 return convertHandle(**ObjHnd);
143}
144
145Expected<ObjectRef> OnDiskCAS::storeImpl(ArrayRef<uint8_t> ComputedHash,
147 ArrayRef<char> Data) {
149 IDs.reserve(Refs.size());
150 for (ObjectRef Ref : Refs) {
151 IDs.push_back(convertRef(Ref));
152 }
153
154 auto StoredID = DB->getReference(ComputedHash);
155 if (LLVM_UNLIKELY(!StoredID))
156 return StoredID.takeError();
157 if (Error E = DB->store(*StoredID, IDs, Data))
158 return std::move(E);
159 return convertRef(*StoredID);
160}
161
162Expected<ObjectRef> OnDiskCAS::storeFromFile(StringRef Path) {
164 if (LLVM_UNLIKELY(!Hash))
165 return Hash.takeError();
166 auto StoredID = DB->getReference(*Hash);
167 if (LLVM_UNLIKELY(!StoredID))
168 return StoredID.takeError();
169 if (Error E = DB->storeFile(*StoredID, Path))
170 return E;
171 return convertRef(*StoredID);
172}
173
174std::unique_ptr<MemoryBuffer>
175OnDiskCAS::getStandaloneMemoryBufferImpl(ObjectHandle Node, StringRef Name,
176 bool RequiresNullTerminator) {
177 return DB->getStandaloneMemoryBuffer(convertHandle(Node), Name,
178 RequiresNullTerminator);
179}
180
181Error OnDiskCAS::exportDataToFile(ObjectHandle Node, StringRef Path) const {
182 auto FBData = DB->getInternalFileBackedObjectData(convertHandle(Node));
183 if (!FBData.FileInfo.has_value())
184 return BuiltinCAS::exportDataToFile(Node, Path);
185
186 // Optimized version using the underlying database file.
187 assert(FBData.FileInfo.has_value());
188
189 auto BypassSandbox = sys::sandbox::scopedDisable();
190
191 ondisk::UniqueTempFile UniqueTmp;
192 auto ExpectedPath = UniqueTmp.createAndCopyFrom(sys::path::parent_path(Path),
193 FBData.FileInfo->FilePath);
194 if (!ExpectedPath)
195 return ExpectedPath.takeError();
196 StringRef TmpPath = *ExpectedPath;
197
198 if (FBData.FileInfo->IsFileNulTerminated) {
199 // Remove the nul terminator.
200 int FD;
201 if (std::error_code EC =
203 return createFileError(TmpPath, EC);
204 auto CloseFile = scope_exit([&FD] {
206 sys::fs::closeFile(File);
207 });
208 if (std::error_code EC = sys::fs::resize_file(FD, FBData.Data.size()))
209 return createFileError(TmpPath, EC);
210 }
211
212 if (Error E = UniqueTmp.renameTo(Path))
213 return E;
214
215 return Error::success();
216}
217
218Error OnDiskCAS::forEachRef(ObjectHandle Node,
219 function_ref<Error(ObjectRef)> Callback) const {
220 auto RefsRange = DB->getObjectRefs(convertHandle(Node));
221 for (ondisk::ObjectID Ref : RefsRange) {
222 if (Error E = Callback(convertRef(Ref)))
223 return E;
224 }
225 return Error::success();
226}
227
228Error OnDiskCAS::setSizeLimit(std::optional<uint64_t> SizeLimit) {
229 UnifiedDB->setSizeLimit(SizeLimit);
230 return Error::success();
231}
232
233Expected<std::optional<uint64_t>> OnDiskCAS::getStorageSize() const {
234 return UnifiedDB->getStorageSize();
235}
236
237Error OnDiskCAS::pruneStorageData() { return UnifiedDB->collectGarbage(); }
238
239Expected<std::unique_ptr<OnDiskCAS>> OnDiskCAS::open(StringRef AbsPath) {
240 std::shared_ptr<ondisk::OnDiskCASLogger> Logger;
241#ifndef _WIN32
242 if (Error E =
243 ondisk::OnDiskCASLogger::openIfEnabled(AbsPath).moveInto(Logger))
244 return std::move(E);
245#endif
246
247 Expected<std::unique_ptr<ondisk::OnDiskGraphDB>> DB =
249 sizeof(HashType), /*UpstreamDB=*/nullptr,
250 std::move(Logger));
251 if (!DB)
252 return DB.takeError();
253 return std::unique_ptr<OnDiskCAS>(new OnDiskCAS(std::move(*DB)));
254}
255
257#if LLVM_ENABLE_ONDISK_CAS
258 return true;
259#else
260 return false;
261#endif
262}
263
265#if LLVM_ENABLE_ONDISK_CAS
266 // FIXME: An absolute path isn't really good enough. Should open a directory
267 // and use openat() for files underneath.
268 SmallString<256> AbsPath;
269 Path.toVector(AbsPath);
270 sys::fs::make_absolute(AbsPath);
271
272 return OnDiskCAS::open(AbsPath);
273#else
274 return createStringError(inconvertibleErrorCode(), "OnDiskCAS is disabled");
275#endif /* LLVM_ENABLE_ONDISK_CAS */
276}
277
278std::unique_ptr<ObjectStore>
280 std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB) {
281 return std::make_unique<OnDiskCAS>(std::move(UniDB));
282}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_UNLIKELY(EXPR)
Definition Compiler.h:344
static cl::opt< unsigned > SizeLimit("eif-limit", cl::init(6), cl::Hidden, cl::desc("Size limit in Hexagon early if-conversion"))
#define I(x, y, z)
Definition MD5.cpp:57
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.
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
This file defines the scope_exit class, which executes user-defined cleanup logic at scope exit.
size_t size() const
Get the array size.
Definition ArrayRef.h:141
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
void reserve(size_type N)
void push_back(const T &Elt)
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
static Expected< HashT > hashFile(StringRef FilePath)
static CASID create(const CASContext *Context, StringRef Hash)
Create CASID from CASContext and raw hash bytes.
Definition CASID.h:117
static StringRef getHashName()
Get the name of the hash for any table identifiers.
Common base class for builtin CAS implementations using the same CASContext.
Definition BuiltinCAS.h:24
static ObjectID fromOpaqueData(uint64_t Opaque)
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...
LLVM_ABI void print(raw_ostream &OS) const
LLVM_ABI Expected< std::optional< ObjectHandle > > load(ObjectID Ref)
LLVM_ABI std::unique_ptr< MemoryBuffer > getStandaloneMemoryBuffer(ObjectHandle Node, StringRef Name, bool RequiresNullTerminator) const
Get a MemoryBuffer for Node's data that stays valid after this database is destroyed.
LLVM_ABI Expected< bool > isMaterialized(ObjectID Ref)
Check whether the object associated with Ref is stored in the CAS.
LLVM_ABI Error validate(bool Deep, HashingFuncT Hasher) const
Validate the OnDiskGraphDB.
object_refs_range getObjectRefs(ObjectHandle Node) const
LLVM_ABI Error store(ObjectID ID, ArrayRef< ObjectID > Refs, ArrayRef< char > Data)
Associate data & references with a particular object ID.
ArrayRef< uint8_t > getDigest(ObjectID Ref) const
LLVM_ABI FileBackedData getInternalFileBackedObjectData(ObjectHandle Node) const
Provides access to the underlying file path, that represents an object leaf node, when available.
LLVM_ABI Error storeFile(ObjectID ID, StringRef FilePath)
Associates the data of a file with a particular object ID.
static LLVM_ABI 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.
LLVM_ABI Expected< ObjectID > getReference(ArrayRef< uint8_t > Hash)
Form a reference for the provided hash.
LLVM_ABI ArrayRef< char > getObjectData(ObjectHandle Node) const
LLVM_ABI std::optional< ObjectID > getExistingReference(ArrayRef< uint8_t > Digest, bool CheckUpstream=true)
Get an existing reference to the object Digest.
Error renameTo(StringRef RenameToPath)
Rename the new unique file to RenameToPath.
Expected< StringRef > createAndCopyFrom(StringRef ParentPath, StringRef CopyFromPath)
Create a new unique file path under ParentPath and copy the contents of CopyFromPath into it.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
void validate(const Triple &TT, const FeatureBitset &FeatureBits)
std::unique_ptr< ObjectStore > createObjectStoreFromUnifiedOnDiskCache(std::shared_ptr< ondisk::UnifiedOnDiskCache > UniDB)
void hashingFunc(ArrayRef< ArrayRef< uint8_t > > Refs, ArrayRef< char > Data, SmallVectorImpl< uint8_t > &Result)
Convenience wrapper for BuiltinObjectHasher.
decltype(HasherT::hash(std::declval< ArrayRef< uint8_t > & >())) HashType
LLVM_ABI bool isOnDiskCASEnabled()
LLVM_ABI Expected< std::unique_ptr< ObjectStore > > createOnDiskCAS(const Twine &Path)
Create a persistent on-disk path at Path.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition Transport.h:139
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
LLVM_ABI std::error_code closeFile(file_t &F)
Close the file object.
@ CD_OpenExisting
CD_OpenExisting - When opening a file:
Definition FileSystem.h:777
std::error_code openFileForWrite(const Twine &Name, int &ResultFD, CreationDisposition Disp=CD_CreateAlways, OpenFlags Flags=OF_None, 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 make_absolute(SmallVectorImpl< char > &path)
Make path an absolute path.
Definition Path.cpp:979
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 StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
Definition Path.cpp:478
ScopedSetting scopedDisable()
Definition IOSandbox.h:36
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.
Definition Error.h:1415
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1669
scope_exit(Callable) -> scope_exit< Callable >
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
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ Ref
The access may reference the value stored in memory.
Definition ModRef.h:32
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1917
StringRef toStringRef(bool B)
Construct a string ref from a boolean.