diff options
author | Guilhem Bichot <guilhem@mysql.com> | 2009-08-04 13:25:19 +0200 |
---|---|---|
committer | Guilhem Bichot <guilhem@mysql.com> | 2009-08-04 13:25:19 +0200 |
commit | b57e4dbd88671df86e2cf39aff5178976d710b64 (patch) | |
tree | 32be2bfec3ca062c65566c60ecf59b673d1f97e9 /storage/innobase/mem | |
parent | 1a0c2153a036296785dcdfa7b5f4974515616e11 (diff) | |
parent | 94efc1c6b084ed531b513e70fb66e7b7a1186b56 (diff) | |
download | mariadb-git-b57e4dbd88671df86e2cf39aff5178976d710b64.tar.gz |
Creation of mysql-trunk = {summit + "Innodb plugin replacing the builtin"}:
bzr branch mysql-5.1-performance-version mysql-trunk # Summit
cd mysql-trunk
bzr merge mysql-5.1-innodb_plugin # which is 5.1 + Innodb plugin
bzr rm innobase # remove the builtin
Next step: build, test fixes.
Diffstat (limited to 'storage/innobase/mem')
-rw-r--r-- | storage/innobase/mem/mem0dbg.c | 984 | ||||
-rw-r--r-- | storage/innobase/mem/mem0mem.c | 577 | ||||
-rw-r--r-- | storage/innobase/mem/mem0pool.c | 682 |
3 files changed, 0 insertions, 2243 deletions
diff --git a/storage/innobase/mem/mem0dbg.c b/storage/innobase/mem/mem0dbg.c deleted file mode 100644 index 72452907c3f..00000000000 --- a/storage/innobase/mem/mem0dbg.c +++ /dev/null @@ -1,984 +0,0 @@ -/************************************************************************ -The memory management: the debug code. This is not a compilation module, -but is included in mem0mem.* ! - -(c) 1994, 1995 Innobase Oy - -Created 6/9/1994 Heikki Tuuri -*************************************************************************/ - -#ifdef UNIV_MEM_DEBUG -mutex_t mem_hash_mutex; /* The mutex which protects in the - debug version the hash table containing - the list of live memory heaps, and - also the global variables below. */ - -/* The following variables contain information about the -extent of memory allocations. Only used in the debug version. -Protected by mem_hash_mutex above. */ - -static ulint mem_n_created_heaps = 0; -static ulint mem_n_allocations = 0; -static ulint mem_total_allocated_memory = 0; -ulint mem_current_allocated_memory = 0; -static ulint mem_max_allocated_memory = 0; -static ulint mem_last_print_info = 0; - -/* Size of the hash table for memory management tracking */ -#define MEM_HASH_SIZE 997 - -/* The node of the list containing currently allocated memory heaps */ - -typedef struct mem_hash_node_struct mem_hash_node_t; -struct mem_hash_node_struct { - UT_LIST_NODE_T(mem_hash_node_t) - list; /* hash list node */ - mem_heap_t* heap; /* memory heap */ - const char* file_name;/* file where heap was created*/ - ulint line; /* file line of creation */ - ulint nth_heap;/* this is the nth heap created */ - UT_LIST_NODE_T(mem_hash_node_t) - all_list;/* list of all created heaps */ -}; - -typedef UT_LIST_BASE_NODE_T(mem_hash_node_t) mem_hash_cell_t; - -/* The hash table of allocated heaps */ -static mem_hash_cell_t mem_hash_table[MEM_HASH_SIZE]; - -/* The base node of the list of all allocated heaps */ -static mem_hash_cell_t mem_all_list_base; - -static ibool mem_hash_initialized = FALSE; - - -UNIV_INLINE -mem_hash_cell_t* -mem_hash_get_nth_cell(ulint i); - -/* Accessor function for the hash table. Returns a pointer to the -table cell. */ -UNIV_INLINE -mem_hash_cell_t* -mem_hash_get_nth_cell(ulint i) -{ - ut_a(i < MEM_HASH_SIZE); - - return(&(mem_hash_table[i])); -} - -/* Accessor functions for a memory field in the debug version */ - -void -mem_field_header_set_len(byte* field, ulint len) -{ - mach_write_to_4(field - 2 * sizeof(ulint), len); -} - -ulint -mem_field_header_get_len(byte* field) -{ - return(mach_read_from_4(field - 2 * sizeof(ulint))); -} - -void -mem_field_header_set_check(byte* field, ulint check) -{ - mach_write_to_4(field - sizeof(ulint), check); -} - -ulint -mem_field_header_get_check(byte* field) -{ - return(mach_read_from_4(field - sizeof(ulint))); -} - -void -mem_field_trailer_set_check(byte* field, ulint check) -{ - mach_write_to_4(field + mem_field_header_get_len(field), check); -} - -ulint -mem_field_trailer_get_check(byte* field) -{ - return(mach_read_from_4(field - + mem_field_header_get_len(field))); -} -#endif /* UNIV_MEM_DEBUG */ - -/********************************************************************** -Initializes the memory system. */ - -void -mem_init( -/*=====*/ - ulint size) /* in: common pool size in bytes */ -{ -#ifdef UNIV_MEM_DEBUG - - ulint i; - - /* Initialize the hash table */ - ut_a(FALSE == mem_hash_initialized); - - mutex_create(&mem_hash_mutex, SYNC_MEM_HASH); - - for (i = 0; i < MEM_HASH_SIZE; i++) { - UT_LIST_INIT(*mem_hash_get_nth_cell(i)); - } - - UT_LIST_INIT(mem_all_list_base); - - mem_hash_initialized = TRUE; -#endif - - mem_comm_pool = mem_pool_create(size); -} - -#ifdef UNIV_MEM_DEBUG -/********************************************************************** -Initializes an allocated memory field in the debug version. */ - -void -mem_field_init( -/*===========*/ - byte* buf, /* in: memory field */ - ulint n) /* in: how many bytes the user requested */ -{ - ulint rnd; - byte* usr_buf; - - usr_buf = buf + MEM_FIELD_HEADER_SIZE; - - /* In the debug version write the length field and the - check fields to the start and the end of the allocated storage. - The field header consists of a length field and - a random number field, in this order. The field trailer contains - the same random number as a check field. */ - - mem_field_header_set_len(usr_buf, n); - - rnd = ut_rnd_gen_ulint(); - - mem_field_header_set_check(usr_buf, rnd); - mem_field_trailer_set_check(usr_buf, rnd); - - /* Update the memory allocation information */ - - mutex_enter(&mem_hash_mutex); - - mem_total_allocated_memory += n; - mem_current_allocated_memory += n; - mem_n_allocations++; - - if (mem_current_allocated_memory > mem_max_allocated_memory) { - mem_max_allocated_memory = mem_current_allocated_memory; - } - - mutex_exit(&mem_hash_mutex); - - /* In the debug version set the buffer to a random - combination of 0xBA and 0xBE */ - - mem_init_buf(usr_buf, n); -} - -/********************************************************************** -Erases an allocated memory field in the debug version. */ - -void -mem_field_erase( -/*============*/ - byte* buf, /* in: memory field */ - ulint n __attribute__((unused))) - /* in: how many bytes the user requested */ -{ - byte* usr_buf; - - usr_buf = buf + MEM_FIELD_HEADER_SIZE; - - mutex_enter(&mem_hash_mutex); - mem_current_allocated_memory -= n; - mutex_exit(&mem_hash_mutex); - - /* Check that the field lengths agree */ - ut_ad(n == (ulint)mem_field_header_get_len(usr_buf)); - - /* In the debug version, set the freed space to a random - combination of 0xDE and 0xAD */ - - mem_erase_buf(buf, MEM_SPACE_NEEDED(n)); -} - -/******************************************************************* -Initializes a buffer to a random combination of hex BA and BE. -Used to initialize allocated memory. */ - -void -mem_init_buf( -/*=========*/ - byte* buf, /* in: pointer to buffer */ - ulint n) /* in: length of buffer */ -{ - byte* ptr; - - UNIV_MEM_ASSERT_W(buf, n); - - for (ptr = buf; ptr < buf + n; ptr++) { - - if (ut_rnd_gen_ibool()) { - *ptr = 0xBA; - } else { - *ptr = 0xBE; - } - } - - UNIV_MEM_INVALID(buf, n); -} - -/******************************************************************* -Initializes a buffer to a random combination of hex DE and AD. -Used to erase freed memory.*/ - -void -mem_erase_buf( -/*==========*/ - byte* buf, /* in: pointer to buffer */ - ulint n) /* in: length of buffer */ -{ - byte* ptr; - - UNIV_MEM_ASSERT_W(buf, n); - - for (ptr = buf; ptr < buf + n; ptr++) { - if (ut_rnd_gen_ibool()) { - *ptr = 0xDE; - } else { - *ptr = 0xAD; - } - } - - UNIV_MEM_FREE(buf, n); -} - -/******************************************************************* -Inserts a created memory heap to the hash table of current allocated -memory heaps. */ - -void -mem_hash_insert( -/*============*/ - mem_heap_t* heap, /* in: the created heap */ - const char* file_name, /* in: file name of creation */ - ulint line) /* in: line where created */ -{ - mem_hash_node_t* new_node; - ulint cell_no ; - - ut_ad(mem_heap_check(heap)); - - mutex_enter(&mem_hash_mutex); - - cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE); - - /* Allocate a new node to the list */ - new_node = ut_malloc(sizeof(mem_hash_node_t)); - - new_node->heap = heap; - new_node->file_name = file_name; - new_node->line = line; - new_node->nth_heap = mem_n_created_heaps; - - /* Insert into lists */ - UT_LIST_ADD_FIRST(list, *mem_hash_get_nth_cell(cell_no), new_node); - - UT_LIST_ADD_LAST(all_list, mem_all_list_base, new_node); - - mem_n_created_heaps++; - - mutex_exit(&mem_hash_mutex); -} - -/******************************************************************* -Removes a memory heap (which is going to be freed by the caller) -from the list of live memory heaps. Returns the size of the heap -in terms of how much memory in bytes was allocated for the user of -the heap (not the total space occupied by the heap). -Also validates the heap. -NOTE: This function does not free the storage occupied by the -heap itself, only the node in the list of heaps. */ - -void -mem_hash_remove( -/*============*/ - mem_heap_t* heap, /* in: the heap to be freed */ - const char* file_name, /* in: file name of freeing */ - ulint line) /* in: line where freed */ -{ - mem_hash_node_t* node; - ulint cell_no; - ibool error; - ulint size; - - ut_ad(mem_heap_check(heap)); - - mutex_enter(&mem_hash_mutex); - - cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE); - - /* Look for the heap in the hash table list */ - node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(cell_no)); - - while (node != NULL) { - if (node->heap == heap) { - - break; - } - - node = UT_LIST_GET_NEXT(list, node); - } - - if (node == NULL) { - fprintf(stderr, - "Memory heap or buffer freed in %s line %lu" - " did not exist.\n", - file_name, (ulong) line); - ut_error; - } - - /* Remove from lists */ - UT_LIST_REMOVE(list, *mem_hash_get_nth_cell(cell_no), node); - - UT_LIST_REMOVE(all_list, mem_all_list_base, node); - - /* Validate the heap which will be freed */ - mem_heap_validate_or_print(node->heap, NULL, FALSE, &error, &size, - NULL, NULL); - if (error) { - fprintf(stderr, - "Inconsistency in memory heap or" - " buffer n:o %lu created\n" - "in %s line %lu and tried to free in %s line %lu.\n" - "Hex dump of 400 bytes around memory heap" - " first block start:\n", - node->nth_heap, node->file_name, (ulong) node->line, - file_name, (ulong) line); - ut_print_buf(stderr, (byte*)node->heap - 200, 400); - fputs("\nDump of the mem heap:\n", stderr); - mem_heap_validate_or_print(node->heap, NULL, TRUE, &error, - &size, NULL, NULL); - ut_error; - } - - /* Free the memory occupied by the node struct */ - ut_free(node); - - mem_current_allocated_memory -= size; - - mutex_exit(&mem_hash_mutex); -} -#endif /* UNIV_MEM_DEBUG */ - -#if defined UNIV_MEM_DEBUG || defined UNIV_DEBUG -/******************************************************************* -Checks a memory heap for consistency and prints the contents if requested. -Outputs the sum of sizes of buffers given to the user (only in -the debug version), the physical size of the heap and the number of -blocks in the heap. In case of error returns 0 as sizes and number -of blocks. */ - -void -mem_heap_validate_or_print( -/*=======================*/ - mem_heap_t* heap, /* in: memory heap */ - byte* top __attribute__((unused)), - /* in: calculate and validate only until - this top pointer in the heap is reached, - if this pointer is NULL, ignored */ - ibool print, /* in: if TRUE, prints the contents - of the heap; works only in - the debug version */ - ibool* error, /* out: TRUE if error */ - ulint* us_size,/* out: allocated memory - (for the user) in the heap, - if a NULL pointer is passed as this - argument, it is ignored; in the - non-debug version this is always -1 */ - ulint* ph_size,/* out: physical size of the heap, - if a NULL pointer is passed as this - argument, it is ignored */ - ulint* n_blocks) /* out: number of blocks in the heap, - if a NULL pointer is passed as this - argument, it is ignored */ -{ - mem_block_t* block; - ulint total_len = 0; - ulint block_count = 0; - ulint phys_len = 0; -#ifdef UNIV_MEM_DEBUG - ulint len; - byte* field; - byte* user_field; - ulint check_field; -#endif - - /* Pessimistically, we set the parameters to error values */ - if (us_size != NULL) { - *us_size = 0; - } - if (ph_size != NULL) { - *ph_size = 0; - } - if (n_blocks != NULL) { - *n_blocks = 0; - } - *error = TRUE; - - block = heap; - - if (block->magic_n != MEM_BLOCK_MAGIC_N) { - return; - } - - if (print) { - fputs("Memory heap:", stderr); - } - - while (block != NULL) { - phys_len += mem_block_get_len(block); - - if ((block->type == MEM_HEAP_BUFFER) - && (mem_block_get_len(block) > UNIV_PAGE_SIZE)) { - - fprintf(stderr, - "InnoDB: Error: mem block %p" - " length %lu > UNIV_PAGE_SIZE\n", - (void*) block, - (ulong) mem_block_get_len(block)); - /* error */ - - return; - } - -#ifdef UNIV_MEM_DEBUG - /* We can trace the fields of the block only in the debug - version */ - if (print) { - fprintf(stderr, " Block %ld:", block_count); - } - - field = (byte*)block + mem_block_get_start(block); - - if (top && (field == top)) { - - goto completed; - } - - while (field < (byte*)block + mem_block_get_free(block)) { - - /* Calculate the pointer to the storage - which was given to the user */ - - user_field = field + MEM_FIELD_HEADER_SIZE; - - len = mem_field_header_get_len(user_field); - - if (print) { - ut_print_buf(stderr, user_field, len); - } - - total_len += len; - check_field = mem_field_header_get_check(user_field); - - if (check_field - != mem_field_trailer_get_check(user_field)) { - /* error */ - - fprintf(stderr, - "InnoDB: Error: block %lx mem" - " field %lx len %lu\n" - "InnoDB: header check field is" - " %lx but trailer %lx\n", - (ulint)block, - (ulint)field, len, check_field, - mem_field_trailer_get_check( - user_field)); - - return; - } - - /* Move to next field */ - field = field + MEM_SPACE_NEEDED(len); - - if (top && (field == top)) { - - goto completed; - } - - } - - /* At the end check that we have arrived to the first free - position */ - - if (field != (byte*)block + mem_block_get_free(block)) { - /* error */ - - fprintf(stderr, - "InnoDB: Error: block %lx end of" - " mem fields %lx\n" - "InnoDB: but block free at %lx\n", - (ulint)block, (ulint)field, - (ulint)((byte*)block - + mem_block_get_free(block))); - - return; - } - -#endif - - block = UT_LIST_GET_NEXT(list, block); - block_count++; - } -#ifdef UNIV_MEM_DEBUG -completed: -#endif - if (us_size != NULL) { - *us_size = total_len; - } - if (ph_size != NULL) { - *ph_size = phys_len; - } - if (n_blocks != NULL) { - *n_blocks = block_count; - } - *error = FALSE; -} - -/****************************************************************** -Prints the contents of a memory heap. */ -static -void -mem_heap_print( -/*===========*/ - mem_heap_t* heap) /* in: memory heap */ -{ - ibool error; - ulint us_size; - ulint phys_size; - ulint n_blocks; - - ut_ad(mem_heap_check(heap)); - - mem_heap_validate_or_print(heap, NULL, TRUE, &error, - &us_size, &phys_size, &n_blocks); - fprintf(stderr, - "\nheap type: %lu; size: user size %lu;" - " physical size %lu; blocks %lu.\n", - (ulong) heap->type, (ulong) us_size, - (ulong) phys_size, (ulong) n_blocks); - ut_a(!error); -} - -/****************************************************************** -Validates the contents of a memory heap. */ - -ibool -mem_heap_validate( -/*==============*/ - /* out: TRUE if ok */ - mem_heap_t* heap) /* in: memory heap */ -{ - ibool error; - ulint us_size; - ulint phys_size; - ulint n_blocks; - - ut_ad(mem_heap_check(heap)); - - mem_heap_validate_or_print(heap, NULL, FALSE, &error, &us_size, - &phys_size, &n_blocks); - if (error) { - mem_heap_print(heap); - } - - ut_a(!error); - - return(TRUE); -} -#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */ - -#ifdef UNIV_DEBUG -/****************************************************************** -Checks that an object is a memory heap (or a block of it). */ - -ibool -mem_heap_check( -/*===========*/ - /* out: TRUE if ok */ - mem_heap_t* heap) /* in: memory heap */ -{ - ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N); - - return(TRUE); -} -#endif /* UNIV_DEBUG */ - -#ifdef UNIV_MEM_DEBUG -/********************************************************************* -TRUE if no memory is currently allocated. */ - -ibool -mem_all_freed(void) -/*===============*/ - /* out: TRUE if no heaps exist */ -{ - mem_hash_node_t* node; - ulint heap_count = 0; - ulint i; - - mem_validate(); - - mutex_enter(&mem_hash_mutex); - - for (i = 0; i < MEM_HASH_SIZE; i++) { - - node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i)); - while (node != NULL) { - heap_count++; - node = UT_LIST_GET_NEXT(list, node); - } - } - - mutex_exit(&mem_hash_mutex); - - if (heap_count == 0) { - - ut_a(mem_pool_get_reserved(mem_comm_pool) == 0); - - return(TRUE); - } else { - return(FALSE); - } -} - -/********************************************************************* -Validates the dynamic memory allocation system. */ - -ibool -mem_validate_no_assert(void) -/*========================*/ - /* out: TRUE if error */ -{ - mem_hash_node_t* node; - ulint n_heaps = 0; - ulint allocated_mem; - ulint ph_size; - ulint total_allocated_mem = 0; - ibool error = FALSE; - ulint n_blocks; - ulint i; - - mem_pool_validate(mem_comm_pool); - - mutex_enter(&mem_hash_mutex); - - for (i = 0; i < MEM_HASH_SIZE; i++) { - - node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i)); - - while (node != NULL) { - n_heaps++; - - mem_heap_validate_or_print(node->heap, NULL, - FALSE, &error, - &allocated_mem, - &ph_size, &n_blocks); - - if (error) { - fprintf(stderr, - "\nERROR!!!!!!!!!!!!!!!!!!!" - "!!!!!!!!!!!!!!!!!!!!!!!\n\n" - "Inconsistency in memory heap" - " or buffer created\n" - "in %s line %lu.\n", - node->file_name, node->line); - - mutex_exit(&mem_hash_mutex); - - return(TRUE); - } - - total_allocated_mem += allocated_mem; - node = UT_LIST_GET_NEXT(list, node); - } - } - - if ((n_heaps == 0) && (mem_current_allocated_memory != 0)) { - error = TRUE; - } - - if (mem_total_allocated_memory < mem_current_allocated_memory) { - error = TRUE; - } - - if (mem_max_allocated_memory > mem_total_allocated_memory) { - error = TRUE; - } - - if (mem_n_created_heaps < n_heaps) { - error = TRUE; - } - - mutex_exit(&mem_hash_mutex); - - return(error); -} - -/**************************************************************** -Validates the dynamic memory */ - -ibool -mem_validate(void) -/*==============*/ - /* out: TRUE if ok */ -{ - ut_a(!mem_validate_no_assert()); - - return(TRUE); -} -#endif /* UNIV_MEM_DEBUG */ - -/**************************************************************** -Tries to find neigboring memory allocation blocks and dumps to stderr -the neighborhood of a given pointer. */ - -void -mem_analyze_corruption( -/*===================*/ - void* ptr) /* in: pointer to place of possible corruption */ -{ - byte* p; - ulint i; - ulint dist; - - fputs("InnoDB: Apparent memory corruption: mem dump ", stderr); - ut_print_buf(stderr, (byte*)ptr - 250, 500); - - fputs("\nInnoDB: Scanning backward trying to find" - " previous allocated mem blocks\n", stderr); - - p = (byte*)ptr; - dist = 0; - - for (i = 0; i < 10; i++) { - for (;;) { - if (((ulint)p) % 4 == 0) { - - if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) { - fprintf(stderr, - "Mem block at - %lu," - " file %s, line %lu\n", - (ulong) dist, - (p + sizeof(ulint)), - (ulong) - (*(ulint*)(p + 8 - + sizeof(ulint)))); - - break; - } - - if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) { - fprintf(stderr, - "Freed mem block at - %lu," - " file %s, line %lu\n", - (ulong) dist, - (p + sizeof(ulint)), - (ulong) - (*(ulint*)(p + 8 - + sizeof(ulint)))); - - break; - } - } - - p--; - dist++; - } - - p--; - dist++; - } - - fprintf(stderr, - "InnoDB: Scanning forward trying to find next" - " allocated mem blocks\n"); - - p = (byte*)ptr; - dist = 0; - - for (i = 0; i < 10; i++) { - for (;;) { - if (((ulint)p) % 4 == 0) { - - if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) { - fprintf(stderr, - "Mem block at + %lu, file %s," - " line %lu\n", - (ulong) dist, - (p + sizeof(ulint)), - (ulong) - (*(ulint*)(p + 8 - + sizeof(ulint)))); - - break; - } - - if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) { - fprintf(stderr, - "Freed mem block at + %lu," - " file %s, line %lu\n", - (ulong) dist, - (p + sizeof(ulint)), - (ulong) - (*(ulint*)(p + 8 - + sizeof(ulint)))); - - break; - } - } - - p++; - dist++; - } - - p++; - dist++; - } -} - -/********************************************************************* -Prints information of dynamic memory usage and currently allocated -memory heaps or buffers. Can only be used in the debug version. */ -static -void -mem_print_info_low( -/*===============*/ - ibool print_all) /* in: if TRUE, all heaps are printed, - else only the heaps allocated after the - previous call of this function */ -{ -#ifdef UNIV_MEM_DEBUG - mem_hash_node_t* node; - ulint n_heaps = 0; - ulint allocated_mem; - ulint ph_size; - ulint total_allocated_mem = 0; - ibool error; - ulint n_blocks; -#endif - FILE* outfile; - - /* outfile = fopen("ibdebug", "a"); */ - - outfile = stdout; - - fprintf(outfile, "\n"); - fprintf(outfile, - "________________________________________________________\n"); - fprintf(outfile, "MEMORY ALLOCATION INFORMATION\n\n"); - -#ifndef UNIV_MEM_DEBUG - - UT_NOT_USED(print_all); - - mem_pool_print_info(outfile, mem_comm_pool); - - fprintf(outfile, - "Sorry, non-debug version cannot give more memory info\n"); - - /* fclose(outfile); */ - - return; -#else - mutex_enter(&mem_hash_mutex); - - fprintf(outfile, "LIST OF CREATED HEAPS AND ALLOCATED BUFFERS: \n\n"); - - if (!print_all) { - fprintf(outfile, "AFTER THE LAST PRINT INFO\n"); - } - - node = UT_LIST_GET_FIRST(mem_all_list_base); - - while (node != NULL) { - n_heaps++; - - if (!print_all && node->nth_heap < mem_last_print_info) { - - goto next_heap; - } - - mem_heap_validate_or_print(node->heap, NULL, - FALSE, &error, &allocated_mem, - &ph_size, &n_blocks); - total_allocated_mem += allocated_mem; - - fprintf(outfile, - "%lu: file %s line %lu of size %lu phys.size %lu" - " with %lu blocks, type %lu\n", - node->nth_heap, node->file_name, node->line, - allocated_mem, ph_size, n_blocks, - (node->heap)->type); -next_heap: - node = UT_LIST_GET_NEXT(all_list, node); - } - - fprintf(outfile, "\n"); - - fprintf(outfile, "Current allocated memory : %lu\n", - mem_current_allocated_memory); - fprintf(outfile, "Current allocated heaps and buffers : %lu\n", - n_heaps); - fprintf(outfile, "Cumulative allocated memory : %lu\n", - mem_total_allocated_memory); - fprintf(outfile, "Maximum allocated memory : %lu\n", - mem_max_allocated_memory); - fprintf(outfile, "Cumulative created heaps and buffers : %lu\n", - mem_n_created_heaps); - fprintf(outfile, "Cumulative number of allocations : %lu\n", - mem_n_allocations); - - mem_last_print_info = mem_n_created_heaps; - - mutex_exit(&mem_hash_mutex); - - mem_pool_print_info(outfile, mem_comm_pool); - - /* mem_validate(); */ - - /* fclose(outfile); */ -#endif -} - -/********************************************************************* -Prints information of dynamic memory usage and currently allocated memory -heaps or buffers. Can only be used in the debug version. */ - -void -mem_print_info(void) -/*================*/ -{ - mem_print_info_low(TRUE); -} - -/********************************************************************* -Prints information of dynamic memory usage and currently allocated memory -heaps or buffers since the last ..._print_info or..._print_new_info. */ - -void -mem_print_new_info(void) -/*====================*/ -{ - mem_print_info_low(FALSE); -} diff --git a/storage/innobase/mem/mem0mem.c b/storage/innobase/mem/mem0mem.c deleted file mode 100644 index f4fd178a39c..00000000000 --- a/storage/innobase/mem/mem0mem.c +++ /dev/null @@ -1,577 +0,0 @@ -/************************************************************************ -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" -#include <stdarg.h> - -/* - 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 */ - ulint n, /* in: desired number of bytes */ - const char* file_name, /* in: file name where created */ - ulint line) /* in: line where created */ -{ - return(mem_alloc_func(n, file_name, line)); -} - -/************************************************************************** -Duplicates a NUL-terminated string, allocated from a memory heap. */ - -char* -mem_heap_strdup( -/*============*/ - /* out, own: a copy of the string */ - mem_heap_t* heap, /* in: memory heap where string is allocated */ - const char* str) /* in: string to be copied */ -{ - return(mem_heap_dup(heap, str, strlen(str) + 1)); -} - -/************************************************************************** -Duplicate a block of data, allocated from a memory heap. */ - -void* -mem_heap_dup( -/*=========*/ - /* out, own: a copy of the data */ - mem_heap_t* heap, /* in: memory heap where copy is allocated */ - const void* data, /* in: data to be copied */ - ulint len) /* in: length of data, in bytes */ -{ - return(memcpy(mem_heap_alloc(heap, len), data, len)); -} - -/************************************************************************** -Concatenate two memory blocks and return the result, using a memory heap. */ - -void* -mem_heap_cat( -/*=========*/ - /* out, own: the result */ - mem_heap_t* heap, /* in: memory heap where result is allocated */ - const void* b1, /* in: block 1 */ - ulint len1, /* in: length of b1, in bytes */ - const void* b2, /* in: block 2 */ - ulint len2) /* in: length of b2, in bytes */ -{ - void* res = mem_heap_alloc(heap, len1 + len2); - - memcpy(res, b1, len1); - memcpy((char*)res + len1, b2, len2); - - return(res); -} - -/************************************************************************** -Concatenate two strings and return the result, using a memory heap. */ - -char* -mem_heap_strcat( -/*============*/ - /* out, own: the result */ - mem_heap_t* heap, /* in: memory heap where string is allocated */ - const char* s1, /* in: string 1 */ - const char* s2) /* in: string 2 */ -{ - char* s; - ulint s1_len = strlen(s1); - ulint s2_len = strlen(s2); - - s = mem_heap_alloc(heap, s1_len + s2_len + 1); - - memcpy(s, s1, s1_len); - memcpy(s + s1_len, s2, s2_len); - - s[s1_len + s2_len] = '\0'; - - return(s); -} - - -/******************************************************************** -Helper function for mem_heap_printf. */ -static -ulint -mem_heap_printf_low( -/*================*/ - /* out: length of formatted string, - including terminating NUL */ - char* buf, /* in/out: buffer to store formatted string - in, or NULL to just calculate length */ - const char* format, /* in: format string */ - va_list ap) /* in: arguments */ -{ - ulint len = 0; - - while (*format) { - - /* Does this format specifier have the 'l' length modifier. */ - ibool is_long = FALSE; - - /* Length of one parameter. */ - size_t plen; - - if (*format++ != '%') { - /* Non-format character. */ - - len++; - - if (buf) { - *buf++ = *(format - 1); - } - - continue; - } - - if (*format == 'l') { - is_long = TRUE; - format++; - } - - switch (*format++) { - case 's': - /* string */ - { - char* s = va_arg(ap, char*); - - /* "%ls" is a non-sensical format specifier. */ - ut_a(!is_long); - - plen = strlen(s); - len += plen; - - if (buf) { - memcpy(buf, s, plen); - buf += plen; - } - } - - break; - - case 'u': - /* unsigned int */ - { - char tmp[32]; - unsigned long val; - - /* We only support 'long' values for now. */ - ut_a(is_long); - - val = va_arg(ap, unsigned long); - - plen = sprintf(tmp, "%lu", val); - len += plen; - - if (buf) { - memcpy(buf, tmp, plen); - buf += plen; - } - } - - break; - - case '%': - - /* "%l%" is a non-sensical format specifier. */ - ut_a(!is_long); - - len++; - - if (buf) { - *buf++ = '%'; - } - - break; - - default: - ut_error; - } - } - - /* For the NUL character. */ - len++; - - if (buf) { - *buf = '\0'; - } - - return(len); -} - -/******************************************************************** -A simple (s)printf replacement that dynamically allocates the space for the -formatted string from the given heap. This supports a very limited set of -the printf syntax: types 's' and 'u' and length modifier 'l' (which is -required for the 'u' type). */ - -char* -mem_heap_printf( -/*============*/ - /* out: heap-allocated formatted string */ - mem_heap_t* heap, /* in: memory heap */ - const char* format, /* in: format string */ - ...) -{ - va_list ap; - char* str; - ulint len; - - /* Calculate length of string */ - len = 0; - va_start(ap, format); - len = mem_heap_printf_low(NULL, format, ap); - va_end(ap); - - /* Now create it for real. */ - str = mem_heap_alloc(heap, len); - va_start(ap, format); - mem_heap_printf_low(str, format, ap); - va_end(ap); - - return(str); -} - -/******************************************************************* -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 (only possible for - MEM_HEAP_BTR_SEARCH type heaps) */ - 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 */ - const 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(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) { - /* Only MEM_HEAP_BTR_SEARCH allocation should ever fail. */ - ut_a(type & MEM_HEAP_BTR_SEARCH); - - return(NULL); - } - - block->magic_n = MEM_BLOCK_MAGIC_N; - ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name)); - 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 (only possible for - MEM_HEAP_BTR_SEARCH type heaps)*/ - 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(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); -#else /* UNIV_MEM_DEBUG */ - UNIV_MEM_ASSERT_AND_FREE(block, len); -#endif /* UNIV_MEM_DEBUG */ - - 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(block); - } - - block = UT_LIST_GET_NEXT(mem_block_list, block); - } - - mem_pool_mutex_exit(); -} -#endif diff --git a/storage/innobase/mem/mem0pool.c b/storage/innobase/mem/mem0pool.c deleted file mode 100644 index 315f719ca09..00000000000 --- a/storage/innobase/mem/mem0pool.c +++ /dev/null @@ -1,682 +0,0 @@ -/************************************************************************ -The lowest-level memory management - -(c) 1997 Innobase Oy - -Created 5/12/1997 Heikki Tuuri -*************************************************************************/ - -#include "mem0pool.h" -#ifdef UNIV_NONINL -#include "mem0pool.ic" -#endif - -#include "sync0sync.h" -#include "ut0mem.h" -#include "ut0lst.h" -#include "ut0byte.h" -#include "mem0mem.h" - -/* We would like to use also the buffer frames to allocate memory. This -would be desirable, because then the memory consumption of the database -would be fixed, and we might even lock the buffer pool to the main memory. -The problem here is that the buffer management routines can themselves call -memory allocation, while the buffer pool mutex is reserved. - -The main components of the memory consumption are: - -1. buffer pool, -2. parsed and optimized SQL statements, -3. data dictionary cache, -4. log buffer, -5. locks for each transaction, -6. hash table for the adaptive index, -7. state and buffers for each SQL query currently being executed, -8. session for each user, and -9. stack for each OS thread. - -Items 1 and 2 are managed by an LRU algorithm. Items 5 and 6 can potentially -consume very much memory. Items 7 and 8 should consume quite little memory, -and the OS should take care of item 9, which too should consume little memory. - -A solution to the memory management: - -1. the buffer pool size is set separately; -2. log buffer size is set separately; -3. the common pool size for all the other entries, except 8, is set separately. - -Problems: we may waste memory if the common pool is set too big. Another -problem is the locks, which may take very much space in big transactions. -Then the shared pool size should be set very big. We can allow locks to take -space from the buffer pool, but the SQL optimizer is then unaware of the -usable size of the buffer pool. We could also combine the objects in the -common pool and the buffers in the buffer pool into a single LRU list and -manage it uniformly, but this approach does not take into account the parsing -and other costs unique to SQL statements. - -The locks for a transaction can be seen as a part of the state of the -transaction. Hence, they should be stored in the common pool. We still -have the problem of a very big update transaction, for example, which -will set very many x-locks on rows, and the locks will consume a lot -of memory, say, half of the buffer pool size. - -Another problem is what to do if we are not able to malloc a requested -block of memory from the common pool. Then we can request memory from -the operating system. If it does not help, a system error results. - -Because 5 and 6 may potentially consume very much memory, we let them grow -into the buffer pool. We may let the locks of a transaction take frames -from the buffer pool, when the corresponding memory heap block has grown to -the size of a buffer frame. Similarly for the hash node cells of the locks, -and for the adaptive index. Thus, for each individual transaction, its locks -can occupy at most about the size of the buffer frame of memory in the common -pool, and after that its locks will grow into the buffer pool. */ - -/* Mask used to extract the free bit from area->size */ -#define MEM_AREA_FREE 1 - -/* The smallest memory area total size */ -#define MEM_AREA_MIN_SIZE (2 * MEM_AREA_EXTRA_SIZE) - - -/* Data structure for a memory pool. The space is allocated using the buddy -algorithm, where free list i contains areas of size 2 to power i. */ -struct mem_pool_struct{ - byte* buf; /* memory pool */ - ulint size; /* memory common pool size */ - ulint reserved; /* amount of currently allocated - memory */ - mutex_t mutex; /* mutex protecting this struct */ - UT_LIST_BASE_NODE_T(mem_area_t) - free_list[64]; /* lists of free memory areas: an - area is put to the list whose number - is the 2-logarithm of the area size */ -}; - -/* The common memory pool */ -mem_pool_t* mem_comm_pool = NULL; - -/* We use this counter to check that the mem pool mutex does not leak; -this is to track a strange assertion failure reported at -mysql@lists.mysql.com */ - -ulint mem_n_threads_inside = 0; - -/************************************************************************ -Reserves the mem pool mutex. */ - -void -mem_pool_mutex_enter(void) -/*======================*/ -{ - mutex_enter(&(mem_comm_pool->mutex)); -} - -/************************************************************************ -Releases the mem pool mutex. */ - -void -mem_pool_mutex_exit(void) -/*=====================*/ -{ - mutex_exit(&(mem_comm_pool->mutex)); -} - -/************************************************************************ -Returns memory area size. */ -UNIV_INLINE -ulint -mem_area_get_size( -/*==============*/ - /* out: size */ - mem_area_t* area) /* in: area */ -{ - return(area->size_and_free & ~MEM_AREA_FREE); -} - -/************************************************************************ -Sets memory area size. */ -UNIV_INLINE -void -mem_area_set_size( -/*==============*/ - mem_area_t* area, /* in: area */ - ulint size) /* in: size */ -{ - area->size_and_free = (area->size_and_free & MEM_AREA_FREE) - | size; -} - -/************************************************************************ -Returns memory area free bit. */ -UNIV_INLINE -ibool -mem_area_get_free( -/*==============*/ - /* out: TRUE if free */ - mem_area_t* area) /* in: area */ -{ -#if TRUE != MEM_AREA_FREE -# error "TRUE != MEM_AREA_FREE" -#endif - return(area->size_and_free & MEM_AREA_FREE); -} - -/************************************************************************ -Sets memory area free bit. */ -UNIV_INLINE -void -mem_area_set_free( -/*==============*/ - mem_area_t* area, /* in: area */ - ibool free) /* in: free bit value */ -{ -#if TRUE != MEM_AREA_FREE -# error "TRUE != MEM_AREA_FREE" -#endif - area->size_and_free = (area->size_and_free & ~MEM_AREA_FREE) - | free; -} - -/************************************************************************ -Creates a memory pool. */ - -mem_pool_t* -mem_pool_create( -/*============*/ - /* out: memory pool */ - ulint size) /* in: pool size in bytes */ -{ - mem_pool_t* pool; - mem_area_t* area; - ulint i; - ulint used; - - ut_a(size > 10000); - - pool = ut_malloc(sizeof(mem_pool_t)); - - /* We do not set the memory to zero (FALSE) in the pool, - but only when allocated at a higher level in mem0mem.c. - This is to avoid masking useful Purify warnings. */ - - pool->buf = ut_malloc_low(size, FALSE, TRUE); - pool->size = size; - - mutex_create(&pool->mutex, SYNC_MEM_POOL); - - /* Initialize the free lists */ - - for (i = 0; i < 64; i++) { - - UT_LIST_INIT(pool->free_list[i]); - } - - used = 0; - - while (size - used >= MEM_AREA_MIN_SIZE) { - - i = ut_2_log(size - used); - - if (ut_2_exp(i) > size - used) { - - /* ut_2_log rounds upward */ - - i--; - } - - area = (mem_area_t*)(pool->buf + used); - - mem_area_set_size(area, ut_2_exp(i)); - mem_area_set_free(area, TRUE); - UNIV_MEM_FREE(MEM_AREA_EXTRA_SIZE + (byte*) area, - ut_2_exp(i) - MEM_AREA_EXTRA_SIZE); - - UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area); - - used = used + ut_2_exp(i); - } - - ut_ad(size >= used); - - pool->reserved = 0; - - return(pool); -} - -/************************************************************************ -Fills the specified free list. */ -static -ibool -mem_pool_fill_free_list( -/*====================*/ - /* out: TRUE if we were able to insert a - block to the free list */ - ulint i, /* in: free list index */ - mem_pool_t* pool) /* in: memory pool */ -{ - mem_area_t* area; - mem_area_t* area2; - ibool ret; - - ut_ad(mutex_own(&(pool->mutex))); - - if (i >= 63) { - /* We come here when we have run out of space in the - memory pool: */ - - return(FALSE); - } - - area = UT_LIST_GET_FIRST(pool->free_list[i + 1]); - - if (area == NULL) { - if (UT_LIST_GET_LEN(pool->free_list[i + 1]) > 0) { - ut_print_timestamp(stderr); - - fprintf(stderr, - " InnoDB: Error: mem pool free list %lu" - " length is %lu\n" - "InnoDB: though the list is empty!\n", - (ulong) i + 1, - (ulong) - UT_LIST_GET_LEN(pool->free_list[i + 1])); - } - - ret = mem_pool_fill_free_list(i + 1, pool); - - if (ret == FALSE) { - - return(FALSE); - } - - area = UT_LIST_GET_FIRST(pool->free_list[i + 1]); - } - - if (UT_LIST_GET_LEN(pool->free_list[i + 1]) == 0) { - mem_analyze_corruption(area); - - ut_error; - } - - UT_LIST_REMOVE(free_list, pool->free_list[i + 1], area); - - area2 = (mem_area_t*)(((byte*)area) + ut_2_exp(i)); - UNIV_MEM_ALLOC(area2, MEM_AREA_EXTRA_SIZE); - - mem_area_set_size(area2, ut_2_exp(i)); - mem_area_set_free(area2, TRUE); - - UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area2); - - mem_area_set_size(area, ut_2_exp(i)); - - UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area); - - return(TRUE); -} - -/************************************************************************ -Allocates memory from a pool. NOTE: This low-level function should only be -used in mem0mem.*! */ - -void* -mem_area_alloc( -/*===========*/ - /* out, own: allocated memory buffer */ - ulint size, /* in: allocated size in bytes; for optimum - space usage, the size should be a power of 2 - minus MEM_AREA_EXTRA_SIZE */ - mem_pool_t* pool) /* in: memory pool */ -{ -#ifdef UNIV_DISABLE_MEM_POOL - (void)pool; /* Remove compiler warning */ - return malloc(size); -#else /* UNIV_DISABLE_MEM_POOL */ - mem_area_t* area; - ulint n; - ibool ret; - - n = ut_2_log(ut_max(size + MEM_AREA_EXTRA_SIZE, MEM_AREA_MIN_SIZE)); - - mutex_enter(&(pool->mutex)); - mem_n_threads_inside++; - - ut_a(mem_n_threads_inside == 1); - - area = UT_LIST_GET_FIRST(pool->free_list[n]); - - if (area == NULL) { - ret = mem_pool_fill_free_list(n, pool); - - if (ret == FALSE) { - /* Out of memory in memory pool: we try to allocate - from the operating system with the regular malloc: */ - - mem_n_threads_inside--; - mutex_exit(&(pool->mutex)); - - return(ut_malloc(size)); - } - - area = UT_LIST_GET_FIRST(pool->free_list[n]); - } - - if (!mem_area_get_free(area)) { - fprintf(stderr, - "InnoDB: Error: Removing element from mem pool" - " free list %lu though the\n" - "InnoDB: element is not marked free!\n", - (ulong) n); - - mem_analyze_corruption(area); - - /* Try to analyze a strange assertion failure reported at - mysql@lists.mysql.com where the free bit IS 1 in the - hex dump above */ - - if (mem_area_get_free(area)) { - fprintf(stderr, - "InnoDB: Probably a race condition" - " because now the area is marked free!\n"); - } - - ut_error; - } - - if (UT_LIST_GET_LEN(pool->free_list[n]) == 0) { - fprintf(stderr, - "InnoDB: Error: Removing element from mem pool" - " free list %lu\n" - "InnoDB: though the list length is 0!\n", - (ulong) n); - mem_analyze_corruption(area); - - ut_error; - } - - ut_ad(mem_area_get_size(area) == ut_2_exp(n)); - - mem_area_set_free(area, FALSE); - - UT_LIST_REMOVE(free_list, pool->free_list[n], area); - - pool->reserved += mem_area_get_size(area); - - mem_n_threads_inside--; - mutex_exit(&(pool->mutex)); - - ut_ad(mem_pool_validate(pool)); - UNIV_MEM_ALLOC(MEM_AREA_EXTRA_SIZE + (byte*)area, - ut_2_exp(n) - MEM_AREA_EXTRA_SIZE); - - return((void*)(MEM_AREA_EXTRA_SIZE + ((byte*)area))); -#endif /* UNIV_DISABLE_MEM_POOL */ -} - -/************************************************************************ -Gets the buddy of an area, if it exists in pool. */ -UNIV_INLINE -mem_area_t* -mem_area_get_buddy( -/*===============*/ - /* out: the buddy, NULL if no buddy in pool */ - mem_area_t* area, /* in: memory area */ - ulint size, /* in: memory area size */ - mem_pool_t* pool) /* in: memory pool */ -{ - mem_area_t* buddy; - - ut_ad(size != 0); - - if (((((byte*)area) - pool->buf) % (2 * size)) == 0) { - - /* The buddy is in a higher address */ - - buddy = (mem_area_t*)(((byte*)area) + size); - - if ((((byte*)buddy) - pool->buf) + size > pool->size) { - - /* The buddy is not wholly contained in the pool: - there is no buddy */ - - buddy = NULL; - } - } else { - /* The buddy is in a lower address; NOTE that area cannot - be at the pool lower end, because then we would end up to - the upper branch in this if-clause: the remainder would be - 0 */ - - buddy = (mem_area_t*)(((byte*)area) - size); - } - - return(buddy); -} - -/************************************************************************ -Frees memory to a pool. */ - -void -mem_area_free( -/*==========*/ - void* ptr, /* in, own: pointer to allocated memory - buffer */ - mem_pool_t* pool) /* in: memory pool */ -{ -#ifdef UNIV_DISABLE_MEM_POOL - (void)pool; /* Remove compiler warning */ - free(ptr); -#else /* UNIV_DISABLE_MEM_POOL */ - mem_area_t* area; - mem_area_t* buddy; - void* new_ptr; - ulint size; - ulint n; - - /* It may be that the area was really allocated from the OS with - regular malloc: check if ptr points within our memory pool */ - - if ((byte*)ptr < pool->buf || (byte*)ptr >= pool->buf + pool->size) { - ut_free(ptr); - - return; - } - - area = (mem_area_t*) (((byte*)ptr) - MEM_AREA_EXTRA_SIZE); - - if (mem_area_get_free(area)) { - fprintf(stderr, - "InnoDB: Error: Freeing element to mem pool" - " free list though the\n" - "InnoDB: element is marked free!\n"); - - mem_analyze_corruption(area); - ut_error; - } - - size = mem_area_get_size(area); - UNIV_MEM_FREE(ptr, size - MEM_AREA_EXTRA_SIZE); - - if (size == 0) { - fprintf(stderr, - "InnoDB: Error: Mem area size is 0. Possibly a" - " memory overrun of the\n" - "InnoDB: previous allocated area!\n"); - - mem_analyze_corruption(area); - ut_error; - } - -#ifdef UNIV_LIGHT_MEM_DEBUG - if (((byte*)area) + size < pool->buf + pool->size) { - - ulint next_size; - - next_size = mem_area_get_size( - (mem_area_t*)(((byte*)area) + size)); - if (ut_2_power_up(next_size) != next_size) { - fprintf(stderr, - "InnoDB: Error: Memory area size %lu," - " next area size %lu not a power of 2!\n" - "InnoDB: Possibly a memory overrun of" - " the buffer being freed here.\n", - (ulong) size, (ulong) next_size); - mem_analyze_corruption(area); - - ut_error; - } - } -#endif - buddy = mem_area_get_buddy(area, size, pool); - - n = ut_2_log(size); - - mutex_enter(&(pool->mutex)); - mem_n_threads_inside++; - - ut_a(mem_n_threads_inside == 1); - - if (buddy && mem_area_get_free(buddy) - && (size == mem_area_get_size(buddy))) { - - /* The buddy is in a free list */ - - if ((byte*)buddy < (byte*)area) { - new_ptr = ((byte*)buddy) + MEM_AREA_EXTRA_SIZE; - - mem_area_set_size(buddy, 2 * size); - mem_area_set_free(buddy, FALSE); - } else { - new_ptr = ptr; - - mem_area_set_size(area, 2 * size); - } - - /* Remove the buddy from its free list and merge it to area */ - - UT_LIST_REMOVE(free_list, pool->free_list[n], buddy); - - pool->reserved += ut_2_exp(n); - - mem_n_threads_inside--; - mutex_exit(&(pool->mutex)); - - mem_area_free(new_ptr, pool); - - return; - } else { - UT_LIST_ADD_FIRST(free_list, pool->free_list[n], area); - - mem_area_set_free(area, TRUE); - - ut_ad(pool->reserved >= size); - - pool->reserved -= size; - } - - mem_n_threads_inside--; - mutex_exit(&(pool->mutex)); - - ut_ad(mem_pool_validate(pool)); -#endif /* UNIV_DISABLE_MEM_POOL */ -} - -/************************************************************************ -Validates a memory pool. */ - -ibool -mem_pool_validate( -/*==============*/ - /* out: TRUE if ok */ - mem_pool_t* pool) /* in: memory pool */ -{ - mem_area_t* area; - mem_area_t* buddy; - ulint free; - ulint i; - - mutex_enter(&(pool->mutex)); - - free = 0; - - for (i = 0; i < 64; i++) { - - UT_LIST_VALIDATE(free_list, mem_area_t, pool->free_list[i]); - - area = UT_LIST_GET_FIRST(pool->free_list[i]); - - while (area != NULL) { - ut_a(mem_area_get_free(area)); - ut_a(mem_area_get_size(area) == ut_2_exp(i)); - - buddy = mem_area_get_buddy(area, ut_2_exp(i), pool); - - ut_a(!buddy || !mem_area_get_free(buddy) - || (ut_2_exp(i) != mem_area_get_size(buddy))); - - area = UT_LIST_GET_NEXT(free_list, area); - - free += ut_2_exp(i); - } - } - - ut_a(free + pool->reserved == pool->size); - - mutex_exit(&(pool->mutex)); - - return(TRUE); -} - -/************************************************************************ -Prints info of a memory pool. */ - -void -mem_pool_print_info( -/*================*/ - FILE* outfile,/* in: output file to write to */ - mem_pool_t* pool) /* in: memory pool */ -{ - ulint i; - - mem_pool_validate(pool); - - fprintf(outfile, "INFO OF A MEMORY POOL\n"); - - mutex_enter(&(pool->mutex)); - - for (i = 0; i < 64; i++) { - if (UT_LIST_GET_LEN(pool->free_list[i]) > 0) { - - fprintf(outfile, - "Free list length %lu for" - " blocks of size %lu\n", - (ulong) UT_LIST_GET_LEN(pool->free_list[i]), - (ulong) ut_2_exp(i)); - } - } - - fprintf(outfile, "Pool size %lu, reserved %lu.\n", (ulong) pool->size, - (ulong) pool->reserved); - mutex_exit(&(pool->mutex)); -} - -/************************************************************************ -Returns the amount of reserved memory. */ - -ulint -mem_pool_get_reserved( -/*==================*/ - /* out: reserved memory in bytes */ - mem_pool_t* pool) /* in: memory pool */ -{ - ulint reserved; - - mutex_enter(&(pool->mutex)); - - reserved = pool->reserved; - - mutex_exit(&(pool->mutex)); - - return(reserved); -} |