LLVM 23.0.0git
OnDiskDataAllocator.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 Implements OnDiskDataAllocator.
10///
11//===----------------------------------------------------------------------===//
12
14#include "DatabaseFile.h"
16#include "llvm/Config/llvm-config.h"
17
18using namespace llvm;
19using namespace llvm::cas;
20using namespace llvm::cas::ondisk;
21
22#if LLVM_ENABLE_ONDISK_CAS
23
24//===----------------------------------------------------------------------===//
25// DataAllocator data structures.
26//===----------------------------------------------------------------------===//
27
28namespace {
29/// DataAllocator table layout:
30/// - [8-bytes: Generic table header]
31/// - 8-bytes: AllocatorOffset (reserved for implementing free lists)
32/// - 8-bytes: Size for user data header
33/// - <user data buffer>
34///
35/// Record layout:
36/// - <data>
37class DataAllocatorHandle {
38public:
39 static constexpr TableHandle::TableKind Kind =
40 TableHandle::TableKind::DataAllocator;
41
42 struct Header {
43 TableHandle::Header GenericHeader;
44 std::atomic<int64_t> AllocatorOffset;
45 const uint64_t UserHeaderSize;
46 };
47
48 operator TableHandle() const {
49 if (!H)
50 return TableHandle();
51 return TableHandle(*Region, H->GenericHeader);
52 }
53
54 Expected<MutableArrayRef<char>> allocate(MappedFileRegionArena &Alloc,
55 size_t DataSize) {
56 assert(&Alloc.getRegion() == Region);
57 auto Ptr = Alloc.allocate(DataSize);
58 if (LLVM_UNLIKELY(!Ptr))
59 return Ptr.takeError();
60 return MutableArrayRef(*Ptr, DataSize);
61 }
62
63 explicit operator bool() const { return H; }
64 const Header &getHeader() const { return *H; }
65 MappedFileRegion &getRegion() const { return *Region; }
66
67 MutableArrayRef<uint8_t> getUserHeader() {
68 return MutableArrayRef(reinterpret_cast<uint8_t *>(H + 1),
69 H->UserHeaderSize);
70 }
71
72 static Expected<DataAllocatorHandle>
73 create(MappedFileRegionArena &Alloc, StringRef Name, uint32_t UserHeaderSize);
74
75 DataAllocatorHandle() = default;
76 DataAllocatorHandle(MappedFileRegion &Region, Header &H)
77 : Region(&Region), H(&H) {}
78 DataAllocatorHandle(MappedFileRegion &Region, intptr_t HeaderOffset)
79 : DataAllocatorHandle(
80 Region, *reinterpret_cast<Header *>(Region.data() + HeaderOffset)) {
81 }
82
83private:
84 MappedFileRegion *Region = nullptr;
85 Header *H = nullptr;
86};
87
88} // end anonymous namespace
89
91 DatabaseFile File;
92 DataAllocatorHandle Store;
93};
94
96DataAllocatorHandle::create(MappedFileRegionArena &Alloc, StringRef Name,
97 uint32_t UserHeaderSize) {
98 // Allocate.
99 auto Offset =
100 Alloc.allocateOffset(sizeof(Header) + UserHeaderSize + Name.size() + 1);
101 if (LLVM_UNLIKELY(!Offset))
102 return Offset.takeError();
103
104 // Construct the header and the name.
105 assert(Name.size() <= UINT16_MAX && "Expected smaller table name");
106 auto *H = new (Alloc.getRegion().data() + *Offset)
108 static_cast<uint16_t>(Name.size()),
109 static_cast<int32_t>(sizeof(Header) + UserHeaderSize)},
110 /*AllocatorOffset=*/{0},
111 /*UserHeaderSize=*/UserHeaderSize};
112 // Memset UserHeader.
113 char *UserHeader = reinterpret_cast<char *>(H + 1);
114 memset(UserHeader, 0, UserHeaderSize);
115 // Write database file name (null-terminated).
116 char *NameStorage = UserHeader + UserHeaderSize;
117 llvm::copy(Name, NameStorage);
118 NameStorage[Name.size()] = 0;
119 return DataAllocatorHandle(Alloc.getRegion(), *H);
120}
121
123 const Twine &PathTwine, const Twine &TableNameTwine, uint64_t MaxFileSize,
124 std::optional<uint64_t> NewFileInitialSize, uint32_t UserHeaderSize,
125 std::shared_ptr<ondisk::OnDiskCASLogger> Logger,
126 function_ref<void(void *)> UserHeaderInit) {
127 assert(!UserHeaderSize || UserHeaderInit);
128 SmallString<128> PathStorage;
129 StringRef Path = PathTwine.toStringRef(PathStorage);
130 SmallString<128> TableNameStorage;
131 StringRef TableName = TableNameTwine.toStringRef(TableNameStorage);
132
133 // Constructor for if the file doesn't exist.
134 auto NewDBConstructor = [&](DatabaseFile &DB) -> Error {
135 auto Store =
136 DataAllocatorHandle::create(DB.getAlloc(), TableName, UserHeaderSize);
137 if (LLVM_UNLIKELY(!Store))
138 return Store.takeError();
139
140 if (auto E = DB.addTable(*Store))
141 return E;
142
143 if (UserHeaderSize)
144 UserHeaderInit(Store->getUserHeader().data());
145 return Error::success();
146 };
147
148 // Get or create the file.
149 Expected<DatabaseFile> File =
150 DatabaseFile::create(Path, MaxFileSize, Logger, NewDBConstructor);
151 if (!File)
152 return File.takeError();
153
154 // Find the table and validate it.
155 std::optional<TableHandle> Table = File->findTable(TableName);
156 if (!Table)
157 return createTableConfigError(std::errc::argument_out_of_domain, Path,
158 TableName, "table not found");
159 if (Error E = checkTable("table kind", (size_t)DataAllocatorHandle::Kind,
160 (size_t)Table->getHeader().Kind, Path, TableName))
161 return std::move(E);
162 auto Store = Table->cast<DataAllocatorHandle>();
163 assert(Store && "Already checked the kind");
164
165 // Success.
166 OnDiskDataAllocator::ImplType Impl{DatabaseFile(std::move(*File)), Store};
167 return OnDiskDataAllocator(std::make_unique<ImplType>(std::move(Impl)));
168}
169
170Expected<OnDiskDataAllocator::OnDiskPtr>
172 auto Data = Impl->Store.allocate(Impl->File.getAlloc(), Size);
173 if (LLVM_UNLIKELY(!Data))
174 return Data.takeError();
175
176 return OnDiskPtr(FileOffset(Data->data() - Impl->Store.getRegion().data()),
177 *Data);
178}
179
180Expected<ArrayRef<char>> OnDiskDataAllocator::get(FileOffset Offset,
181 size_t Size) const {
182 assert(Offset);
183 assert(Impl);
184 if (Offset.get() + Size >= Impl->File.getAlloc().size())
185 return createStringError(make_error_code(std::errc::protocol_error),
186 "requested size too large in allocator");
187 return ArrayRef<char>{Impl->File.getRegion().data() + Offset.get(), Size};
188}
189
190MutableArrayRef<uint8_t> OnDiskDataAllocator::getUserHeader() const {
191 return Impl->Store.getUserHeader();
192}
193
194size_t OnDiskDataAllocator::size() const { return Impl->File.size(); }
195size_t OnDiskDataAllocator::capacity() const {
196 return Impl->File.getRegion().size();
197}
198
199OnDiskDataAllocator::OnDiskDataAllocator(std::unique_ptr<ImplType> Impl)
200 : Impl(std::move(Impl)) {}
201
202#else // !LLVM_ENABLE_ONDISK_CAS
203
205
207 const Twine &Path, const Twine &TableName, uint64_t MaxFileSize,
208 std::optional<uint64_t> NewFileInitialSize, uint32_t UserHeaderSize,
209 std::shared_ptr<ondisk::OnDiskCASLogger> Logger,
210 function_ref<void(void *)> UserHeaderInit) {
211 return createStringError(make_error_code(std::errc::not_supported),
212 "OnDiskDataAllocator is not supported");
213}
214
217 return createStringError(make_error_code(std::errc::not_supported),
218 "OnDiskDataAllocator is not supported");
219}
220
222 size_t Size) const {
223 return createStringError(make_error_code(std::errc::not_supported),
224 "OnDiskDataAllocator is not supported");
225}
226
230
231size_t OnDiskDataAllocator::size() const { return 0; }
232size_t OnDiskDataAllocator::capacity() const { return 0; }
233
234#endif // LLVM_ENABLE_ONDISK_CAS
235
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Prepare AGPR Alloc
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_UNLIKELY(EXPR)
Definition Compiler.h:336
This file declares the common interface for a DatabaseFile that is used to implement OnDiskCAS.
#define H(x, y, z)
Definition MD5.cpp:56
This file declares interface for OnDiskCASLogger, an interface that can be used to log CAS events to ...
This file declares interface for OnDiskDataAllocator, a file backed data pool can be used to allocate...
static Split data
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Logging utility - given an ordered specification of features, and assuming a scalar reward,...
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition ArrayRef.h:298
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
StringRef toStringRef(SmallVectorImpl< char > &Out) const
This returns the twine as a single StringRef if it can be represented as such.
Definition Twine.h:461
FileOffset is a wrapper around uint64_t to represent the offset of data from the beginning of the fil...
Definition FileOffset.h:24
Allocator for an owned mapped file region that supports thread-safe and process-safe bump pointer all...
A pointer to data stored on disk.
LLVM_ABI_FOR_TEST ~OnDiskDataAllocator()
MutableArrayRef< uint8_t > getUserHeader() const
LLVM_ABI_FOR_TEST Expected< OnDiskPtr > allocate(size_t Size)
Allocate at least Size with 8-byte alignment.
LLVM_ABI_FOR_TEST Expected< ArrayRef< char > > get(FileOffset Offset, size_t Size) const
Get the data of Size stored at the given Offset.
static LLVM_ABI_FOR_TEST Expected< OnDiskDataAllocator > create(const Twine &Path, const Twine &TableName, uint64_t MaxFileSize, std::optional< uint64_t > NewFileInitialSize, uint32_t UserHeaderSize=0, std::shared_ptr< ondisk::OnDiskCASLogger > Logger=nullptr, function_ref< void(void *)> UserHeaderInit=nullptr)
LLVM_ABI_FOR_TEST size_t size() const
LLVM_ABI_FOR_TEST OnDiskDataAllocator & operator=(OnDiskDataAllocator &&RHS)
LLVM_ABI_FOR_TEST OnDiskDataAllocator(OnDiskDataAllocator &&RHS)
LLVM_ABI_FOR_TEST size_t capacity() const
static Expected< DatabaseFile > create(const Twine &Path, uint64_t Capacity, std::shared_ptr< OnDiskCASLogger > Logger, function_ref< Error(DatabaseFile &)> NewDBConstructor)
Create the DatabaseFile at Path with Capacity.
An efficient, type-erasing, non-owning reference to a callable.
Error createTableConfigError(std::errc ErrC, StringRef Path, StringRef TableName, const Twine &Msg)
MappedFileRegionArena::RegionT MappedFileRegion
Error checkTable(StringRef Label, size_t Expected, size_t Observed, StringRef Path, StringRef TrieName)
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
@ Offset
Definition DWP.cpp:532
std::error_code make_error_code(BitcodeError E)
FunctionAddr VTableAddr uintptr_t uintptr_t DataSize
Definition InstrProf.h:267
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1305
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:189
OutputIt copy(R &&Range, OutputIt Out)
Definition STLExtras.h:1883
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:1915