mirror of
https://github.com/MariaDB/server.git
synced 2025-01-20 14:02:32 +01:00
025ddfea28
innobase/dict/dict0crea.c: Remove unneeded prototypes for static functions Remove unused parameters from some functions Replace some assertions with compile-time checks dict_create_add_foreigns_to_dictionary(): allocate space dynamically for the SQL, and quote quotes innobase/dict/dict0dict.c: Remove unnecessary prototypes for static functions dict_tables_have_same_db(): Remove length limitation dict_remove_db_name(): Use strchr() dict_get_db_name_len(): Use strchr() Replace mem_heap_alloc()+strlen()+memcpy() with mem_heap_strdup() Remove unnecessary strlen() calls Allocate space dynamically for generated strings dict_scan_id(): allow quotes within quoted strings innobase/dict/dict0load.c: Remove unnecessary strlen() calls Replace mem_heap_alloc()+strlen()+memcpy() with mem_heap_strdup() innobase/dict/dict0mem.c: Replace mem_heap_alloc()+strlen()+memcpy() with mem_heap_strdup() innobase/eval/eval0eval.c: Make TO_CHAR() work with any machine word width innobase/fil/fil0fil.c: Replace mem_alloc()+strlen()+strcpy() with mem_strdup() innobase/ibuf/ibuf0ibuf.c: Make some global variables static Add #ifdef UNIV_IBUF_DEBUG around debug statements innobase/include/data0data.h: Add #ifdef UNIV_DEBUG around dtuple_validate() innobase/include/data0data.ic: Replace = with == in ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N) innobase/include/dict0dict.h: Add const qualifiers innobase/include/lock0lock.h: Add UL suffixes to unsigned long masks innobase/include/log0log.h: Remove unused parameter "type" of log_group_write_buf() innobase/include/mem0mem.h: Add mem_strdup(), mem_strdupl(), mem_strdupq(), mem_heap_strdup(), and mem_heap_strdupl() innobase/include/mem0mem.ic: Add mem_strdup(), mem_strdupl(), mem_strdupq(), mem_heap_strdup(), and mem_heap_strdupl() innobase/include/row0uins.h: Remove unused parameter "thr" of row_undo_ins() innobase/include/row0undo.h: Remvoe unused parameter "thr" of row_undo_search_clust_to_pcur() innobase/include/ut0byte.h: Add const qualifier to ut_cpy_in_lower_case() Remove parameter "len" of ut_cmp_in_lower_case() innobase/include/ut0mem.h: Add ut_strlenq(), ut_strcpyq() and ut_memcpyq() innobase/include/ut0mem.ic: Add ut_strlenq() innobase/include/ut0ut.h: Declare ut_sprintf() as a printf-style function innobase/lock/lock0lock.c: lock_clust_rec_modify_check_and_lock(): Remove unused variable "trx" innobase/log/log0log.c: Remove unused parameters innobase/log/log0recv.c: Remove parameter "type" from log_group_write_buf() innobase/mem/mem0mem.c: Simplify the initialization of block->init_block innobase/mtr/mtr0log.c: Add a debug assertion to mlog_parse_initial_log_record() innobase/page/page0cur.c: Add debug assertion to page_cur_insert_rec_write_log() Remove hard-coded buffer size in page_cur_parse_insert_rec() innobase/page/page0page.c: Remove unneeded variable rec innobase/pars/pars0opt.c: Correct a potential buffer overflow innobase/pars/pars0pars.c: Replace mem_heap_alloc()+strlen()+memcpy() with mem_heap_strdup() innobase/row/row0ins.c: Replace parameter "thr" with "trx" in row_ins_foreign_report_add_err() Remove unnecessary strlen() call Use strchr() innobase/row/row0mysql.c: Add row_mysql_is_recovered_tmp_table() Add row_mysql_is_system_table() Compare reserved table names with exact match Use strstr() and strchr() and mem_strdupl() Compute space needed for generated SQL, and allocate it dynamically innobase/row/row0purge.c: Remove unused parameters "thr" innobase/row/row0row.c: Simplify row_get_clust_rec() innobase/row/row0uins.c: Remove unused parameters "thr" innobase/row/row0umod.c: Remove unused variable "index" row_undo_mod_del_unmark_sec_and_undo_update(): Remove parameter "node" and variable "rec" Remove unused parameters "thr" innobase/row/row0undo.c: Remove unused parameters "thr" innobase/srv/srv0srv.c: Replace UT_NOT_USED() with __attribute__((unused)) innobase/srv/srv0start.c: Remove unnecessary strlen() calls Remove unused parameter "create_new_db" of open_or_create_log_file() innobase/trx/trx0roll.c: Replace mem_alloc()+strlen()+memcpy() with mem_strdup() innobase/trx/trx0sys.c: Remove unnecessary strlen() call innobase/ut/ut0byte.c: Add const qualifier to ut_cpy_in_lower_case() Remove parameter "len" of ut_cmp_in_lower_case() innobase/ut/ut0mem.c: Add ut_strlenq() and ut_memcpyq() sql/ha_innodb.cc: Remove parameter "len" of ut_cmp_in_lower_case()
358 lines
9.7 KiB
C
358 lines
9.7 KiB
C
/************************************************************************
|
|
The memory management
|
|
|
|
(c) 1994, 1995 Innobase Oy
|
|
|
|
Created 6/9/1994 Heikki Tuuri
|
|
*************************************************************************/
|
|
|
|
|
|
#include "mem0mem.h"
|
|
#ifdef UNIV_NONINL
|
|
#include "mem0mem.ic"
|
|
#endif
|
|
|
|
#include "mach0data.h"
|
|
#include "buf0buf.h"
|
|
#include "btr0sea.h"
|
|
#include "srv0srv.h"
|
|
#include "mem0dbg.c"
|
|
|
|
/*
|
|
THE MEMORY MANAGEMENT
|
|
=====================
|
|
|
|
The basic element of the memory management is called a memory
|
|
heap. A memory heap is conceptually a
|
|
stack from which memory can be allocated. The stack may grow infinitely.
|
|
The top element of the stack may be freed, or
|
|
the whole stack can be freed at one time. The advantage of the
|
|
memory heap concept is that we can avoid using the malloc and free
|
|
functions of C which are quite expensive, for example, on the Solaris + GCC
|
|
system (50 MHz Sparc, 1993) the pair takes 3 microseconds,
|
|
on Win NT + 100MHz Pentium, 2.5 microseconds.
|
|
When we use a memory heap,
|
|
we can allocate larger blocks of memory at a time and thus
|
|
reduce overhead. Slightly more efficient the method is when we
|
|
allocate the memory from the index page buffer pool, as we can
|
|
claim a new page fast. This is called buffer allocation.
|
|
When we allocate the memory from the dynamic memory of the
|
|
C environment, that is called dynamic allocation.
|
|
|
|
The default way of operation of the memory heap is the following.
|
|
First, when the heap is created, an initial block of memory is
|
|
allocated. In dynamic allocation this may be about 50 bytes.
|
|
If more space is needed, additional blocks are allocated
|
|
and they are put into a linked list.
|
|
After the initial block, each allocated block is twice the size of the
|
|
previous, until a threshold is attained, after which the sizes
|
|
of the blocks stay the same. An exception is, of course, the case
|
|
where the caller requests a memory buffer whose size is
|
|
bigger than the threshold. In that case a block big enough must
|
|
be allocated.
|
|
|
|
The heap is physically arranged so that if the current block
|
|
becomes full, a new block is allocated and always inserted in the
|
|
chain of blocks as the last block.
|
|
|
|
In the debug version of the memory management, all the allocated
|
|
heaps are kept in a list (which is implemented as a hash table).
|
|
Thus we can notice if the caller tries to free an already freed
|
|
heap. In addition, each buffer given to the caller contains
|
|
start field at the start and a trailer field at the end of the buffer.
|
|
|
|
The start field has the following content:
|
|
A. sizeof(ulint) bytes of field length (in the standard byte order)
|
|
B. sizeof(ulint) bytes of check field (a random number)
|
|
|
|
The trailer field contains:
|
|
A. sizeof(ulint) bytes of check field (the same random number as at the start)
|
|
|
|
Thus we can notice if something has been copied over the
|
|
borders of the buffer, which is illegal.
|
|
The memory in the buffers is initialized to a random byte sequence.
|
|
After freeing, all the blocks in the heap are set to random bytes
|
|
to help us discover errors which result from the use of
|
|
buffers in an already freed heap. */
|
|
|
|
#ifdef MEM_PERIODIC_CHECK
|
|
|
|
ibool mem_block_list_inited;
|
|
/* List of all mem blocks allocated; protected by the mem_comm_pool mutex */
|
|
UT_LIST_BASE_NODE_T(mem_block_t) mem_block_list;
|
|
|
|
#endif
|
|
|
|
/*******************************************************************
|
|
NOTE: Use the corresponding macro instead of this function.
|
|
Allocates a single buffer of memory from the dynamic memory of
|
|
the C compiler. Is like malloc of C. The buffer must be freed
|
|
with mem_free. */
|
|
|
|
void*
|
|
mem_alloc_func_noninline(
|
|
/*=====================*/
|
|
/* out, own: free storage, NULL if did not
|
|
succeed */
|
|
ulint n, /* in: desired number of bytes */
|
|
char* file_name, /* in: file name where created */
|
|
ulint line /* in: line where created */
|
|
)
|
|
{
|
|
return(mem_alloc_func(n, file_name, line));
|
|
}
|
|
|
|
/*******************************************************************
|
|
Creates a memory heap block where data can be allocated. */
|
|
|
|
mem_block_t*
|
|
mem_heap_create_block(
|
|
/*==================*/
|
|
/* out, own: memory heap block, NULL if did not
|
|
succeed */
|
|
mem_heap_t* heap,/* in: memory heap or NULL if first block should
|
|
be created */
|
|
ulint n, /* in: number of bytes needed for user data, or
|
|
if init_block is not NULL, its size in bytes */
|
|
void* init_block, /* in: init block in fast create, type must be
|
|
MEM_HEAP_DYNAMIC */
|
|
ulint type, /* in: type of heap: MEM_HEAP_DYNAMIC, or
|
|
MEM_HEAP_BUFFER possibly ORed to MEM_HEAP_BTR_SEARCH */
|
|
char* file_name,/* in: file name where created */
|
|
ulint line) /* in: line where created */
|
|
{
|
|
mem_block_t* block;
|
|
ulint len;
|
|
|
|
ut_ad((type == MEM_HEAP_DYNAMIC) || (type == MEM_HEAP_BUFFER)
|
|
|| (type == MEM_HEAP_BUFFER + MEM_HEAP_BTR_SEARCH));
|
|
|
|
if (heap && heap->magic_n != MEM_BLOCK_MAGIC_N) {
|
|
mem_analyze_corruption((byte*)heap);
|
|
}
|
|
|
|
/* In dynamic allocation, calculate the size: block header + data. */
|
|
|
|
if (init_block != NULL) {
|
|
ut_ad(type == MEM_HEAP_DYNAMIC);
|
|
ut_ad(n > MEM_BLOCK_START_SIZE + MEM_BLOCK_HEADER_SIZE);
|
|
len = n;
|
|
block = init_block;
|
|
|
|
} else if (type == MEM_HEAP_DYNAMIC) {
|
|
|
|
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
|
|
block = mem_area_alloc(len, mem_comm_pool);
|
|
} else {
|
|
ut_ad(n <= MEM_MAX_ALLOC_IN_BUF);
|
|
|
|
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
|
|
|
|
if (len < UNIV_PAGE_SIZE / 2) {
|
|
|
|
block = mem_area_alloc(len, mem_comm_pool);
|
|
} else {
|
|
len = UNIV_PAGE_SIZE;
|
|
|
|
if ((type & MEM_HEAP_BTR_SEARCH) && heap) {
|
|
/* We cannot allocate the block from the
|
|
buffer pool, but must get the free block from
|
|
the heap header free block field */
|
|
|
|
block = (mem_block_t*)heap->free_block;
|
|
heap->free_block = NULL;
|
|
} else {
|
|
block = (mem_block_t*)buf_frame_alloc();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (block == NULL) {
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
block->magic_n = MEM_BLOCK_MAGIC_N;
|
|
ut_memcpy(&(block->file_name), file_name + ut_strlen(file_name) - 7,
|
|
7);
|
|
block->file_name[7]='\0';
|
|
block->line = line;
|
|
|
|
#ifdef MEM_PERIODIC_CHECK
|
|
mem_pool_mutex_enter();
|
|
|
|
if (!mem_block_list_inited) {
|
|
mem_block_list_inited = TRUE;
|
|
UT_LIST_INIT(mem_block_list);
|
|
}
|
|
|
|
UT_LIST_ADD_LAST(mem_block_list, mem_block_list, block);
|
|
|
|
mem_pool_mutex_exit();
|
|
#endif
|
|
mem_block_set_len(block, len);
|
|
mem_block_set_type(block, type);
|
|
mem_block_set_free(block, MEM_BLOCK_HEADER_SIZE);
|
|
mem_block_set_start(block, MEM_BLOCK_HEADER_SIZE);
|
|
|
|
block->free_block = NULL;
|
|
block->init_block = (init_block != NULL);
|
|
|
|
ut_ad((ulint)MEM_BLOCK_HEADER_SIZE < len);
|
|
|
|
return(block);
|
|
}
|
|
|
|
/*******************************************************************
|
|
Adds a new block to a memory heap. */
|
|
|
|
mem_block_t*
|
|
mem_heap_add_block(
|
|
/*===============*/
|
|
/* out: created block, NULL if did not
|
|
succeed */
|
|
mem_heap_t* heap, /* in: memory heap */
|
|
ulint n) /* in: number of bytes user needs */
|
|
{
|
|
mem_block_t* block;
|
|
mem_block_t* new_block;
|
|
ulint new_size;
|
|
|
|
ut_ad(mem_heap_check(heap));
|
|
|
|
block = UT_LIST_GET_LAST(heap->base);
|
|
|
|
/* We have to allocate a new block. The size is always at least
|
|
doubled until the standard size is reached. After that the size
|
|
stays the same, except in cases where the caller needs more space. */
|
|
|
|
new_size = 2 * mem_block_get_len(block);
|
|
|
|
if (heap->type != MEM_HEAP_DYNAMIC) {
|
|
/* From the buffer pool we allocate buffer frames */
|
|
ut_a(n <= MEM_MAX_ALLOC_IN_BUF);
|
|
|
|
if (new_size > MEM_MAX_ALLOC_IN_BUF) {
|
|
new_size = MEM_MAX_ALLOC_IN_BUF;
|
|
}
|
|
} else if (new_size > MEM_BLOCK_STANDARD_SIZE) {
|
|
|
|
new_size = MEM_BLOCK_STANDARD_SIZE;
|
|
}
|
|
|
|
if (new_size < n) {
|
|
new_size = n;
|
|
}
|
|
|
|
new_block = mem_heap_create_block(heap, new_size, NULL, heap->type,
|
|
heap->file_name, heap->line);
|
|
if (new_block == NULL) {
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
/* Add the new block as the last block */
|
|
|
|
UT_LIST_INSERT_AFTER(list, heap->base, block, new_block);
|
|
|
|
return(new_block);
|
|
}
|
|
|
|
/**********************************************************************
|
|
Frees a block from a memory heap. */
|
|
|
|
void
|
|
mem_heap_block_free(
|
|
/*================*/
|
|
mem_heap_t* heap, /* in: heap */
|
|
mem_block_t* block) /* in: block to free */
|
|
{
|
|
ulint type;
|
|
ulint len;
|
|
ibool init_block;
|
|
|
|
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
|
|
mem_analyze_corruption((byte*)block);
|
|
}
|
|
|
|
UT_LIST_REMOVE(list, heap->base, block);
|
|
|
|
#ifdef MEM_PERIODIC_CHECK
|
|
mem_pool_mutex_enter();
|
|
|
|
UT_LIST_REMOVE(mem_block_list, mem_block_list, block);
|
|
|
|
mem_pool_mutex_exit();
|
|
#endif
|
|
type = heap->type;
|
|
len = block->len;
|
|
init_block = block->init_block;
|
|
block->magic_n = MEM_FREED_BLOCK_MAGIC_N;
|
|
|
|
#ifdef UNIV_MEM_DEBUG
|
|
/* In the debug version we set the memory to a random combination
|
|
of hex 0xDE and 0xAD. */
|
|
|
|
mem_erase_buf((byte*)block, len);
|
|
|
|
#endif
|
|
|
|
if (init_block) {
|
|
/* Do not have to free: do nothing */
|
|
|
|
} else if (type == MEM_HEAP_DYNAMIC) {
|
|
|
|
mem_area_free(block, mem_comm_pool);
|
|
} else {
|
|
ut_ad(type & MEM_HEAP_BUFFER);
|
|
|
|
if (len >= UNIV_PAGE_SIZE / 2) {
|
|
buf_frame_free((byte*)block);
|
|
} else {
|
|
mem_area_free(block, mem_comm_pool);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**********************************************************************
|
|
Frees the free_block field from a memory heap. */
|
|
|
|
void
|
|
mem_heap_free_block_free(
|
|
/*=====================*/
|
|
mem_heap_t* heap) /* in: heap */
|
|
{
|
|
if (heap->free_block) {
|
|
|
|
buf_frame_free(heap->free_block);
|
|
|
|
heap->free_block = NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef MEM_PERIODIC_CHECK
|
|
/**********************************************************************
|
|
Goes through the list of all allocated mem blocks, checks their magic
|
|
numbers, and reports possible corruption. */
|
|
|
|
void
|
|
mem_validate_all_blocks(void)
|
|
/*=========================*/
|
|
{
|
|
mem_block_t* block;
|
|
|
|
mem_pool_mutex_enter();
|
|
|
|
block = UT_LIST_GET_FIRST(mem_block_list);
|
|
|
|
while (block) {
|
|
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
|
|
mem_analyze_corruption((byte*)block);
|
|
}
|
|
|
|
block = UT_LIST_GET_NEXT(mem_block_list, block);
|
|
}
|
|
|
|
mem_pool_mutex_exit();
|
|
}
|
|
#endif
|