1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, 2018, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /**************************************************//** |
21 | @file include/mem0mem.h |
22 | The memory management |
23 | |
24 | Created 6/9/1994 Heikki Tuuri |
25 | *******************************************************/ |
26 | |
27 | #ifndef mem0mem_h |
28 | #define mem0mem_h |
29 | |
30 | #include "univ.i" |
31 | #include "ut0mem.h" |
32 | #include "ut0byte.h" |
33 | #include "ut0rnd.h" |
34 | #include "mach0data.h" |
35 | |
36 | #include <memory> |
37 | |
38 | /* -------------------- MEMORY HEAPS ----------------------------- */ |
39 | |
40 | /** A block of a memory heap consists of the info structure |
41 | followed by an area of memory */ |
42 | typedef struct mem_block_info_t mem_block_t; |
43 | |
44 | /** A memory heap is a nonempty linear list of memory blocks */ |
45 | typedef mem_block_t mem_heap_t; |
46 | |
47 | /** Types of allocation for memory heaps: DYNAMIC means allocation from the |
48 | dynamic memory pool of the C compiler, BUFFER means allocation from the |
49 | buffer pool; the latter method is used for very big heaps */ |
50 | |
51 | #define MEM_HEAP_DYNAMIC 0 /* the most common type */ |
52 | #define MEM_HEAP_BUFFER 1 |
53 | #define MEM_HEAP_BTR_SEARCH 2 /* this flag can optionally be |
54 | ORed to MEM_HEAP_BUFFER, in which |
55 | case heap->free_block is used in |
56 | some cases for memory allocations, |
57 | and if it's NULL, the memory |
58 | allocation functions can return |
59 | NULL. */ |
60 | |
61 | /** Different type of heaps in terms of which datastructure is using them */ |
62 | #define MEM_HEAP_FOR_BTR_SEARCH (MEM_HEAP_BTR_SEARCH | MEM_HEAP_BUFFER) |
63 | #define MEM_HEAP_FOR_PAGE_HASH (MEM_HEAP_DYNAMIC) |
64 | #define MEM_HEAP_FOR_RECV_SYS (MEM_HEAP_BUFFER) |
65 | #define MEM_HEAP_FOR_LOCK_HEAP (MEM_HEAP_BUFFER) |
66 | |
67 | /** The following start size is used for the first block in the memory heap if |
68 | the size is not specified, i.e., 0 is given as the parameter in the call of |
69 | create. The standard size is the maximum (payload) size of the blocks used for |
70 | allocations of small buffers. */ |
71 | |
72 | #define MEM_BLOCK_START_SIZE 64 |
73 | #define MEM_BLOCK_STANDARD_SIZE \ |
74 | (srv_page_size >= 16384 ? 8000 : MEM_MAX_ALLOC_IN_BUF) |
75 | |
76 | /** If a memory heap is allowed to grow into the buffer pool, the following |
77 | is the maximum size for a single allocated buffer: */ |
78 | #define MEM_MAX_ALLOC_IN_BUF (srv_page_size - 200) |
79 | |
80 | /** Space needed when allocating for a user a field of length N. |
81 | The space is allocated only in multiples of UNIV_MEM_ALIGNMENT. */ |
82 | #define MEM_SPACE_NEEDED(N) ut_calc_align((N), UNIV_MEM_ALIGNMENT) |
83 | |
84 | #ifdef UNIV_DEBUG |
85 | /** Macro for memory heap creation. |
86 | @param[in] size Desired start block size. */ |
87 | # define mem_heap_create(size) \ |
88 | mem_heap_create_func((size), __FILE__, __LINE__, MEM_HEAP_DYNAMIC) |
89 | |
90 | /** Macro for memory heap creation. |
91 | @param[in] size Desired start block size. |
92 | @param[in] type Heap type */ |
93 | # define mem_heap_create_typed(size, type) \ |
94 | mem_heap_create_func((size), __FILE__, __LINE__, (type)) |
95 | |
96 | #else /* UNIV_DEBUG */ |
97 | /** Macro for memory heap creation. |
98 | @param[in] size Desired start block size. */ |
99 | # define mem_heap_create(size) mem_heap_create_func((size), MEM_HEAP_DYNAMIC) |
100 | |
101 | /** Macro for memory heap creation. |
102 | @param[in] size Desired start block size. |
103 | @param[in] type Heap type */ |
104 | # define mem_heap_create_typed(size, type) \ |
105 | mem_heap_create_func((size), (type)) |
106 | |
107 | #endif /* UNIV_DEBUG */ |
108 | |
109 | /** Creates a memory heap. |
110 | NOTE: Use the corresponding macros instead of this function. |
111 | A single user buffer of 'size' will fit in the block. |
112 | 0 creates a default size block. |
113 | @param[in] size Desired start block size. |
114 | @param[in] file_name File name where created |
115 | @param[in] line Line where created |
116 | @param[in] type Heap type |
117 | @return own: memory heap, NULL if did not succeed (only possible for |
118 | MEM_HEAP_BTR_SEARCH type heaps) */ |
119 | UNIV_INLINE |
120 | mem_heap_t* |
121 | mem_heap_create_func( |
122 | ulint size, |
123 | #ifdef UNIV_DEBUG |
124 | const char* file_name, |
125 | unsigned line, |
126 | #endif /* UNIV_DEBUG */ |
127 | ulint type); |
128 | |
129 | /** Frees the space occupied by a memory heap. |
130 | NOTE: Use the corresponding macro instead of this function. |
131 | @param[in] heap Heap to be freed */ |
132 | UNIV_INLINE |
133 | void |
134 | mem_heap_free( |
135 | mem_heap_t* heap); |
136 | |
137 | /** Allocates and zero-fills n bytes of memory from a memory heap. |
138 | @param[in] heap memory heap |
139 | @param[in] n number of bytes; if the heap is allowed to grow into |
140 | the buffer pool, this must be <= MEM_MAX_ALLOC_IN_BUF |
141 | @return allocated, zero-filled storage */ |
142 | UNIV_INLINE |
143 | void* |
144 | mem_heap_zalloc( |
145 | mem_heap_t* heap, |
146 | ulint n); |
147 | |
148 | /** Allocates n bytes of memory from a memory heap. |
149 | @param[in] heap memory heap |
150 | @param[in] n number of bytes; if the heap is allowed to grow into |
151 | the buffer pool, this must be <= MEM_MAX_ALLOC_IN_BUF |
152 | @return allocated storage, NULL if did not succeed (only possible for |
153 | MEM_HEAP_BTR_SEARCH type heaps) */ |
154 | UNIV_INLINE |
155 | void* |
156 | mem_heap_alloc( |
157 | mem_heap_t* heap, |
158 | ulint n); |
159 | |
160 | /** Returns a pointer to the heap top. |
161 | @param[in] heap memory heap |
162 | @return pointer to the heap top */ |
163 | UNIV_INLINE |
164 | byte* |
165 | mem_heap_get_heap_top( |
166 | mem_heap_t* heap); |
167 | |
168 | /** Frees the space in a memory heap exceeding the pointer given. |
169 | The pointer must have been acquired from mem_heap_get_heap_top. |
170 | The first memory block of the heap is not freed. |
171 | @param[in] heap heap from which to free |
172 | @param[in] old_top pointer to old top of heap */ |
173 | UNIV_INLINE |
174 | void |
175 | mem_heap_free_heap_top( |
176 | mem_heap_t* heap, |
177 | byte* old_top); |
178 | |
179 | /** Empties a memory heap. |
180 | The first memory block of the heap is not freed. |
181 | @param[in] heap heap to empty */ |
182 | UNIV_INLINE |
183 | void |
184 | mem_heap_empty( |
185 | mem_heap_t* heap); |
186 | |
187 | /** Returns a pointer to the topmost element in a memory heap. |
188 | The size of the element must be given. |
189 | @param[in] heap memory heap |
190 | @param[in] n size of the topmost element |
191 | @return pointer to the topmost element */ |
192 | UNIV_INLINE |
193 | void* |
194 | mem_heap_get_top( |
195 | mem_heap_t* heap, |
196 | ulint n); |
197 | |
198 | /** Checks if a given chunk of memory is the topmost element stored in the |
199 | heap. If this is the case, then calling mem_heap_free_top() would free |
200 | that element from the heap. |
201 | @param[in] heap memory heap |
202 | @param[in] buf presumed topmost element |
203 | @param[in] buf_sz size of buf in bytes |
204 | @return true if topmost */ |
205 | UNIV_INLINE |
206 | bool |
207 | mem_heap_is_top( |
208 | mem_heap_t* heap, |
209 | const void* buf, |
210 | ulint buf_sz) |
211 | MY_ATTRIBUTE((warn_unused_result)); |
212 | |
213 | /*****************************************************************//** |
214 | Allocate a new chunk of memory from a memory heap, possibly discarding |
215 | the topmost element. If the memory chunk specified with (top, top_sz) |
216 | is the topmost element, then it will be discarded, otherwise it will |
217 | be left untouched and this function will be equivallent to |
218 | mem_heap_alloc(). |
219 | @return allocated storage, NULL if did not succeed (only possible for |
220 | MEM_HEAP_BTR_SEARCH type heaps) */ |
221 | UNIV_INLINE |
222 | void* |
223 | mem_heap_replace( |
224 | /*=============*/ |
225 | mem_heap_t* heap, /*!< in/out: memory heap */ |
226 | const void* top, /*!< in: chunk to discard if possible */ |
227 | ulint top_sz, /*!< in: size of top in bytes */ |
228 | ulint new_sz);/*!< in: desired size of the new chunk */ |
229 | /*****************************************************************//** |
230 | Allocate a new chunk of memory from a memory heap, possibly discarding |
231 | the topmost element and then copy the specified data to it. If the memory |
232 | chunk specified with (top, top_sz) is the topmost element, then it will be |
233 | discarded, otherwise it will be left untouched and this function will be |
234 | equivallent to mem_heap_dup(). |
235 | @return allocated storage, NULL if did not succeed (only possible for |
236 | MEM_HEAP_BTR_SEARCH type heaps) */ |
237 | UNIV_INLINE |
238 | void* |
239 | mem_heap_dup_replace( |
240 | /*=================*/ |
241 | mem_heap_t* heap, /*!< in/out: memory heap */ |
242 | const void* top, /*!< in: chunk to discard if possible */ |
243 | ulint top_sz, /*!< in: size of top in bytes */ |
244 | const void* data, /*!< in: new data to duplicate */ |
245 | ulint data_sz);/*!< in: size of data in bytes */ |
246 | /*****************************************************************//** |
247 | Allocate a new chunk of memory from a memory heap, possibly discarding |
248 | the topmost element and then copy the specified string to it. If the memory |
249 | chunk specified with (top, top_sz) is the topmost element, then it will be |
250 | discarded, otherwise it will be left untouched and this function will be |
251 | equivallent to mem_heap_strdup(). |
252 | @return allocated string, NULL if did not succeed (only possible for |
253 | MEM_HEAP_BTR_SEARCH type heaps) */ |
254 | UNIV_INLINE |
255 | char* |
256 | mem_heap_strdup_replace( |
257 | /*====================*/ |
258 | mem_heap_t* heap, /*!< in/out: memory heap */ |
259 | const void* top, /*!< in: chunk to discard if possible */ |
260 | ulint top_sz, /*!< in: size of top in bytes */ |
261 | const char* str); /*!< in: new data to duplicate */ |
262 | /*****************************************************************//** |
263 | Frees the topmost element in a memory heap. |
264 | The size of the element must be given. */ |
265 | UNIV_INLINE |
266 | void |
267 | mem_heap_free_top( |
268 | /*==============*/ |
269 | mem_heap_t* heap, /*!< in: memory heap */ |
270 | ulint n); /*!< in: size of the topmost element */ |
271 | /*****************************************************************//** |
272 | Returns the space in bytes occupied by a memory heap. */ |
273 | UNIV_INLINE |
274 | ulint |
275 | mem_heap_get_size( |
276 | /*==============*/ |
277 | mem_heap_t* heap); /*!< in: heap */ |
278 | |
279 | /**********************************************************************//** |
280 | Duplicates a NUL-terminated string. |
281 | @return own: a copy of the string, must be deallocated with ut_free */ |
282 | UNIV_INLINE |
283 | char* |
284 | mem_strdup( |
285 | /*=======*/ |
286 | const char* str); /*!< in: string to be copied */ |
287 | /**********************************************************************//** |
288 | Makes a NUL-terminated copy of a nonterminated string. |
289 | @return own: a copy of the string, must be deallocated with ut_free */ |
290 | UNIV_INLINE |
291 | char* |
292 | mem_strdupl( |
293 | /*========*/ |
294 | const char* str, /*!< in: string to be copied */ |
295 | ulint len); /*!< in: length of str, in bytes */ |
296 | |
297 | /** Duplicate a block of data, allocated from a memory heap. |
298 | @param[in] heap memory heap where string is allocated |
299 | @param[in] data block of data to be copied |
300 | @param[in] len length of data, in bytes |
301 | @return own: a copy of data */ |
302 | inline |
303 | void* |
304 | mem_heap_dup(mem_heap_t* heap, const void* data, size_t len) |
305 | { |
306 | return(memcpy(mem_heap_alloc(heap, len), data, len)); |
307 | } |
308 | |
309 | /** Duplicate a NUL-terminated string, allocated from a memory heap. |
310 | @param[in] heap memory heap where string is allocated |
311 | @param[in] str string to be copied |
312 | @return own: a copy of the string */ |
313 | inline |
314 | char* |
315 | mem_heap_strdup(mem_heap_t* heap, const char* str) |
316 | { |
317 | return(static_cast<char*>(mem_heap_dup(heap, str, strlen(str) + 1))); |
318 | } |
319 | |
320 | /** Duplicate a string, allocated from a memory heap. |
321 | @param[in] heap memory heap where string is allocated |
322 | @param[in] str string to be copied |
323 | @param[in] len length of str, in bytes |
324 | @return own: a NUL-terminated copy of str */ |
325 | inline |
326 | char* |
327 | mem_heap_strdupl(mem_heap_t* heap, const char* str, size_t len) |
328 | { |
329 | char* s = static_cast<char*>(mem_heap_alloc(heap, len + 1)); |
330 | s[len] = 0; |
331 | return(static_cast<char*>(memcpy(s, str, len))); |
332 | } |
333 | |
334 | /**********************************************************************//** |
335 | Concatenate two strings and return the result, using a memory heap. |
336 | @return own: the result */ |
337 | char* |
338 | mem_heap_strcat( |
339 | /*============*/ |
340 | mem_heap_t* heap, /*!< in: memory heap where string is allocated */ |
341 | const char* s1, /*!< in: string 1 */ |
342 | const char* s2); /*!< in: string 2 */ |
343 | |
344 | /****************************************************************//** |
345 | A simple sprintf replacement that dynamically allocates the space for the |
346 | formatted string from the given heap. This supports a very limited set of |
347 | the printf syntax: types 's' and 'u' and length modifier 'l' (which is |
348 | required for the 'u' type). |
349 | @return heap-allocated formatted string */ |
350 | char* |
351 | mem_heap_printf( |
352 | /*============*/ |
353 | mem_heap_t* heap, /*!< in: memory heap */ |
354 | const char* format, /*!< in: format string */ |
355 | ...) MY_ATTRIBUTE ((format (printf, 2, 3))); |
356 | |
357 | /** Checks that an object is a memory heap (or a block of it) |
358 | @param[in] heap Memory heap to check */ |
359 | UNIV_INLINE |
360 | void |
361 | mem_block_validate( |
362 | const mem_heap_t* heap); |
363 | |
364 | #ifdef UNIV_DEBUG |
365 | /** Validates the contents of a memory heap. |
366 | Asserts that the memory heap is consistent |
367 | @param[in] heap Memory heap to validate */ |
368 | void |
369 | mem_heap_validate( |
370 | const mem_heap_t* heap); |
371 | |
372 | #endif /* UNIV_DEBUG */ |
373 | |
374 | /*#######################################################################*/ |
375 | |
376 | /** The info structure stored at the beginning of a heap block */ |
377 | struct mem_block_info_t { |
378 | ulint magic_n;/* magic number for debugging */ |
379 | #ifdef UNIV_DEBUG |
380 | char file_name[8];/* file name where the mem heap was created */ |
381 | unsigned line; /*!< line number where the mem heap was created */ |
382 | #endif /* UNIV_DEBUG */ |
383 | UT_LIST_BASE_NODE_T(mem_block_t) base; /* In the first block in the |
384 | the list this is the base node of the list of blocks; |
385 | in subsequent blocks this is undefined */ |
386 | UT_LIST_NODE_T(mem_block_t) list; /* This contains pointers to next |
387 | and prev in the list. The first block allocated |
388 | to the heap is also the first block in this list, |
389 | though it also contains the base node of the list. */ |
390 | ulint len; /*!< physical length of this block in bytes */ |
391 | ulint total_size; /*!< physical length in bytes of all blocks |
392 | in the heap. This is defined only in the base |
393 | node and is set to ULINT_UNDEFINED in others. */ |
394 | ulint type; /*!< type of heap: MEM_HEAP_DYNAMIC, or |
395 | MEM_HEAP_BUF possibly ORed to MEM_HEAP_BTR_SEARCH */ |
396 | ulint free; /*!< offset in bytes of the first free position for |
397 | user data in the block */ |
398 | ulint start; /*!< the value of the struct field 'free' at the |
399 | creation of the block */ |
400 | |
401 | void* free_block; |
402 | /* if the MEM_HEAP_BTR_SEARCH bit is set in type, |
403 | and this is the heap root, this can contain an |
404 | allocated buffer frame, which can be appended as a |
405 | free block to the heap, if we need more space; |
406 | otherwise, this is NULL */ |
407 | void* buf_block; |
408 | /* if this block has been allocated from the buffer |
409 | pool, this contains the buf_block_t handle; |
410 | otherwise, this is NULL */ |
411 | }; |
412 | |
413 | #define MEM_BLOCK_MAGIC_N 764741555 |
414 | #define MEM_FREED_BLOCK_MAGIC_N 547711122 |
415 | |
416 | /* Header size for a memory heap block */ |
417 | #define ut_calc_align(sizeof(mem_block_info_t),\ |
418 | UNIV_MEM_ALIGNMENT) |
419 | |
420 | #include "mem0mem.ic" |
421 | |
422 | /** A C++ wrapper class to the mem_heap_t routines, so that it can be used |
423 | as an STL allocator */ |
424 | template<typename T> |
425 | class mem_heap_allocator |
426 | { |
427 | public: |
428 | typedef T value_type; |
429 | typedef size_t size_type; |
430 | typedef ptrdiff_t difference_type; |
431 | typedef T* pointer; |
432 | typedef const T* const_pointer; |
433 | typedef T& reference; |
434 | typedef const T& const_reference; |
435 | |
436 | mem_heap_allocator(mem_heap_t* heap) : m_heap(heap) { } |
437 | |
438 | mem_heap_allocator(const mem_heap_allocator& other) |
439 | : |
440 | m_heap(other.m_heap) |
441 | { |
442 | // Do nothing |
443 | } |
444 | |
445 | template <typename U> |
446 | mem_heap_allocator (const mem_heap_allocator<U>& other) |
447 | : |
448 | m_heap(other.m_heap) |
449 | { |
450 | // Do nothing |
451 | } |
452 | |
453 | ~mem_heap_allocator() { m_heap = 0; } |
454 | |
455 | size_type max_size() const |
456 | { |
457 | return(ULONG_MAX / sizeof(T)); |
458 | } |
459 | |
460 | /** This function returns a pointer to the first element of a newly |
461 | allocated array large enough to contain n objects of type T; only the |
462 | memory is allocated, and the objects are not constructed. Moreover, |
463 | an optional pointer argument (that points to an object already |
464 | allocated by mem_heap_allocator) can be used as a hint to the |
465 | implementation about where the new memory should be allocated in |
466 | order to improve locality. */ |
467 | pointer allocate(size_type n) |
468 | { |
469 | return(reinterpret_cast<pointer>( |
470 | mem_heap_alloc(m_heap, n * sizeof(T)))); |
471 | } |
472 | pointer allocate(size_type n, const_pointer) { return allocate(n); } |
473 | |
474 | void deallocate(pointer, size_type) {} |
475 | |
476 | pointer address (reference r) const { return(&r); } |
477 | |
478 | const_pointer address (const_reference r) const { return(&r); } |
479 | |
480 | void construct(pointer p, const_reference t) |
481 | { |
482 | new (reinterpret_cast<void*>(p)) T(t); |
483 | } |
484 | |
485 | void destroy(pointer p) |
486 | { |
487 | (reinterpret_cast<T*>(p))->~T(); |
488 | } |
489 | |
490 | /** Allocators are required to supply the below template class member |
491 | which enables the possibility of obtaining a related allocator, |
492 | parametrized in terms of a different type. For example, given an |
493 | allocator type IntAllocator for objects of type int, a related |
494 | allocator type for objects of type long could be obtained using |
495 | IntAllocator::rebind<long>::other */ |
496 | template <typename U> |
497 | struct rebind |
498 | { |
499 | typedef mem_heap_allocator<U> other; |
500 | }; |
501 | |
502 | private: |
503 | mem_heap_t* m_heap; |
504 | template <typename U> friend class mem_heap_allocator; |
505 | }; |
506 | |
507 | template <class T> |
508 | bool operator== (const mem_heap_allocator<T>& left, |
509 | const mem_heap_allocator<T>& right) |
510 | { |
511 | return(left.heap == right.heap); |
512 | } |
513 | |
514 | template <class T> |
515 | bool operator!= (const mem_heap_allocator<T>& left, |
516 | const mem_heap_allocator<T>& right) |
517 | { |
518 | return(left.heap != right.heap); |
519 | } |
520 | |
521 | #endif |
522 | |