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