1/*****************************************************************************
2
3Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2017, MariaDB Corporation.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program; if not, write to the Free Software Foundation, Inc.,
1651 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/********************************************************************//**
21@file include/mem0mem.ic
22The memory management
23
24Created 6/8/1994 Heikki Tuuri
25*************************************************************************/
26
27#include "ut0new.h"
28
29#ifdef UNIV_DEBUG
30# define mem_heap_create_block(heap, n, type, file_name, line) \
31 mem_heap_create_block_func(heap, n, file_name, line, type)
32# define mem_heap_create_at(N, file_name, line) \
33 mem_heap_create_func(N, file_name, line, MEM_HEAP_DYNAMIC)
34#else /* UNIV_DEBUG */
35# define mem_heap_create_block(heap, n, type, file_name, line) \
36 mem_heap_create_block_func(heap, n, type)
37# define mem_heap_create_at(N, file_name, line) \
38 mem_heap_create_func(N, MEM_HEAP_DYNAMIC)
39#endif /* UNIV_DEBUG */
40/***************************************************************//**
41Creates a memory heap block where data can be allocated.
42@return own: memory heap block, NULL if did not succeed (only possible
43for MEM_HEAP_BTR_SEARCH type heaps) */
44mem_block_t*
45mem_heap_create_block_func(
46/*=======================*/
47 mem_heap_t* heap, /*!< in: memory heap or NULL if first block
48 should be created */
49 ulint n, /*!< in: number of bytes needed for user data */
50#ifdef UNIV_DEBUG
51 const char* file_name,/*!< in: file name where created */
52 unsigned line, /*!< in: line where created */
53#endif /* UNIV_DEBUG */
54 ulint type); /*!< in: type of heap: MEM_HEAP_DYNAMIC or
55 MEM_HEAP_BUFFER */
56
57/******************************************************************//**
58Frees a block from a memory heap. */
59void
60mem_heap_block_free(
61/*================*/
62 mem_heap_t* heap, /*!< in: heap */
63 mem_block_t* block); /*!< in: block to free */
64
65/******************************************************************//**
66Frees the free_block field from a memory heap. */
67void
68mem_heap_free_block_free(
69/*=====================*/
70 mem_heap_t* heap); /*!< in: heap */
71
72/***************************************************************//**
73Adds a new block to a memory heap.
74@param[in] heap memory heap
75@param[in] n number of bytes needed
76@return created block, NULL if did not succeed (only possible for
77MEM_HEAP_BTR_SEARCH type heaps) */
78mem_block_t*
79mem_heap_add_block(
80 mem_heap_t* heap,
81 ulint n);
82
83UNIV_INLINE
84void
85mem_block_set_len(mem_block_t* block, ulint len)
86{
87 ut_ad(len > 0);
88
89 block->len = len;
90}
91
92UNIV_INLINE
93ulint
94mem_block_get_len(mem_block_t* block)
95{
96 return(block->len);
97}
98
99UNIV_INLINE
100void
101mem_block_set_type(mem_block_t* block, ulint type)
102{
103 ut_ad((type == MEM_HEAP_DYNAMIC) || (type == MEM_HEAP_BUFFER)
104 || (type == MEM_HEAP_BUFFER + MEM_HEAP_BTR_SEARCH));
105
106 block->type = type;
107}
108
109UNIV_INLINE
110ulint
111mem_block_get_type(mem_block_t* block)
112{
113 return(block->type);
114}
115
116UNIV_INLINE
117void
118mem_block_set_free(mem_block_t* block, ulint free)
119{
120 ut_ad(free > 0);
121 ut_ad(free <= mem_block_get_len(block));
122
123 block->free = free;
124}
125
126UNIV_INLINE
127ulint
128mem_block_get_free(mem_block_t* block)
129{
130 return(block->free);
131}
132
133UNIV_INLINE
134void
135mem_block_set_start(mem_block_t* block, ulint start)
136{
137 ut_ad(start > 0);
138
139 block->start = start;
140}
141
142UNIV_INLINE
143ulint
144mem_block_get_start(mem_block_t* block)
145{
146 return(block->start);
147}
148
149/** Checks that an object is a memory heap block
150@param[in] block Memory block to check. */
151UNIV_INLINE
152void
153mem_block_validate(
154 const mem_block_t* block)
155{
156 ut_a(block->magic_n == MEM_BLOCK_MAGIC_N);
157}
158
159/** Allocates and zero-fills n bytes of memory from a memory heap.
160@param[in] heap memory heap
161@param[in] n number of bytes; if the heap is allowed to grow into
162the buffer pool, this must be <= MEM_MAX_ALLOC_IN_BUF
163@return allocated, zero-filled storage */
164UNIV_INLINE
165void*
166mem_heap_zalloc(
167 mem_heap_t* heap,
168 ulint n)
169{
170 ut_ad(heap);
171 ut_ad(!(heap->type & MEM_HEAP_BTR_SEARCH));
172 return(memset(mem_heap_alloc(heap, n), 0, n));
173}
174
175/** Allocates n bytes of memory from a memory heap.
176@param[in] heap memory heap
177@param[in] n number of bytes; if the heap is allowed to grow into
178the buffer pool, this must be <= MEM_MAX_ALLOC_IN_BUF
179@return allocated storage, NULL if did not succeed (only possible for
180MEM_HEAP_BTR_SEARCH type heaps) */
181UNIV_INLINE
182void*
183mem_heap_alloc(
184 mem_heap_t* heap,
185 ulint n)
186{
187 mem_block_t* block;
188 void* buf;
189 ulint free;
190
191 ut_d(mem_block_validate(heap));
192
193 block = UT_LIST_GET_LAST(heap->base);
194
195 ut_ad(!(block->type & MEM_HEAP_BUFFER) || (n <= MEM_MAX_ALLOC_IN_BUF));
196
197 /* Check if there is enough space in block. If not, create a new
198 block to the heap */
199
200 if (mem_block_get_len(block)
201 < mem_block_get_free(block) + MEM_SPACE_NEEDED(n)) {
202
203 block = mem_heap_add_block(heap, n);
204
205 if (block == NULL) {
206
207 return(NULL);
208 }
209 }
210
211 free = mem_block_get_free(block);
212
213 buf = (byte*) block + free;
214
215 mem_block_set_free(block, free + MEM_SPACE_NEEDED(n));
216
217 UNIV_MEM_ALLOC(buf, n);
218 return(buf);
219}
220
221/** Returns a pointer to the heap top.
222@param[in] heap memory heap
223@return pointer to the heap top */
224UNIV_INLINE
225byte*
226mem_heap_get_heap_top(
227 mem_heap_t* heap)
228{
229 mem_block_t* block;
230 byte* buf;
231
232 ut_d(mem_block_validate(heap));
233
234 block = UT_LIST_GET_LAST(heap->base);
235
236 buf = (byte*) block + mem_block_get_free(block);
237
238 return(buf);
239}
240
241/** Frees the space in a memory heap exceeding the pointer given.
242The pointer must have been acquired from mem_heap_get_heap_top.
243The first memory block of the heap is not freed.
244@param[in] heap heap from which to free
245@param[in] old_top pointer to old top of heap */
246UNIV_INLINE
247void
248mem_heap_free_heap_top(
249 mem_heap_t* heap,
250 byte* old_top)
251{
252 mem_block_t* block;
253 mem_block_t* prev_block;
254
255 ut_d(mem_heap_validate(heap));
256
257 block = UT_LIST_GET_LAST(heap->base);
258
259 while (block != NULL) {
260 if (((byte*) block + mem_block_get_free(block) >= old_top)
261 && ((byte*) block <= old_top)) {
262 /* Found the right block */
263
264 break;
265 }
266
267 /* Store prev_block value before freeing the current block
268 (the current block will be erased in freeing) */
269
270 prev_block = UT_LIST_GET_PREV(list, block);
271
272 mem_heap_block_free(heap, block);
273
274 block = prev_block;
275 }
276
277 ut_ad(block);
278
279 /* Set the free field of block */
280 mem_block_set_free(block,
281 ulint(old_top - reinterpret_cast<byte*>(block)));
282
283 ut_ad(mem_block_get_start(block) <= mem_block_get_free(block));
284 UNIV_MEM_FREE(old_top, (byte*) block + block->len - old_top);
285
286 /* If free == start, we may free the block if it is not the first
287 one */
288
289 if ((heap != block) && (mem_block_get_free(block)
290 == mem_block_get_start(block))) {
291 mem_heap_block_free(heap, block);
292 }
293}
294
295/** Empties a memory heap.
296The first memory block of the heap is not freed.
297@param[in] heap heap to empty */
298UNIV_INLINE
299void
300mem_heap_empty(
301 mem_heap_t* heap)
302{
303 mem_heap_free_heap_top(heap, (byte*) heap + mem_block_get_start(heap));
304
305 if (heap->free_block) {
306 mem_heap_free_block_free(heap);
307 }
308}
309
310/** Returns a pointer to the topmost element in a memory heap.
311The size of the element must be given.
312@param[in] heap memory heap
313@param[in] n size of the topmost element
314@return pointer to the topmost element */
315UNIV_INLINE
316void*
317mem_heap_get_top(
318 mem_heap_t* heap,
319 ulint n)
320{
321 mem_block_t* block;
322 byte* buf;
323
324 ut_d(mem_block_validate(heap));
325
326 block = UT_LIST_GET_LAST(heap->base);
327
328 buf = (byte*) block + mem_block_get_free(block) - MEM_SPACE_NEEDED(n);
329
330 return((void*) buf);
331}
332
333/** Checks if a given chunk of memory is the topmost element stored in the
334heap. If this is the case, then calling mem_heap_free_top() would free
335that element from the heap.
336@param[in] heap memory heap
337@param[in] buf presumed topmost element
338@param[in] buf_sz size of buf in bytes
339@return true if topmost */
340UNIV_INLINE
341bool
342mem_heap_is_top(
343 mem_heap_t* heap,
344 const void* buf,
345 ulint buf_sz)
346{
347 const byte* first_free_byte;
348 const byte* presumed_start_of_buf;
349
350 ut_d(mem_block_validate(heap));
351
352 first_free_byte = mem_heap_get_heap_top(heap);
353
354 presumed_start_of_buf = first_free_byte - MEM_SPACE_NEEDED(buf_sz);
355
356 return(presumed_start_of_buf == buf);
357}
358
359/*****************************************************************//**
360Allocate a new chunk of memory from a memory heap, possibly discarding
361the topmost element. If the memory chunk specified with (top, top_sz)
362is the topmost element, then it will be discarded, otherwise it will
363be left untouched and this function will be equivallent to
364mem_heap_alloc().
365@return allocated storage, NULL if did not succeed (only possible for
366MEM_HEAP_BTR_SEARCH type heaps) */
367UNIV_INLINE
368void*
369mem_heap_replace(
370/*=============*/
371 mem_heap_t* heap, /*!< in/out: memory heap */
372 const void* top, /*!< in: chunk to discard if possible */
373 ulint top_sz, /*!< in: size of top in bytes */
374 ulint new_sz) /*!< in: desired size of the new chunk */
375{
376 if (mem_heap_is_top(heap, top, top_sz)) {
377 mem_heap_free_top(heap, top_sz);
378 }
379
380 return(mem_heap_alloc(heap, new_sz));
381}
382
383/*****************************************************************//**
384Allocate a new chunk of memory from a memory heap, possibly discarding
385the topmost element and then copy the specified data to it. If the memory
386chunk specified with (top, top_sz) is the topmost element, then it will be
387discarded, otherwise it will be left untouched and this function will be
388equivallent to mem_heap_dup().
389@return allocated storage, NULL if did not succeed (only possible for
390MEM_HEAP_BTR_SEARCH type heaps) */
391UNIV_INLINE
392void*
393mem_heap_dup_replace(
394/*=================*/
395 mem_heap_t* heap, /*!< in/out: memory heap */
396 const void* top, /*!< in: chunk to discard if possible */
397 ulint top_sz, /*!< in: size of top in bytes */
398 const void* data, /*!< in: new data to duplicate */
399 ulint data_sz)/*!< in: size of data in bytes */
400{
401 void* p = mem_heap_replace(heap, top, top_sz, data_sz);
402
403 memcpy(p, data, data_sz);
404
405 return(p);
406}
407
408/*****************************************************************//**
409Allocate a new chunk of memory from a memory heap, possibly discarding
410the topmost element and then copy the specified string to it. If the memory
411chunk specified with (top, top_sz) is the topmost element, then it will be
412discarded, otherwise it will be left untouched and this function will be
413equivallent to mem_heap_strdup().
414@return allocated string, NULL if did not succeed (only possible for
415MEM_HEAP_BTR_SEARCH type heaps) */
416UNIV_INLINE
417char*
418mem_heap_strdup_replace(
419/*====================*/
420 mem_heap_t* heap, /*!< in/out: memory heap */
421 const void* top, /*!< in: chunk to discard if possible */
422 ulint top_sz, /*!< in: size of top in bytes */
423 const char* str) /*!< in: new data to duplicate */
424{
425 return(reinterpret_cast<char*>(mem_heap_dup_replace(
426 heap, top, top_sz, str, strlen(str) + 1)));
427}
428
429/*****************************************************************//**
430Frees the topmost element in a memory heap. The size of the element must be
431given. */
432UNIV_INLINE
433void
434mem_heap_free_top(
435/*==============*/
436 mem_heap_t* heap, /*!< in: memory heap */
437 ulint n) /*!< in: size of the topmost element */
438{
439 mem_block_t* block;
440
441 ut_d(mem_block_validate(heap));
442
443 block = UT_LIST_GET_LAST(heap->base);
444
445 /* Subtract the free field of block */
446 mem_block_set_free(block, mem_block_get_free(block)
447 - MEM_SPACE_NEEDED(n));
448
449 /* If free == start, we may free the block if it is not the first
450 one */
451
452 if ((heap != block) && (mem_block_get_free(block)
453 == mem_block_get_start(block))) {
454 mem_heap_block_free(heap, block);
455 } else {
456 UNIV_MEM_FREE((byte*) block + mem_block_get_free(block), n);
457 }
458}
459
460/** Creates a memory heap.
461NOTE: Use the corresponding macros instead of this function.
462A single user buffer of 'size' will fit in the block.
4630 creates a default size block.
464@param[in] size Desired start block size.
465@param[in] file_name File name where created
466@param[in] line Line where created
467@param[in] type Heap type
468@return own: memory heap, NULL if did not succeed (only possible for
469MEM_HEAP_BTR_SEARCH type heaps) */
470UNIV_INLINE
471mem_heap_t*
472mem_heap_create_func(
473 ulint size,
474#ifdef UNIV_DEBUG
475 const char* file_name,
476 unsigned line,
477#endif /* UNIV_DEBUG */
478 ulint type)
479{
480 mem_block_t* block;
481
482 if (!size) {
483 size = MEM_BLOCK_START_SIZE;
484 }
485
486 block = mem_heap_create_block(NULL, size, type, file_name, line);
487
488 if (block == NULL) {
489
490 return(NULL);
491 }
492
493 /* The first block should not be in buffer pool,
494 because it might be relocated to resize buffer pool. */
495 ut_ad(block->buf_block == NULL);
496
497 UT_LIST_INIT(block->base, &mem_block_t::list);
498
499 /* Add the created block itself as the first block in the list */
500 UT_LIST_ADD_FIRST(block->base, block);
501
502 return(block);
503}
504
505/** Frees the space occupied by a memory heap.
506NOTE: Use the corresponding macro instead of this function.
507@param[in] heap Heap to be freed */
508UNIV_INLINE
509void
510mem_heap_free(
511 mem_heap_t* heap)
512{
513 mem_block_t* block;
514 mem_block_t* prev_block;
515
516 ut_d(mem_block_validate(heap));
517
518 block = UT_LIST_GET_LAST(heap->base);
519
520 if (heap->free_block) {
521 mem_heap_free_block_free(heap);
522 }
523
524 while (block != NULL) {
525 /* Store the contents of info before freeing current block
526 (it is erased in freeing) */
527
528 prev_block = UT_LIST_GET_PREV(list, block);
529
530 mem_heap_block_free(heap, block);
531
532 block = prev_block;
533 }
534}
535
536/*****************************************************************//**
537Returns the space in bytes occupied by a memory heap. */
538UNIV_INLINE
539ulint
540mem_heap_get_size(
541/*==============*/
542 mem_heap_t* heap) /*!< in: heap */
543{
544 ulint size = 0;
545
546 ut_d(mem_block_validate(heap));
547
548 size = heap->total_size;
549
550 if (heap->free_block) {
551 size += srv_page_size;
552 }
553
554 return(size);
555}
556
557/**********************************************************************//**
558Duplicates a NUL-terminated string.
559@return own: a copy of the string, must be deallocated with ut_free */
560UNIV_INLINE
561char*
562mem_strdup(
563/*=======*/
564 const char* str) /*!< in: string to be copied */
565{
566 ulint len = strlen(str) + 1;
567 return(static_cast<char*>(memcpy(ut_malloc_nokey(len), str, len)));
568}
569
570/**********************************************************************//**
571Makes a NUL-terminated copy of a nonterminated string.
572@return own: a copy of the string, must be deallocated with ut_free */
573UNIV_INLINE
574char*
575mem_strdupl(
576/*========*/
577 const char* str, /*!< in: string to be copied */
578 ulint len) /*!< in: length of str, in bytes */
579{
580 char* s = static_cast<char*>(ut_malloc_nokey(len + 1));
581 s[len] = 0;
582 return(static_cast<char*>(memcpy(s, str, len)));
583}
584