MySQL 9.3.0
Source Code Documentation
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
secure_memory_pool.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2025, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef ROUTER_SRC_HARNESS_INCLUDE_SECURE_MEMORY_POOL_H_
27#define ROUTER_SRC_HARNESS_INCLUDE_SECURE_MEMORY_POOL_H_
28
29#include <cstddef>
30#include <list>
31#include <memory>
32#include <mutex>
33#include <unordered_map>
34#include <unordered_set>
35#include <vector>
36
37#include "harness_export.h" // NOLINT(build/include_subdir)
38
39namespace mysql_harness {
40
41/**
42 * Manages a pool of memory which is prevented from being swapped.
43 */
44class HARNESS_EXPORT SecureMemoryPool final {
45 public:
48
51
52 ~SecureMemoryPool() = default;
53
54 /**
55 * The single instance of this class.
56 */
57 [[nodiscard]] static SecureMemoryPool &get();
58
59 /**
60 * Allocates the given number of bytes.
61 *
62 * @param size Number of bytes to allocate.
63 *
64 * @returns Allocated memory.
65 */
66 [[nodiscard]] void *allocate(std::size_t size);
67
68 /**
69 * Deallocates the given number of bytes.
70 *
71 * @param ptr Memory previously allocated by this class.
72 * @param size Size of the memory.
73 */
74 void deallocate(void *ptr, std::size_t size) noexcept;
75
76 private:
77 template <class Strategy>
78 class Bucket;
79
80 /**
81 * Allows to allocate multiple contiguous blocks of memory.
82 */
83 class ContiguousBlocks final {
84 public:
85 ContiguousBlocks() = delete;
86
87 explicit ContiguousBlocks(const Bucket<ContiguousBlocks> &parent);
88
91
94
96
97 /**
98 * Allocates the given number of blocks.
99 *
100 * @param count Number of blocks to allocate.
101 *
102 * @returns Allocated memory or nullptr if cannot allocate the requested
103 * amount of blocks.
104 */
105 [[nodiscard]] void *allocate_blocks(std::size_t count) noexcept;
106
107 /**
108 * Deallocates the given number of blocks.
109 *
110 * @param ptr Memory previously allocated by this class.
111 * @param count Number of blocks.
112 */
113 void deallocate_blocks(void *ptr, std::size_t count) noexcept;
114
115 private:
116 [[nodiscard]] std::size_t find_contiguous_blocks(
117 std::size_t count) const noexcept;
118
119 void set_in_use(std::size_t index, std::size_t count) noexcept;
120
121 void set_free(std::size_t index, std::size_t count) noexcept;
122
124 // holds one bit per each block of memory, 0 block is unused, 1 block is in
125 // use
126 unsigned char *index_;
127 };
128
129 /**
130 * Allocates a single block of memory.
131 */
132 class FixedBlock final {
133 public:
134 FixedBlock() = delete;
135
136 explicit FixedBlock(const Bucket<FixedBlock> &parent);
137
138 FixedBlock(const FixedBlock &) = delete;
139 FixedBlock(FixedBlock &&) noexcept;
140
141 FixedBlock &operator=(const FixedBlock &) = delete;
142 FixedBlock &operator=(FixedBlock &&) = delete;
143
144 ~FixedBlock() = default;
145
146 /**
147 * Allocates the given number of blocks.
148 *
149 * @param count Number of blocks to allocate.
150 *
151 * @returns Allocated memory or nullptr if cannot allocate the requested
152 * amount of blocks.
153 */
154 [[nodiscard]] void *allocate_blocks(std::size_t count) noexcept;
155
156 /**
157 * Deallocates the given number of blocks.
158 *
159 * @param ptr Memory previously allocated by this class.
160 * @param count Number of blocks.
161 */
162 void deallocate_blocks(void *ptr, std::size_t count) noexcept;
163
164 private:
165 struct BlockList {
167 };
168
170 // unused blocks
172 };
173
174 /**
175 * A bucket of memory blocks of the given size.
176 */
177 template <class Strategy>
178 class Bucket final {
179 public:
180 Bucket() = delete;
181
182 /**
183 * Creates the bucket.
184 *
185 * @param bucket_size Size of the whole bucket.
186 * @param block_size Size of a single block of memory.
187 */
188 Bucket(std::size_t bucket_size, std::size_t block_size);
189
190 Bucket(const Bucket &) = delete;
191 Bucket(Bucket &&) noexcept;
192
193 Bucket &operator=(const Bucket &) = delete;
194 Bucket &operator=(Bucket &&) = delete;
195
196 ~Bucket();
197
198 /**
199 * Size of the whole bucket.
200 */
201 [[nodiscard]] inline std::size_t bucket_size() const noexcept {
202 return bucket_size_;
203 }
204
205 /**
206 * Number of memory blocks in this bucket.
207 */
208 [[nodiscard]] inline std::size_t block_count() const noexcept {
209 return block_count_;
210 }
211
212 /**
213 * Size of a single block of memory.
214 */
215 [[nodiscard]] inline std::size_t block_size() const noexcept {
216 return block_size_;
217 }
218
219 /**
220 * Number of unused blocks.
221 */
222 [[nodiscard]] inline std::size_t blocks_free() const noexcept {
223 return blocks_free_;
224 }
225
226 /**
227 * Whether all blocks are unused.
228 */
229 [[nodiscard]] inline std::size_t is_empty() const noexcept {
230 return block_count() == blocks_free();
231 }
232
233 /**
234 * Whether all blocks are being used.
235 */
236 [[nodiscard]] inline std::size_t is_full() const noexcept {
237 return 0 == blocks_free();
238 }
239
240 /**
241 * Pointer to the memory held by this bucket.
242 */
243 [[nodiscard]] inline std::byte *memory() const noexcept { return memory_; }
244
245 /**
246 * Whether this bucket contains the given pointer.
247 */
248 [[nodiscard]] bool contains(const void *ptr) const noexcept;
249
250 /**
251 * Allocates the given number of bytes.
252 *
253 * @param bytes Number of bytes to allocate.
254 *
255 * @returns Allocated memory or nullptr if bucket cannot allocate the
256 * requested amount of memory.
257 */
258 [[nodiscard]] void *allocate(std::size_t bytes) noexcept;
259
260 /**
261 * Deallocates the given number of bytes.
262 *
263 * @param ptr Memory previously allocated by this class.
264 * @param bytes Size of the memory.
265 */
266 void deallocate(void *ptr, std::size_t bytes) noexcept;
267
268 /**
269 * Compares two buckets.
270 */
271 friend inline bool operator==(const Bucket &l, const Bucket &r) noexcept {
272 return l.memory_ == r.memory_;
273 }
274
275 private:
276 const std::size_t bucket_size_;
277 const std::size_t block_count_;
278 const std::size_t block_size_;
279 std::size_t blocks_free_;
280
281 // allocated memory
283 // allocator strategy to use
284 Strategy allocator_;
285 };
286
287 /**
288 * Holds buckets with the given block size.
289 */
290 template <class BucketType>
291 class BucketPool final {
292 public:
293 BucketPool() = delete;
294
295 /**
296 * Creates the pool.
297 *
298 * @param page_size Page size for the buckets in this pool, size of each
299 * bucket is going to be a factor of this size.
300 * @param block_size Blocks size for the buckets in this pool.
301 */
302 BucketPool(std::size_t page_size, std::size_t block_size);
303
304 BucketPool(const BucketPool &) = delete;
305 BucketPool(BucketPool &&) = delete;
306
307 BucketPool &operator=(const BucketPool &) = delete;
309
310 ~BucketPool() = default;
311
312 /**
313 * Page size for the buckets in this pool.
314 */
315 [[nodiscard]] inline std::size_t page_size() const noexcept {
316 return page_size_;
317 }
318
319 /**
320 * Size of a single block of memory.
321 */
322 [[nodiscard]] inline std::size_t block_size() const noexcept {
323 return block_size_;
324 }
325
326 /**
327 * Allocates the given number of bytes.
328 *
329 * @param bytes Number of bytes to allocate.
330 *
331 * @returns Allocated memory.
332 */
333 [[nodiscard]] void *allocate(std::size_t bytes);
334
335 /**
336 * Deallocates the given number of bytes.
337 *
338 * @param ptr Memory previously allocated by this class.
339 * @param bytes Size of the memory.
340 */
341 void deallocate(void *ptr, std::size_t bytes) noexcept;
342
343 private:
344 struct BucketHash {
345 std::size_t operator()(const BucketType &b) const noexcept {
346 // buckets are hashed using the memory they hold
347 return reinterpret_cast<std::size_t>(b.memory());
348 }
349 };
350
351 using Buckets = std::unordered_set<BucketType, BucketHash>;
352
353 [[nodiscard]] static inline BucketType *pointer(
354 Buckets::const_iterator it) {
355 // buckets are stored in an unordered set, where iterators are always
356 // const; we can safely cast away the const, as the memory allocated by
357 // each bucket does not change during their lifetime, ensuring that hash
358 // does not change
359 return const_cast<BucketType *>(&*it);
360 }
361
362 [[nodiscard]] BucketType *add_bucket(std::size_t size);
363
364 void remove_bucket(BucketType *bucket);
365
366 [[nodiscard]] BucketType *find_bucket(const void *ptr);
367
368 const std::size_t page_size_;
369 const std::size_t block_size_;
370
371 std::mutex mutex_;
372
373 // buckets which have memory available
375 // buckets which don't have memory available
377
378 // maps the memory aligned to the system page to the bucket which holds that
379 // memory
380 std::unordered_map<const void *, BucketType *> memory_map_;
381
382 // we keep a single empty bucket to avoid repeatedly adding and removing a
383 // new bucket when close to the capacity limit
384 const BucketType *empty_bucket_;
385 };
386
388
389 // buckets which serve memory blocks of a constant size
390 std::vector<Bucket<FixedBlock>> fixed_buckets_;
391 // mutexes which control access to the fixed_buckets_
392 std::vector<std::mutex> fixed_buckets_mutexes_;
393 // pool which serves memory that does not fit into other pools
395};
396
397} // namespace mysql_harness
398
399#endif // ROUTER_SRC_HARNESS_INCLUDE_SECURE_MEMORY_POOL_H_
Holds buckets with the given block size.
Definition: secure_memory_pool.h:291
const std::size_t block_size_
Definition: secure_memory_pool.h:369
Buckets buckets_
Definition: secure_memory_pool.h:374
std::size_t page_size() const noexcept
Page size for the buckets in this pool.
Definition: secure_memory_pool.h:315
const std::size_t page_size_
Definition: secure_memory_pool.h:368
std::unordered_set< BucketType, BucketHash > Buckets
Definition: secure_memory_pool.h:351
Buckets full_buckets_
Definition: secure_memory_pool.h:376
BucketPool & operator=(const BucketPool &)=delete
std::mutex mutex_
Definition: secure_memory_pool.h:371
std::unordered_map< const void *, BucketType * > memory_map_
Definition: secure_memory_pool.h:380
std::size_t block_size() const noexcept
Size of a single block of memory.
Definition: secure_memory_pool.h:322
static BucketType * pointer(Buckets::const_iterator it)
Definition: secure_memory_pool.h:353
BucketPool & operator=(BucketPool &&)=delete
BucketPool(const BucketPool &)=delete
const BucketType * empty_bucket_
Definition: secure_memory_pool.h:384
A bucket of memory blocks of the given size.
Definition: secure_memory_pool.h:178
const std::size_t block_count_
Definition: secure_memory_pool.h:277
std::size_t block_size() const noexcept
Size of a single block of memory.
Definition: secure_memory_pool.h:215
std::size_t block_count() const noexcept
Number of memory blocks in this bucket.
Definition: secure_memory_pool.h:208
std::byte * memory_
Definition: secure_memory_pool.h:282
const std::size_t bucket_size_
Definition: secure_memory_pool.h:276
std::size_t blocks_free_
Definition: secure_memory_pool.h:279
friend bool operator==(const Bucket &l, const Bucket &r) noexcept
Compares two buckets.
Definition: secure_memory_pool.h:271
std::size_t is_empty() const noexcept
Whether all blocks are unused.
Definition: secure_memory_pool.h:229
const std::size_t block_size_
Definition: secure_memory_pool.h:278
std::size_t is_full() const noexcept
Whether all blocks are being used.
Definition: secure_memory_pool.h:236
Strategy allocator_
Definition: secure_memory_pool.h:284
std::size_t blocks_free() const noexcept
Number of unused blocks.
Definition: secure_memory_pool.h:222
std::byte * memory() const noexcept
Pointer to the memory held by this bucket.
Definition: secure_memory_pool.h:243
Allows to allocate multiple contiguous blocks of memory.
Definition: secure_memory_pool.h:83
ContiguousBlocks & operator=(ContiguousBlocks &&)=delete
ContiguousBlocks(const ContiguousBlocks &)=delete
const Bucket< ContiguousBlocks > & parent_
Definition: secure_memory_pool.h:123
ContiguousBlocks & operator=(const ContiguousBlocks &)=delete
unsigned char * index_
Definition: secure_memory_pool.h:126
Allocates a single block of memory.
Definition: secure_memory_pool.h:132
FixedBlock(const FixedBlock &)=delete
const Bucket< FixedBlock > & parent_
Definition: secure_memory_pool.h:169
BlockList * unused_blocks_
Definition: secure_memory_pool.h:171
Manages a pool of memory which is prevented from being swapped.
Definition: secure_memory_pool.h:44
BucketPool< Bucket< ContiguousBlocks > > large_pool_
Definition: secure_memory_pool.h:394
std::vector< Bucket< FixedBlock > > fixed_buckets_
Definition: secure_memory_pool.h:390
SecureMemoryPool(SecureMemoryPool &&)=delete
SecureMemoryPool & operator=(SecureMemoryPool &&)=delete
SecureMemoryPool & operator=(const SecureMemoryPool &)=delete
std::vector< std::mutex > fixed_buckets_mutexes_
Definition: secure_memory_pool.h:392
SecureMemoryPool(const SecureMemoryPool &)=delete
struct bucket Bucket
static bool contains(const std::vector< std::string > &container, const std::string &file)
Definition: config_files.cc:41
unsigned char byte
Blob class.
Definition: common.h:151
static int count
Definition: myisam_ftdump.cc:45
bool index(const std::string &value, const String &search_for, uint32_t *idx)
Definition: contains.h:75
static mysql_service_status_t get(THD **thd) noexcept
Definition: mysql_current_thread_reader_all_empty.cc:31
Definition: common.h:44
size_t size(const char *const c)
Definition: base64.h:46
Definition: gcs_xcom_synode.h:64
const mysql_service_registry_t * r
Definition: pfs_example_plugin_employee.cc:86
Definition: completion_hash.h:40
std::size_t operator()(const BucketType &b) const noexcept
Definition: secure_memory_pool.h:345
Definition: secure_memory_pool.h:165
BlockList * next
Definition: secure_memory_pool.h:166