mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
d04832d195
BitKeeper/etc/ignore: auto-union BUILD/autorun.sh: Auto merged BitKeeper/deleted/.del-bdb.vcproj~ed8534936e40cefb: Auto merged BitKeeper/deleted/.del-heap.vcproj~70c0cc1d680a51c1: Auto merged BitKeeper/deleted/.del-innobase.vcproj~71e1de81f11138bf: Auto merged BitKeeper/deleted/.del-myisam.vcproj~32bb9e4a163fcb5a: Auto merged BitKeeper/deleted/.del-myisammrg.vcproj~6534e59acbfbb63: Auto merged BitKeeper/deleted/.del-mysqld.vcproj~703886a28862bb2: Auto merged Makefile.am: Auto merged client/mysqltest.c: Auto merged include/my_global.h: Auto merged include/mysql_com.h: Auto merged mysql-test/mysql-test-run.pl: Auto merged mysql-test/r/ndb_alter_table.result: Auto merged mysql-test/r/ps_6bdb.result: Auto merged mysql-test/r/ps_7ndb.result: Auto merged mysql-test/t/query_cache.test: Auto merged mysys/default.c: Auto merged scripts/make_win_src_distribution.sh: Auto merged scripts/mysql_create_system_tables.sh: Auto merged scripts/mysql_fix_privilege_tables.sql: Auto merged sql/Makefile.am: Auto merged sql/field.cc: Auto merged sql/ha_berkeley.cc: Auto merged sql/ha_berkeley.h: Auto merged sql/ha_federated.cc: Auto merged sql/ha_heap.cc: Auto merged sql/ha_innodb.cc: Auto merged sql/ha_innodb.h: Auto merged sql/ha_myisam.cc: Auto merged sql/ha_myisammrg.cc: Auto merged sql/ha_ndbcluster.h: Auto merged sql/handler.cc: Auto merged sql/item.cc: Auto merged sql/item_subselect.cc: Auto merged sql/log.cc: Auto merged sql/mysql_priv.h: Auto merged sql/opt_sum.cc: Auto merged sql/repl_failsafe.cc: Auto merged sql/set_var.cc: Auto merged sql/sp.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_acl.h: Auto merged sql/sql_base.cc: Auto merged sql/sql_cache.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_delete.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_load.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_show.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/table.h: Auto merged sql/unireg.cc: Auto merged storage/innobase/buf/buf0buf.c: Auto merged storage/innobase/buf/buf0flu.c: Auto merged storage/innobase/data/data0data.c: Auto merged storage/innobase/dict/dict0dict.c: Auto merged storage/innobase/include/btr0btr.h: Auto merged storage/innobase/include/data0type.ic: Auto merged storage/innobase/include/dict0dict.h: Auto merged storage/innobase/include/dict0mem.h: Auto merged storage/innobase/include/mem0mem.h: Auto merged storage/innobase/include/mem0mem.ic: Auto merged storage/innobase/include/os0file.h: Auto merged storage/innobase/include/row0mysql.h: Auto merged storage/innobase/include/trx0trx.h: Auto merged storage/innobase/include/ut0mem.h: Auto merged storage/innobase/mem/mem0mem.c: Auto merged storage/innobase/os/os0file.c: Auto merged storage/innobase/os/os0proc.c: Auto merged storage/innobase/rem/rem0rec.c: Auto merged storage/innobase/row/row0ins.c: Auto merged storage/innobase/row/row0mysql.c: Auto merged storage/innobase/srv/srv0start.c: Auto merged storage/innobase/trx/trx0sys.c: Auto merged storage/innobase/trx/trx0trx.c: Auto merged storage/innobase/ut/ut0mem.c: Auto merged storage/myisam/ft_boolean_search.c: Auto merged storage/myisam/mi_check.c: Auto merged storage/myisam/mi_dbug.c: Auto merged storage/myisam/mi_delete.c: Auto merged storage/myisam/mi_delete_all.c: Auto merged storage/myisam/mi_key.c: Auto merged storage/myisam/mi_open.c: Auto merged storage/myisam/mi_rkey.c: Auto merged storage/myisam/mi_search.c: Auto merged storage/myisam/mi_test1.c: Auto merged storage/myisam/mi_update.c: Auto merged storage/myisam/mi_write.c: Auto merged storage/myisam/myisamchk.c: Auto merged storage/myisam/myisamdef.h: Auto merged storage/myisam/myisampack.c: Auto merged storage/myisam/sp_key.c: Auto merged storage/myisammrg/myrg_rkey.c: Auto merged storage/ndb/include/kernel/GlobalSignalNumbers.h: Auto merged storage/ndb/include/kernel/signaldata/ApiVersion.hpp: Auto merged storage/ndb/include/kernel/signaldata/EventReport.hpp: Auto merged storage/ndb/include/kernel/signaldata/StopReq.hpp: Auto merged storage/ndb/include/mgmapi/ndb_logevent.h: Auto merged storage/ndb/include/ndbapi/NdbBlob.hpp: Auto merged storage/ndb/include/ndbapi/NdbIndexOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbRecAttr.hpp: Auto merged storage/ndb/include/ndbapi/NdbTransaction.hpp: Auto merged storage/ndb/src/common/util/SimpleProperties.cpp: Auto merged storage/ndb/src/kernel/blocks/backup/Backup.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp: Auto merged storage/ndb/src/mgmapi/ndb_logevent.cpp: Auto merged storage/ndb/src/mgmclient/CommandInterpreter.cpp: Auto merged storage/ndb/src/mgmsrv/Config.cpp: Auto merged storage/ndb/src/mgmsrv/Config.hpp: Auto merged storage/ndb/src/mgmsrv/ConfigInfo.cpp: Auto merged storage/ndb/src/mgmsrv/InitConfigFileParser.cpp: Auto merged storage/ndb/src/mgmsrv/InitConfigFileParser.hpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvr.hpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp: Auto merged storage/ndb/src/mgmsrv/Services.cpp: Auto merged storage/ndb/src/mgmsrv/Services.hpp: Auto merged storage/ndb/src/mgmsrv/main.cpp: Auto merged storage/ndb/src/ndbapi/NdbApiSignal.cpp: Auto merged storage/ndb/src/ndbapi/NdbApiSignal.hpp: Auto merged storage/ndb/src/ndbapi/NdbBlob.cpp: Auto merged storage/ndb/src/ndbapi/NdbImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbRecAttr.cpp: Auto merged storage/ndb/src/ndbapi/NdbUtil.cpp: Auto merged storage/ndb/src/ndbapi/NdbUtil.hpp: Auto merged storage/ndb/src/ndbapi/Ndbif.cpp: Auto merged storage/ndb/src/ndbapi/Ndblist.cpp: Auto merged storage/ndb/src/ndbapi/ObjectMap.hpp: Auto merged storage/ndb/test/include/NDBT_Test.hpp: Auto merged storage/ndb/test/ndbapi/bank/BankLoad.cpp: Auto merged storage/ndb/test/ndbapi/testOIBasic.cpp: Auto merged storage/ndb/test/src/HugoCalculator.cpp: Auto merged storage/ndb/test/src/NDBT_Test.cpp: Auto merged storage/ndb/test/src/NdbBackup.cpp: Auto merged storage/ndb/test/src/NdbRestarts.cpp: Auto merged storage/ndb/tools/ndb_condig.cpp: Auto merged storage/ndb/tools/restore/Restore.cpp: Auto merged storage/ndb/tools/restore/consumer_restore.cpp: Auto merged support-files/mysql.spec.sh: Auto merged configure.in: merge BUILD/SETUP.sh: merge BitKeeper/deleted/.del-mysql.sln~f2120278f8a437be: SCCS merged libmysqld/Makefile.am: merge sql/ha_ndbcluster.cc: merge sql/handler.h: merge sql/mysqld.cc: merge sql/opt_range.cc: merge sql/slave.cc: merge sql/slave.h: e merge sql/sql_parse.cc: merge sql/table.cc: merge sql/examples/ha_tina.cc: merge sql/examples/ha_tina.h: merge sql/share/errmsg.txt: merge storage/ndb/include/ndbapi/Ndb.hpp: merge storage/ndb/src/common/debugger/EventLogger.cpp: merge storage/ndb/src/kernel/blocks/dbdict/Makefile.am: merge storage/ndb/src/mgmsrv/MgmtSrvr.cpp: merge storage/ndb/src/ndbapi/Ndbinit.cpp: SCCS merged
370 lines
10 KiB
C
370 lines
10 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 */
|
|
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 */
|
|
{
|
|
ulint len = strlen(str) + 1;
|
|
return(memcpy(mem_heap_alloc(heap, len), str, len));
|
|
}
|
|
|
|
/*******************************************************************
|
|
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 */
|
|
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((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_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 */
|
|
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
|