MySQL 8.4.0
Source Code Documentation
my_alloc.h
Go to the documentation of this file.
1/* Copyright (c) 2000, 2024, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is designed to work with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have either included with
13 the program or referenced in the documentation.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23
24/**
25 * @file include/my_alloc.h
26 *
27 * This file follows Google coding style, except for the name MEM_ROOT (which is
28 * kept for historical reasons).
29 */
30
31#ifndef INCLUDE_MY_ALLOC_H_
32#define INCLUDE_MY_ALLOC_H_
33
34#include <string.h>
35
36#include <memory>
37#include <new>
38#include <type_traits>
39#include <utility>
40
41#include "memory_debugging.h"
42#include "my_compiler.h"
43#include "my_dbug.h"
44#include "my_inttypes.h"
47
48#if defined(MYSQL_SERVER)
49extern "C" void sql_alloc_error_handler();
50#endif
51
52/**
53 * The MEM_ROOT is a simple arena, where allocations are carved out of
54 * larger blocks. Using an arena over plain malloc gives you two main
55 * advantages:
56 *
57 * * Allocation is very cheap (only a few CPU cycles on the fast path).
58 * * You do not need to keep track of which memory you have allocated,
59 * as it will all be freed when the arena is destroyed.
60 *
61 * Thus, if you need to do many small allocations that all are to have
62 * roughly the same lifetime, the MEM_ROOT is probably a good choice.
63 * The flip side is that _no_ memory is freed until the arena is destroyed,
64 * and no destructors are run (although you can run them manually yourself).
65 *
66 *
67 * This specific implementation works by allocating exponentially larger blocks
68 * each time it needs more memory (generally increasing them by 50%), which
69 * guarantees O(1) total calls to malloc and free. Only one free block is
70 * ever used; as soon as there's an allocation that comes in that doesn't fit,
71 * that block is stored away and never allocated from again. (There's an
72 * exception for allocations larger than the block size; see #AllocSlow
73 * for details.)
74 *
75 * The MEM_ROOT is thread-compatible but not thread-safe. This means you cannot
76 * use the same instance from multiple threads at the same time without external
77 * synchronization, but you can use different MEM_ROOTs concurrently in
78 * different threads.
79 *
80 * For C compatibility reasons, MEM_ROOT is a struct, even though it is
81 * logically a class and follows the style guide for classes.
82 */
83struct MEM_ROOT {
84 private:
85 struct Block {
86 Block *prev{nullptr}; /** Previous block; used for freeing. */
87 char *end{nullptr}; /** One byte past the end; used for Contains(). */
88 };
89
90 public:
91 MEM_ROOT() : MEM_ROOT(0, 512) {} // 0 = PSI_NOT_INSTRUMENTED.
92
93 MEM_ROOT(PSI_memory_key key, size_t block_size)
94 : m_block_size(block_size),
95 m_orig_block_size(block_size),
96 m_psi_key(key) {
97#if defined(MYSQL_SERVER)
99#endif
100 }
101
102 // MEM_ROOT is movable but not copyable.
103 MEM_ROOT(const MEM_ROOT &) = delete;
104 MEM_ROOT(MEM_ROOT &&other)
105 noexcept
116 other.m_current_block = nullptr;
117 other.m_allocated_size = 0;
118 other.m_block_size = m_orig_block_size;
119 other.m_current_free_start = &s_dummy_target;
120 other.m_current_free_end = &s_dummy_target;
121 }
122
123 MEM_ROOT &operator=(const MEM_ROOT &) = delete;
124 MEM_ROOT &operator=(MEM_ROOT &&other) noexcept {
125 Clear();
126 ::new (this) MEM_ROOT(std::move(other));
127 return *this;
128 }
129
131
132 /**
133 * Allocate memory. Will return nullptr if there's not enough memory,
134 * or if the maximum capacity is reached.
135 *
136 * Note that a zero-length allocation can return _any_ pointer, including
137 * nullptr or a pointer that has been given out before. The current
138 * implementation takes some pains to make sure we never return nullptr
139 * (although it might return a bogus pointer), since there is code that
140 * assumes nullptr always means 'out of memory', but you should not rely on
141 * it, as it may change in the future.
142 *
143 * The returned pointer will always be 8-aligned.
144 */
145 void *Alloc(size_t length) MY_ATTRIBUTE((malloc)) {
147
148 // Skip the straight path if simulating OOM; it should always fail.
149 DBUG_EXECUTE_IF("simulate_out_of_memory", return AllocSlow(length););
150
151 // Fast path, used in the majority of cases. It would be faster here
152 // (saving one register due to CSE) to instead test
153 //
154 // m_current_free_start + length <= m_current_free_end
155 //
156 // but it would invoke undefined behavior, and in particular be prone
157 // to wraparound on 32-bit platforms.
158 if (static_cast<size_t>(m_current_free_end - m_current_free_start) >=
159 length) {
160 void *ret = m_current_free_start;
162 return ret;
163 }
164
165 return AllocSlow(length);
166 }
167
168 /**
169 Allocate 'num' objects of type T, and initialize them to a default value
170 that is created by passing the supplied args to T's constructor. If args
171 is empty, value-initialization is used. For primitive types, like int and
172 pointers, this means the elements will be set to the equivalent of 0
173 (or false or nullptr).
174
175 If the constructor throws an exception, behavior is undefined.
176
177 We don't use new[], as it can put extra data in front of the array.
178 */
179 template <class T, class... Args>
180 T *ArrayAlloc(size_t num, Args... args) {
181 static_assert(alignof(T) <= 8, "MEM_ROOT only returns 8-aligned memory.");
182 if (num * sizeof(T) < num) {
183 // Overflow.
184 return nullptr;
185 }
186 T *ret = static_cast<T *>(Alloc(num * sizeof(T)));
187 if (ret == nullptr) {
188 // Out of memory.
189 return nullptr;
190 }
191
192 // Initialize all elements.
193 for (size_t i = 0; i < num; ++i) {
194 new (&ret[i]) T(args...);
195 }
196
197 return ret;
198 }
199
200 /**
201 * Claim all the allocated memory for the current thread in the performance
202 * schema. Use when transferring responsibility for a MEM_ROOT from one thread
203 * to another.
204 */
205 void Claim(bool claim);
206
207 /**
208 * Deallocate all the RAM used. The MEM_ROOT itself continues to be valid,
209 * so you can make new calls to Alloc() afterwards.
210
211 * @note
212 * One can call this function either with a MEM_ROOT initialized with the
213 * constructor, or with one that's memset() to all zeros.
214 * It's also safe to call this multiple times with the same mem_root.
215 */
216 void Clear();
217
218 /**
219 * Similar to Clear(), but anticipates that the block will be reused for
220 * further allocations. This means that even though all the data is gone,
221 * one memory block (typically the largest allocated) will be kept and
222 * made immediately available for calls to Alloc() without having to go to the
223 * OS for new memory. This can yield performance gains if you use the same
224 * MEM_ROOT many times. Also, the block size is not reset.
225 */
226 void ClearForReuse();
227
228 /**
229 Whether the constructor has run or not.
230
231 This exists solely to support legacy code that memset()s the MEM_ROOT to
232 all zeros, which wants to distinguish between that state and a properly
233 initialized MEM_ROOT. If you do not run the constructor _nor_ do memset(),
234 you are invoking undefined behavior.
235 */
236 bool inited() const { return m_block_size != 0; }
237
238 /**
239 * Set maximum capacity for this MEM_ROOT. Whenever the MEM_ROOT has
240 * allocated more than this (not including overhead), and the free block
241 * is empty, future allocations will fail.
242 *
243 * @param max_capacity Maximum capacity this mem_root can hold
244 */
245 void set_max_capacity(size_t max_capacity) { m_max_capacity = max_capacity; }
246
247 /**
248 * Return maximum capacity for this MEM_ROOT.
249 */
250 size_t get_max_capacity() const { return m_max_capacity; }
251
252 /**
253 * Enable/disable error reporting for exceeding the maximum capacity.
254 * If error reporting is enabled, an error is flagged to indicate that the
255 * capacity is exceeded. However, allocation will still happen for the
256 * requested memory.
257 *
258 * @param report_error whether the error should be reported
259 */
262 }
263
264 /**
265 * Return whether error is to be reported when
266 * maximum capacity exceeds for MEM_ROOT.
267 */
270 }
271
272 /**
273 * Set the error handler on memory allocation failure (or nullptr for none).
274 * The error handler is called called whenever my_malloc() failed to allocate
275 * more memory from the OS (which causes my_alloc() to return nullptr).
276 */
277 void set_error_handler(void (*error_handler)(void)) {
278 m_error_handler = error_handler;
279 }
280
281 /**
282 * Amount of memory we have allocated from the operating system, not including
283 * overhead.
284 */
285 size_t allocated_size() const { return m_allocated_size; }
286
287 /**
288 * Set the desired size of the next block to be allocated. Note that future
289 * allocations
290 * will grow in size over this, although a Clear() will reset the size again.
291 */
292 void set_block_size(size_t block_size) {
293 m_block_size = m_orig_block_size = block_size;
294 }
295
296 /**
297 * @name Raw interface
298 * Peek(), ForceNewBlock() and RawCommit() together define an
299 * alternative interface to MEM_ROOT, for special uses. The raw interface
300 * gives direct access to the underlying blocks, allowing a user to bypass the
301 * normal alignment requirements and to write data directly into them without
302 * knowing beforehand exactly how long said data is going to be, while still
303 * retaining the convenience of block management and automatic freeing. It
304 * generally cannot be combined with calling Alloc() as normal; see RawCommit.
305 *
306 * The raw interface, unlike Alloc(), is not affected by running under
307 * ASan or Valgrind.
308 *
309 * @{
310 */
311
312 /**
313 * Get the bounds of the currently allocated memory block. Assuming no other
314 * MEM_ROOT calls are made in the meantime, you can start writing into this
315 * block and then call RawCommit() once you know how many bytes you actually
316 * needed. (This is useful when e.g. packing rows.)
317 */
318 std::pair<char *, char *> Peek() const {
320 }
321
322 /**
323 * Allocate a new block of at least 'minimum_length' bytes; usually more.
324 * This holds no matter how many bytes are free in the current block.
325 * The new block will always become the current block, ie., the next call
326 * to Peek() will return the newly allocated block. (This is different
327 * from Alloc(), where it is possible to allocate a new block that is
328 * not made into the current block.)
329 *
330 * @return true Allocation failed (possibly due to size restrictions).
331 */
332 bool ForceNewBlock(size_t minimum_length);
333
334 /**
335 * Mark the first N bytes as the current block as used.
336 *
337 * WARNING: If you use RawCommit() with a length that is not a multiple of 8,
338 * you cannot use Alloc() afterwards! The exception is that if EnsureSpace()
339 * has just returned, you've got a new block, and can use Alloc() again.
340 */
341 void RawCommit(size_t length) {
342 assert(static_cast<size_t>(m_current_free_end - m_current_free_start) >=
343 length);
345 }
346
347 /**
348 * Returns whether this MEM_ROOT contains the given pointer,
349 * ie., whether it was given back from Alloc(n) (given n >= 1)
350 * at some point. This means it will be legally accessible until
351 * the next Clear() or ClearForReuse() call.
352 */
353 bool Contains(void *ptr) const {
354 for (Block *block = m_current_block; block != nullptr;
355 block = block->prev) {
356 if (ptr >= block && ptr < block->end) {
357 return true;
358 }
359 }
360 return false;
361 }
362
363 /// @}
364
365 private:
366 /**
367 * Something to point on that exists solely to never return nullptr
368 * from Alloc(0).
369 */
370 static char s_dummy_target;
371
372 /**
373 Allocate a new block of the given length (plus overhead for the block
374 header). If the MEM_ROOT is near capacity, it may allocate less memory
375 than wanted_length, but if it cannot allocate at least minimum_length,
376 will return nullptr.
377 */
378 Block *AllocBlock(size_t wanted_length, size_t minimum_length);
379
380 /** Allocate memory that doesn't fit into the current free block. */
381 void *AllocSlow(size_t length);
382
383 /** Free all blocks in a linked list, starting at the given block. */
384 static void FreeBlocks(Block *start);
385
386 /** The current block we are giving out memory from. nullptr if none. */
388
389 /** Start (inclusive) of the current free block. */
391
392 /** End (exclusive) of the current free block. */
394
395 /** Size of the _next_ block we intend to allocate. */
397
398 /** The original block size the user asked for on construction. */
400
401 /**
402 Maximum amount of memory this MEM_ROOT can hold. A value of 0
403 implies there is no limit.
404 */
405 size_t m_max_capacity = 0;
406
407 /**
408 * Total allocated size for this MEM_ROOT. Does not include overhead
409 * for block headers or malloc overhead, since especially the latter
410 * is impossible to quantify portably.
411 */
413
414 /** If enabled, exceeding the capacity will lead to a my_error() call. */
416
417 void (*m_error_handler)(void) = nullptr;
418
420};
421
422/**
423 * Allocate an object of the given type. Use like this:
424 *
425 * Foo *foo = new (mem_root) Foo();
426 *
427 * Note that unlike regular operator new, this will not throw exceptions.
428 * However, it can return nullptr if the capacity of the MEM_ROOT has been
429 * reached. This is allowed since it is not a replacement for global operator
430 * new, and thus isn't used automatically by e.g. standard library containers.
431 *
432 * TODO: This syntax is confusing in that it could look like allocating
433 * a MEM_ROOT using regular placement new. We should make a less ambiguous
434 * syntax, e.g. new (On(mem_root)) Foo().
435 */
436inline void *operator new(size_t size, MEM_ROOT *mem_root,
437 const std::nothrow_t &arg
438 [[maybe_unused]] = std::nothrow) noexcept {
439 return mem_root->Alloc(size);
440}
441
442inline void *operator new[](size_t size, MEM_ROOT *mem_root,
443 const std::nothrow_t &arg
444 [[maybe_unused]] = std::nothrow) noexcept {
445 return mem_root->Alloc(size);
446}
447
448inline void operator delete(void *, MEM_ROOT *,
449 const std::nothrow_t &) noexcept {
450 /* never called */
451}
452
453inline void operator delete[](void *, MEM_ROOT *,
454 const std::nothrow_t &) noexcept {
455 /* never called */
456}
457
458template <class T>
459inline void destroy_at(T *ptr) {
460 assert(ptr != nullptr);
461 std::destroy_at(ptr);
462 TRASH(const_cast<std::remove_const_t<T> *>(ptr), sizeof(T));
463}
464
465/*
466 * For std::unique_ptr with objects allocated on a MEM_ROOT, you shouldn't use
467 * Default_deleter; use this deleter instead.
468 */
469template <class T>
471 public:
472 void operator()(T *ptr) const { ::destroy_at(ptr); }
473};
474
475/** std::unique_ptr, but only destroying. */
476template <class T>
477using unique_ptr_destroy_only = std::unique_ptr<T, Destroy_only<T>>;
478
479template <typename T, typename... Args>
481 Args &&... args) {
483 T(std::forward<Args>(args)...));
484}
485
486#endif // INCLUDE_MY_ALLOC_H_
Definition: my_alloc.h:470
void operator()(T *ptr) const
Definition: my_alloc.h:472
static MEM_ROOT mem_root
Definition: client_plugin.cc:114
static bool report_error(THD *thd, int error_code, Sql_condition::enum_severity_level level, Args... args)
Definition: error_handler.cc:291
unsigned int PSI_memory_key
Instrumented memory key.
Definition: psi_memory_bits.h:49
static void start(mysql_harness::PluginFuncEnv *env)
Definition: http_auth_backend_plugin.cc:180
#define malloc(A)
Definition: lexyy.cc:914
Various macros useful for communicating with memory debuggers, such as Valgrind.
void TRASH(void *ptr, size_t length)
Put bad content in memory to be sure it will segfault if dereferenced.
Definition: memory_debugging.h:71
void destroy_at(T *ptr)
Definition: my_alloc.h:459
unique_ptr_destroy_only< T > make_unique_destroy_only(MEM_ROOT *mem_root, Args &&... args)
Definition: my_alloc.h:480
void sql_alloc_error_handler()
Definition: mysql_tzinfo_to_sql.cc:331
std::unique_ptr< T, Destroy_only< T > > unique_ptr_destroy_only
std::unique_ptr, but only destroying.
Definition: my_alloc.h:477
Header for compiler-dependent features.
#define DBUG_EXECUTE_IF(keyword, a1)
Definition: my_dbug.h:171
Some integer typedefs for easier portability.
Some macros for dealing with pointer arithmetic, e.g., aligning of buffers to a given size.
#define ALIGN_SIZE(A)
Definition: my_pointer_arithmetic.h:36
bool length(const dd::Spatial_reference_system *srs, const Geometry *g1, double *length, bool *null) noexcept
Computes the length of linestrings and multilinestrings.
Definition: length.cc:76
size_t size(const char *const c)
Definition: base64.h:46
Cursor end()
A past-the-end Cursor.
Definition: rules_table_service.cc:192
Performance schema instrumentation interface.
required string key
Definition: replication_asynchronous_connection_failover.proto:60
Definition: my_alloc.h:85
char * end
Previous block; used for freeing.
Definition: my_alloc.h:87
Block * prev
Definition: my_alloc.h:86
The MEM_ROOT is a simple arena, where allocations are carved out of larger blocks.
Definition: my_alloc.h:83
bool Contains(void *ptr) const
Returns whether this MEM_ROOT contains the given pointer, ie., whether it was given back from Alloc(n...
Definition: my_alloc.h:353
void Claim(bool claim)
Claim all the allocated memory for the current thread in the performance schema.
Definition: my_alloc.cc:223
size_t m_block_size
Size of the next block we intend to allocate.
Definition: my_alloc.h:396
char * m_current_free_end
End (exclusive) of the current free block.
Definition: my_alloc.h:393
void set_block_size(size_t block_size)
Set the desired size of the next block to be allocated.
Definition: my_alloc.h:292
size_t get_max_capacity() const
Return maximum capacity for this MEM_ROOT.
Definition: my_alloc.h:250
size_t allocated_size() const
Amount of memory we have allocated from the operating system, not including overhead.
Definition: my_alloc.h:285
void RawCommit(size_t length)
Mark the first N bytes as the current block as used.
Definition: my_alloc.h:341
Block * m_current_block
The current block we are giving out memory from.
Definition: my_alloc.h:387
bool ForceNewBlock(size_t minimum_length)
Allocate a new block of at least 'minimum_length' bytes; usually more.
Definition: my_alloc.cc:154
void Clear()
Deallocate all the RAM used.
Definition: my_alloc.cc:172
MEM_ROOT()
Definition: my_alloc.h:91
T * ArrayAlloc(size_t num, Args... args)
Allocate 'num' objects of type T, and initialize them to a default value that is created by passing t...
Definition: my_alloc.h:180
MEM_ROOT(PSI_memory_key key, size_t block_size)
Definition: my_alloc.h:93
PSI_memory_key m_psi_key
Definition: my_alloc.h:419
MEM_ROOT & operator=(MEM_ROOT &&other) noexcept
Definition: my_alloc.h:124
void ClearForReuse()
Similar to Clear(), but anticipates that the block will be reused for further allocations.
Definition: my_alloc.cc:190
size_t m_orig_block_size
The original block size the user asked for on construction.
Definition: my_alloc.h:399
MEM_ROOT & operator=(const MEM_ROOT &)=delete
void * AllocSlow(size_t length)
Allocate memory that doesn't fit into the current free block.
Definition: my_alloc.cc:109
void set_error_handler(void(*error_handler)(void))
Set the error handler on memory allocation failure (or nullptr for none).
Definition: my_alloc.h:277
size_t m_allocated_size
Total allocated size for this MEM_ROOT.
Definition: my_alloc.h:412
Block * AllocBlock(size_t wanted_length, size_t minimum_length)
Allocate a new block of the given length (plus overhead for the block header).
Definition: my_alloc.cc:59
size_t m_max_capacity
Maximum amount of memory this MEM_ROOT can hold.
Definition: my_alloc.h:405
~MEM_ROOT()
Definition: my_alloc.h:130
bool get_error_for_capacity_exceeded() const
Return whether error is to be reported when maximum capacity exceeds for MEM_ROOT.
Definition: my_alloc.h:268
bool m_error_for_capacity_exceeded
If enabled, exceeding the capacity will lead to a my_error() call.
Definition: my_alloc.h:415
char * m_current_free_start
Start (inclusive) of the current free block.
Definition: my_alloc.h:390
void set_error_for_capacity_exceeded(bool report_error)
Enable/disable error reporting for exceeding the maximum capacity.
Definition: my_alloc.h:260
void * Alloc(size_t length)
Allocate memory.
Definition: my_alloc.h:145
static void FreeBlocks(Block *start)
Free all blocks in a linked list, starting at the given block.
Definition: my_alloc.cc:212
static char s_dummy_target
Something to point on that exists solely to never return nullptr from Alloc(0).
Definition: my_alloc.h:370
bool inited() const
Whether the constructor has run or not.
Definition: my_alloc.h:236
MEM_ROOT(const MEM_ROOT &)=delete
void set_max_capacity(size_t max_capacity)
Set maximum capacity for this MEM_ROOT.
Definition: my_alloc.h:245
void(* m_error_handler)(void)
Definition: my_alloc.h:417
std::pair< char *, char * > Peek() const
Get the bounds of the currently allocated memory block.
Definition: my_alloc.h:318