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