Commit dda7217e authored by marko's avatar marko

branches/zip: Free all resources at shutdown. Set pointers to NULL, so

that Valgrind will not complain about freed data structures that are
reachable via pointers.  This addresses Bug #45992 and Bug #46656.

This patch is mostly based on changes copied from branches/embedded-1.0,
mainly c5432, c3439, c3134, c2994, c2978, but also some other code was
copied.  Some added cleanup code is specific to MySQL/InnoDB.

rb://199 approved by Sunny Bains
parent 215f53bb
2009-01-01 The InnoDB Team
* btr/btr0sea.c, buf/buf0buf.c, dict/dict0dict.c, fil/fil0fil.c,
ibuf/ibuf0ibuf.c, include/btr0sea.h, include/dict0dict.h,
include/fil0fil.h, include/ibuf0ibuf.h, include/lock0lock.h,
include/log0log.h, include/log0recv.h, include/mem0mem.h,
include/mem0pool.h, include/os0file.h, include/pars0pars.h,
include/srv0srv.h, include/thr0loc.h, include/trx0i_s.h,
include/trx0purge.h, include/trx0rseg.h, include/trx0sys.h,
include/trx0undo.h, include/usr0sess.h, lock/lock0lock.c,
log/log0log.c, log/log0recv.c, mem/mem0dbg.c, mem/mem0pool.c,
os/os0file.c, os/os0sync.c, os/os0thread.c, pars/lexyy.c,
pars/pars0lex.l, que/que0que.c, srv/srv0srv.c, srv/srv0start.c,
sync/sync0arr.c, sync/sync0sync.c, thr/thr0loc.c, trx/trx0i_s.c,
trx/trx0purge.c, trx/trx0rseg.c, trx/trx0sys.c, trx/trx0undo.c,
usr/usr0sess.c, ut/ut0mem.c:
Fix Bug #45992 innodb memory not freed after shutdown
Fix Bug #46656 InnoDB plugin: memory leaks (Valgrind)
2009-10-29 The InnoDB Team
* handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
......
......@@ -175,6 +175,21 @@ btr_search_sys_create(
btr_search_sys->hash_index = ha_create(hash_size, 0, 0);
}
/*****************************************************************//**
Frees the adaptive search system at a database shutdown. */
UNIV_INTERN
void
btr_search_sys_free(void)
/*=====================*/
{
mem_free(btr_search_latch_temp);
btr_search_latch_temp = NULL;
mem_heap_free(btr_search_sys->hash_index->heap);
hash_table_free(btr_search_sys->hash_index);
mem_free(btr_search_sys);
btr_search_sys = NULL;
}
/********************************************************************//**
Disable the adaptive hash search system and empty the index. */
UNIV_INTERN
......
......@@ -1020,7 +1020,11 @@ buf_pool_free(void)
os_mem_free_large(chunk->mem, chunk->mem_size);
}
buf_pool->n_chunks = 0;
mem_free(buf_pool->chunks);
hash_table_free(buf_pool->page_hash);
hash_table_free(buf_pool->zip_hash);
mem_free(buf_pool);
buf_pool = NULL;
}
/********************************************************************//**
......
......@@ -4652,6 +4652,26 @@ dict_ind_init(void)
dict_ind_redundant->cached = dict_ind_compact->cached = TRUE;
}
/**********************************************************************//**
Frees dict_ind_redundant and dict_ind_compact. */
static
void
dict_ind_free(void)
/*===============*/
{
dict_table_t* table;
table = dict_ind_compact->table;
dict_mem_index_free(dict_ind_compact);
dict_ind_compact = NULL;
dict_mem_table_free(table);
table = dict_ind_redundant->table;
dict_mem_index_free(dict_ind_redundant);
dict_ind_redundant = NULL;
dict_mem_table_free(table);
}
#ifndef UNIV_HOTBACKUP
/**********************************************************************//**
Get index by name
......@@ -4777,4 +4797,55 @@ dict_table_check_for_dup_indexes(
}
}
#endif /* UNIV_DEBUG */
/**************************************************************************
Closes the data dictionary module. */
UNIV_INTERN
void
dict_close(void)
/*============*/
{
ulint i;
/* Free the hash elements. We don't remove them from the table
because we are going to destroy the table anyway. */
for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) {
dict_table_t* table;
table = HASH_GET_FIRST(dict_sys->table_hash, i);
while (table) {
dict_table_t* prev_table = table;
table = HASH_GET_NEXT(name_hash, prev_table);
#ifdef UNIV_DEBUG
ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N);
#endif
/* Acquire only because it's a pre-condition. */
mutex_enter(&dict_sys->mutex);
dict_table_remove_from_cache(prev_table);
mutex_exit(&dict_sys->mutex);
}
}
hash_table_free(dict_sys->table_hash);
/* The elements are the same instance as in dict_sys->table_hash,
therefore we don't delete the individual elements. */
hash_table_free(dict_sys->table_id_hash);
dict_ind_free();
mutex_free(&dict_sys->mutex);
rw_lock_free(&dict_operation_lock);
memset(&dict_operation_lock, 0x0, sizeof(dict_operation_lock));
mutex_free(&dict_foreign_err_mutex);
mem_free(dict_sys);
dict_sys = NULL;
}
#endif /* !UNIV_HOTBACKUP */
......@@ -321,6 +321,17 @@ fil_get_space_id_for_table(
/*=======================*/
const char* name); /*!< in: table name in the standard
'databasename/tablename' format */
/*******************************************************************//**
Frees a space object from the tablespace memory cache. Closes the files in
the chain but does not delete them. There must not be any pending i/o's or
flushes on the files. */
static
ibool
fil_space_free(
/*===========*/
/* out: TRUE if success */
ulint id, /* in: space id */
ibool own_mutex);/* in: TRUE if own system->mutex */
/********************************************************************//**
Reads data from a space to a buffer. Remember that the possible incomplete
blocks at the end of file are ignored: they are not taken into account when
......@@ -1144,7 +1155,7 @@ fil_space_create(
mutex_exit(&fil_system->mutex);
fil_space_free(namesake_id);
fil_space_free(namesake_id, FALSE);
goto try_again;
}
......@@ -1269,17 +1280,21 @@ Frees a space object from the tablespace memory cache. Closes the files in
the chain but does not delete them. There must not be any pending i/o's or
flushes on the files.
@return TRUE if success */
UNIV_INTERN
static
ibool
fil_space_free(
/*===========*/
ulint id) /*!< in: space id */
/* out: TRUE if success */
ulint id, /* in: space id */
ibool own_mutex) /* in: TRUE if own system->mutex */
{
fil_space_t* space;
fil_space_t* namespace;
fil_node_t* fil_node;
if (!own_mutex) {
mutex_enter(&fil_system->mutex);
}
space = fil_space_get_by_id(id);
......@@ -1326,7 +1341,9 @@ fil_space_free(
ut_a(0 == UT_LIST_GET_LEN(space->chain));
if (!own_mutex) {
mutex_exit(&fil_system->mutex);
}
rw_lock_free(&(space->latch));
......@@ -1586,6 +1603,8 @@ fil_close_all_files(void)
space = UT_LIST_GET_FIRST(fil_system->space_list);
while (space != NULL) {
fil_space_t* prev_space = space;
node = UT_LIST_GET_FIRST(space->chain);
while (node != NULL) {
......@@ -1595,6 +1614,7 @@ fil_close_all_files(void)
node = UT_LIST_GET_NEXT(chain, node);
}
space = UT_LIST_GET_NEXT(space_list, space);
fil_space_free(prev_space->id, TRUE);
}
mutex_exit(&fil_system->mutex);
......@@ -2226,7 +2246,7 @@ fil_delete_tablespace(
#endif
/* printf("Deleting tablespace %s id %lu\n", space->name, id); */
success = fil_space_free(id);
success = fil_space_free(id, FALSE);
if (success) {
success = os_file_delete(path);
......@@ -4753,3 +4773,26 @@ fil_page_get_type(
return(mach_read_from_2(page + FIL_PAGE_TYPE));
}
/********************************************************************
Initializes the tablespace memory cache. */
UNIV_INTERN
void
fil_close(void)
/*===========*/
{
/* The mutex should already have been freed. */
ut_ad(fil_system->mutex.magic_n == 0);
hash_table_free(fil_system->spaces);
hash_table_free(fil_system->name_hash);
ut_a(UT_LIST_GET_LEN(fil_system->LRU) == 0);
ut_a(UT_LIST_GET_LEN(fil_system->unflushed_spaces) == 0);
ut_a(UT_LIST_GET_LEN(fil_system->space_list) == 0);
mem_free(fil_system);
fil_system = NULL;
}
......@@ -389,6 +389,27 @@ ibuf_count_set(
}
#endif
/******************************************************************//**
Closes insert buffer and frees the data structures. */
UNIV_INTERN
void
ibuf_close(void)
/*============*/
{
mutex_free(&ibuf_pessimistic_insert_mutex);
memset(&ibuf_pessimistic_insert_mutex,
0x0, sizeof(ibuf_pessimistic_insert_mutex));
mutex_free(&ibuf_mutex);
memset(&ibuf_mutex, 0x0, sizeof(ibuf_mutex));
mutex_free(&ibuf_bitmap_mutex);
memset(&ibuf_bitmap_mutex, 0x0, sizeof(ibuf_mutex));
mem_free(ibuf);
ibuf = NULL;
}
/******************************************************************//**
Updates the size information of the ibuf, assuming the segment size has not
changed. */
......
......@@ -41,6 +41,12 @@ void
btr_search_sys_create(
/*==================*/
ulint hash_size); /*!< in: hash index hash table size */
/*****************************************************************//**
Frees the adaptive search system at a database shutdown. */
UNIV_INTERN
void
btr_search_sys_free(void);
/*=====================*/
/********************************************************************//**
Disable the adaptive hash search system and empty the index. */
......
......@@ -1151,6 +1151,13 @@ void
dict_ind_init(void);
/*===============*/
/**********************************************************************//**
Closes the data dictionary module. */
UNIV_INTERN
void
dict_close(void);
/*============*/
#ifndef UNIV_NONINL
#include "dict0dict.ic"
#endif
......
......@@ -224,15 +224,6 @@ fil_space_create(
0 for uncompressed tablespaces */
ulint purpose);/*!< in: FIL_TABLESPACE, or FIL_LOG if log */
/*******************************************************************//**
Frees a space object from a the tablespace memory cache. Closes the files in
the chain but does not delete them.
@return TRUE if success */
UNIV_INTERN
ibool
fil_space_free(
/*===========*/
ulint id); /*!< in: space id */
/*******************************************************************//**
Returns the size of the space in pages. The tablespace must be cached in the
memory cache.
@return space size, 0 if space not found */
......@@ -278,6 +269,12 @@ fil_init(
ulint hash_size, /*!< in: hash table size */
ulint max_n_open); /*!< in: max number of open files */
/*******************************************************************//**
Initializes the tablespace memory cache. */
UNIV_INTERN
void
fil_close(void);
/*===========*/
/*******************************************************************//**
Opens all log files and system tablespace data files. They stay open until the
database server shutdown. This should be called at a server startup after the
space objects for the log and the system tablespace have been created. The
......
......@@ -356,6 +356,12 @@ void
ibuf_print(
/*=======*/
FILE* file); /*!< in: file where to print */
/******************************************************************//**
Closes insert buffer and frees the data structures. */
UNIV_INTERN
void
ibuf_close(void);
/*============*/
#define IBUF_HEADER_PAGE_NO FSP_IBUF_HEADER_PAGE_NO
#define IBUF_TREE_ROOT_PAGE_NO FSP_IBUF_TREE_ROOT_PAGE_NO
......
......@@ -59,6 +59,12 @@ lock_sys_create(
/*============*/
ulint n_cells); /*!< in: number of slots in lock hash table */
/*********************************************************************//**
Closes the lock system at database shutdown. */
UNIV_INTERN
void
lock_sys_close(void);
/*================*/
/*********************************************************************//**
Checks if some transaction has an implicit x-lock on a record in a clustered
index.
@return transaction which has the x-lock, or NULL */
......
......@@ -572,6 +572,18 @@ UNIV_INTERN
void
log_refresh_stats(void);
/*===================*/
/**********************************************************
Shutdown the log system but do not release all the memory. */
UNIV_INTERN
void
log_shutdown(void);
/*==============*/
/**********************************************************
Free the log system data structures. */
UNIV_INTERN
void
log_mem_free(void);
/*==============*/
extern log_t* log_sys;
......@@ -721,9 +733,12 @@ struct log_group_struct{
ulint lsn_offset; /*!< the offset of the above lsn */
ulint n_pending_writes;/*!< number of currently pending flush
writes for this log group */
byte** file_header_bufs_ptr;/*!< unaligned buffers */
byte** file_header_bufs;/*!< buffers for each file
header in the group */
#ifdef UNIV_LOG_ARCHIVE
/*-----------------------------*/
byte** archive_file_header_bufs_ptr;/*!< unaligned buffers */
byte** archive_file_header_bufs;/*!< buffers for each file
header in the group */
ulint archive_space_id;/*!< file space which
......@@ -742,10 +757,12 @@ struct log_group_struct{
completion function then sets the new
value to ..._file_no */
ulint next_archived_offset; /*!< like the preceding field */
#endif /* UNIV_LOG_ARCHIVE */
/*-----------------------------*/
ib_uint64_t scanned_lsn; /*!< used only in recovery: recovery scan
succeeded up to this lsn in this log
group */
byte* checkpoint_buf_ptr;/*!< unaligned checkpoint header */
byte* checkpoint_buf; /*!< checkpoint header is written from
this buffer to the group */
UT_LIST_NODE_T(log_group_t)
......@@ -763,6 +780,7 @@ struct log_struct{
#ifndef UNIV_HOTBACKUP
mutex_t mutex; /*!< mutex protecting the log */
#endif /* !UNIV_HOTBACKUP */
byte* buf_ptr; /* unaligned log buffer */
byte* buf; /*!< log buffer */
ulint buf_size; /*!< log buffer size in bytes */
ulint max_buf_free; /*!< recommended maximum value of
......@@ -899,6 +917,7 @@ struct log_struct{
should wait for this without owning
the log mutex */
#endif /* !UNIV_HOTBACKUP */
byte* checkpoint_buf_ptr;/* unaligned checkpoint header */
byte* checkpoint_buf; /*!< checkpoint header is read to this
buffer */
/* @} */
......
......@@ -239,6 +239,18 @@ UNIV_INTERN
void
recv_sys_create(void);
/*=================*/
/**********************************************************//**
Release recovery system mutexes. */
UNIV_INTERN
void
recv_sys_close(void);
/*================*/
/********************************************************//**
Frees the recovery system memory. */
UNIV_INTERN
void
recv_sys_mem_free(void);
/*===================*/
/********************************************************//**
Inits the recovery system for a recovery operation. */
UNIV_INTERN
......@@ -246,6 +258,12 @@ void
recv_sys_init(
/*==========*/
ulint available_memory); /*!< in: available memory in bytes */
/********************************************************//**
Reset the state of the recovery system variables. */
UNIV_INTERN
void
recv_sys_var_init(void);
/*===================*/
/*******************************************************************//**
Empties the hash table of stored log records, applying them to appropriate
pages. */
......
......@@ -82,6 +82,13 @@ void
mem_init(
/*=====*/
ulint size); /*!< in: common pool size in bytes */
/******************************************************************//**
Closes the memory system. */
UNIV_INTERN
void
mem_close(void);
/*===========*/
/**************************************************************//**
Use this macro instead of the corresponding function! Macro for memory
heap creation. */
......
......@@ -62,6 +62,13 @@ mem_pool_create(
/*============*/
ulint size); /*!< in: pool size in bytes */
/********************************************************************//**
Frees a memory pool. */
UNIV_INTERN
void
mem_pool_free(
/*==========*/
mem_pool_t* pool); /*!< in, own: memory pool */
/********************************************************************//**
Allocates memory from a pool. NOTE: This low-level function should only be
used in mem0mem.*!
@return own: allocated memory buffer */
......
......@@ -620,6 +620,13 @@ os_aio_init(
ulint n_write_segs, /*<! in: number of writer threads */
ulint n_slots_sync); /*<! in: number of slots in the sync aio
array */
/***********************************************************************
Frees the asynchronous io system. */
UNIV_INTERN
void
os_aio_free(void);
/*=============*/
/*******************************************************************//**
Requests an asynchronous i/o operation.
@return TRUE if request was queued successfully, FALSE if fail */
......
......@@ -583,6 +583,12 @@ pars_info_get_bound_id(
pars_info_t* info, /*!< in: info struct */
const char* name); /*!< in: bound id name to find */
/******************************************************************//**
Release any resources used by the lexer. */
UNIV_INTERN
void
pars_lexer_close(void);
/*==================*/
/** Extra information supplied for pars_sql(). */
struct pars_info_struct {
......
......@@ -411,7 +411,7 @@ void
srv_init(void);
/*==========*/
/*********************************************************************//**
Frees the OS fast mutex created in srv_boot(). */
Frees the data structures created in srv_init(). */
UNIV_INTERN
void
srv_free(void);
......
......@@ -39,6 +39,12 @@ UNIV_INTERN
void
thr_local_init(void);
/*================*/
/****************************************************************//**
Close the thread local storage module. */
UNIV_INTERN
void
thr_local_close(void);
/*=================*/
/*******************************************************************//**
Creates a local storage struct for the calling new thread. */
UNIV_INTERN
......
......@@ -141,6 +141,13 @@ void
trx_i_s_cache_init(
/*===============*/
trx_i_s_cache_t* cache); /*!< out: cache to init */
/*******************************************************************//**
Free the INFORMATION SCHEMA trx related cache. */
UNIV_INTERN
void
trx_i_s_cache_free(
/*===============*/
trx_i_s_cache_t* cache); /*!< in/out: cache to free */
/*******************************************************************//**
Issue a shared/read lock on the tables cache. */
......
......@@ -71,6 +71,12 @@ void
trx_purge_sys_create(void);
/*======================*/
/********************************************************************//**
Frees the global purge system control structure. */
UNIV_INTERN
void
trx_purge_sys_close(void);
/*======================*/
/************************************************************************
Adds the update undo log as the first log in the history list. Removes the
update undo log segment from the rseg slot if it is too big for reuse. */
UNIV_INTERN
......
......@@ -125,6 +125,13 @@ trx_rseg_create(
ulint max_size, /*!< in: max size in pages */
ulint* id, /*!< out: rseg id */
mtr_t* mtr); /*!< in: mtr */
/***************************************************************************
Free's an instance of the rollback segment in memory. */
UNIV_INTERN
void
trx_rseg_mem_free(
/*==============*/
trx_rseg_t* rseg); /* in, own: instance to free */
/* Number of undo log slots in a rollback segment file copy */
......
......@@ -334,6 +334,12 @@ void
trx_sys_file_format_tag_init(void);
/*==============================*/
/*****************************************************************//**
Shutdown/Close the transaction system. */
UNIV_INTERN
void
trx_sys_close(void);
/*===============*/
/*****************************************************************//**
Get the name representation of the file format from its id.
@return pointer to the name */
UNIV_INTERN
......
......@@ -333,6 +333,13 @@ trx_undo_parse_discard_latest(
byte* end_ptr,/*!< in: buffer end */
page_t* page, /*!< in: page or NULL */
mtr_t* mtr); /*!< in: mtr or NULL */
/************************************************************************
Frees an undo log memory copy. */
UNIV_INTERN
void
trx_undo_mem_free(
/*==============*/
trx_undo_t* undo); /* in: the undo object to be freed */
/* Types of an undo log segment */
#define TRX_UNDO_INSERT 1 /* contains undo entries for inserts */
......
......@@ -44,14 +44,12 @@ sess_t*
sess_open(void);
/*============*/
/*********************************************************************//**
Closes a session, freeing the memory occupied by it, if it is in a state
where it should be closed.
@return TRUE if closed */
Closes a session, freeing the memory occupied by it. */
UNIV_INTERN
ibool
sess_try_close(
/*===========*/
sess_t* sess); /*!< in, own: session object */
void
sess_close(
/*=======*/
sess_t* sess); /* in, own: session object */
/* The session handle. All fields are protected by the kernel mutex */
struct sess_struct{
......
......@@ -577,6 +577,23 @@ lock_sys_create(
ut_a(lock_latest_err_file);
}
/*********************************************************************//**
Closes the lock system at database shutdown. */
UNIV_INTERN
void
lock_sys_close(void)
/*================*/
{
if (lock_latest_err_file != NULL) {
fclose(lock_latest_err_file);
lock_latest_err_file = NULL;
}
hash_table_free(lock_sys->rec_hash);
mem_free(lock_sys);
lock_sys = NULL;
}
/*********************************************************************//**
Gets the size of a lock struct.
@return size in bytes */
......
......@@ -771,8 +771,6 @@ void
log_init(void)
/*==========*/
{
byte* buf;
log_sys = mem_alloc(sizeof(log_t));
mutex_create(&log_sys->mutex, SYNC_LOG);
......@@ -787,8 +785,8 @@ log_init(void)
ut_a(LOG_BUFFER_SIZE >= 16 * OS_FILE_LOG_BLOCK_SIZE);
ut_a(LOG_BUFFER_SIZE >= 4 * UNIV_PAGE_SIZE);
buf = mem_alloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE);
log_sys->buf = ut_align(buf, OS_FILE_LOG_BLOCK_SIZE);
log_sys->buf_ptr = mem_alloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE);
log_sys->buf = ut_align(log_sys->buf_ptr, OS_FILE_LOG_BLOCK_SIZE);
log_sys->buf_size = LOG_BUFFER_SIZE;
......@@ -833,8 +831,8 @@ log_init(void)
rw_lock_create(&log_sys->checkpoint_lock, SYNC_NO_ORDER_CHECK);
log_sys->checkpoint_buf
= ut_align(mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE),
log_sys->checkpoint_buf_ptr = mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE);
log_sys->checkpoint_buf = ut_align(log_sys->checkpoint_buf_ptr,
OS_FILE_LOG_BLOCK_SIZE);
memset(log_sys->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE);
/*----------------------------*/
......@@ -918,23 +916,33 @@ log_group_init(
group->lsn_offset = LOG_FILE_HDR_SIZE;
group->n_pending_writes = 0;
group->file_header_bufs_ptr = mem_alloc(sizeof(byte*) * n_files);
group->file_header_bufs = mem_alloc(sizeof(byte*) * n_files);
#ifdef UNIV_LOG_ARCHIVE
group->archive_file_header_bufs_ptr = mem_alloc(
sizeof(byte*) * n_files);
group->archive_file_header_bufs = mem_alloc(sizeof(byte*) * n_files);
#endif /* UNIV_LOG_ARCHIVE */
for (i = 0; i < n_files; i++) {
*(group->file_header_bufs + i) = ut_align(
mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE),
group->file_header_bufs_ptr[i] = mem_alloc(
LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
group->file_header_bufs[i] = ut_align(
group->file_header_bufs_ptr[i],
OS_FILE_LOG_BLOCK_SIZE);
memset(*(group->file_header_bufs + i), '\0',
LOG_FILE_HDR_SIZE);
#ifdef UNIV_LOG_ARCHIVE
*(group->archive_file_header_bufs + i) = ut_align(
mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE),
group->archive_file_header_bufs_ptr[i] = mem_alloc(
LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
group->archive_file_header_bufs[i] = ut_align(
group->archive_file_header_bufs_ptr[i],
OS_FILE_LOG_BLOCK_SIZE);
memset(*(group->archive_file_header_bufs + i), '\0',
LOG_FILE_HDR_SIZE);
#endif /* UNIV_LOG_ARCHIVE */
......@@ -947,8 +955,9 @@ log_group_init(
group->archived_offset = 0;
#endif /* UNIV_LOG_ARCHIVE */
group->checkpoint_buf = ut_align(
mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE), OS_FILE_LOG_BLOCK_SIZE);
group->checkpoint_buf_ptr = mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE);
group->checkpoint_buf = ut_align(group->checkpoint_buf_ptr,
OS_FILE_LOG_BLOCK_SIZE);
memset(group->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE);
......@@ -3364,4 +3373,95 @@ log_refresh_stats(void)
log_sys->n_log_ios_old = log_sys->n_log_ios;
log_sys->last_printout_time = time(NULL);
}
/**********************************************************************
Closes a log group. */
static
void
log_group_close(
/*===========*/
log_group_t* group) /* in,own: log group to close */
{
ulint i;
for (i = 0; i < group->n_files; i++) {
mem_free(group->file_header_bufs_ptr[i]);
#ifdef UNIV_LOG_ARCHIVE
mem_free(group->archive_file_header_bufs_ptr[i]);
#endif /* UNIV_LOG_ARCHIVE */
}
mem_free(group->file_header_bufs_ptr);
mem_free(group->file_header_bufs);
#ifdef UNIV_LOG_ARCHIVE
mem_free(group->archive_file_header_bufs_ptr);
mem_free(group->archive_file_header_bufs);
#endif /* UNIV_LOG_ARCHIVE */
mem_free(group->checkpoint_buf_ptr);
mem_free(group);
}
/**********************************************************
Shutdown the log system but do not release all the memory. */
UNIV_INTERN
void
log_shutdown(void)
/*==============*/
{
log_group_t* group;
group = UT_LIST_GET_FIRST(log_sys->log_groups);
while (UT_LIST_GET_LEN(log_sys->log_groups) > 0) {
log_group_t* prev_group = group;
group = UT_LIST_GET_NEXT(log_groups, group);
UT_LIST_REMOVE(log_groups, log_sys->log_groups, prev_group);
log_group_close(prev_group);
}
mem_free(log_sys->buf_ptr);
log_sys->buf_ptr = NULL;
log_sys->buf = NULL;
mem_free(log_sys->checkpoint_buf_ptr);
log_sys->checkpoint_buf_ptr = NULL;
log_sys->checkpoint_buf = NULL;
os_event_free(log_sys->no_flush_event);
os_event_free(log_sys->one_flushed_event);
rw_lock_free(&log_sys->checkpoint_lock);
mutex_free(&log_sys->mutex);
#ifdef UNIV_LOG_ARCHIVE
rw_lock_free(&log_sys->archive_lock);
os_event_create(log_sys->archiving_on);
#endif /* UNIV_LOG_ARCHIVE */
#ifdef UNIV_LOG_DEBUG
recv_sys_debug_free();
#endif
recv_sys_close();
}
/**********************************************************
Free the log system data structures. */
UNIV_INTERN
void
log_mem_free(void)
/*==============*/
{
if (log_sys != NULL) {
recv_sys_mem_free();
mem_free(log_sys);
log_sys = NULL;
}
}
#endif /* !UNIV_HOTBACKUP */
......@@ -69,15 +69,15 @@ UNIV_INTERN recv_sys_t* recv_sys = NULL;
/** TRUE when applying redo log records during crash recovery; FALSE
otherwise. Note that this is FALSE while a background thread is
rolling back incomplete transactions. */
UNIV_INTERN ibool recv_recovery_on = FALSE;
UNIV_INTERN ibool recv_recovery_on;
#ifdef UNIV_LOG_ARCHIVE
/** TRUE when applying redo log records from an archived log file */
UNIV_INTERN ibool recv_recovery_from_backup_on = FALSE;
UNIV_INTERN ibool recv_recovery_from_backup_on;
#endif /* UNIV_LOG_ARCHIVE */
#ifndef UNIV_HOTBACKUP
/** TRUE when recv_init_crash_recovery() has been called. */
UNIV_INTERN ibool recv_needed_recovery = FALSE;
UNIV_INTERN ibool recv_needed_recovery;
# ifdef UNIV_DEBUG
/** TRUE if writing to the redo log (mtr_commit) is forbidden.
Protected by log_sys->mutex. */
......@@ -87,7 +87,7 @@ UNIV_INTERN ibool recv_no_log_write = FALSE;
/** TRUE if buf_page_is_corrupted() should check if the log sequence
number (FIL_PAGE_LSN) is in the future. Initially FALSE, and set by
recv_recovery_from_checkpoint_start_func(). */
UNIV_INTERN ibool recv_lsn_checks_on = FALSE;
UNIV_INTERN ibool recv_lsn_checks_on;
/** There are two conditions under which we scan the logs, the first
is normal startup and the second is when we do a recovery from an
......@@ -97,7 +97,7 @@ startup. If we find log entries that were written after the last checkpoint
we know that the server was not cleanly shutdown. We must then initialize
the crash recovery environment before attempting to store these entries in
the log hash table. */
static ibool recv_log_scan_is_startup_type = FALSE;
static ibool recv_log_scan_is_startup_type;
/** If the following is TRUE, the buffer pool file pages must be invalidated
after recovery and no ibuf operations are allowed; this becomes TRUE if
......@@ -108,7 +108,7 @@ buffer pool before the pages have been recovered to the up-to-date state.
TRUE means that recovery is running and no operations on the log files
are allowed yet: the variable name is misleading. */
UNIV_INTERN ibool recv_no_ibuf_operations = FALSE;
UNIV_INTERN ibool recv_no_ibuf_operations;
/** TRUE when the redo log is being backed up */
# define recv_is_making_a_backup FALSE
/** TRUE when recovering from a backed up redo log file */
......@@ -123,23 +123,23 @@ UNIV_INTERN ibool recv_is_from_backup = FALSE;
#endif /* !UNIV_HOTBACKUP */
/** The following counter is used to decide when to print info on
log scan */
static ulint recv_scan_print_counter = 0;
static ulint recv_scan_print_counter;
/** The type of the previous parsed redo log record */
static ulint recv_previous_parsed_rec_type = 999999;
static ulint recv_previous_parsed_rec_type;
/** The offset of the previous parsed redo log record */
static ulint recv_previous_parsed_rec_offset = 0;
static ulint recv_previous_parsed_rec_offset;
/** The 'multi' flag of the previous parsed redo log record */
static ulint recv_previous_parsed_rec_is_multi = 0;
static ulint recv_previous_parsed_rec_is_multi;
/** Maximum page number encountered in the redo log */
UNIV_INTERN ulint recv_max_parsed_page_no = 0;
UNIV_INTERN ulint recv_max_parsed_page_no;
/** This many frames must be left free in the buffer pool when we scan
the log and store the scanned log records in the buffer pool: we will
use these free frames to read in pages when we start applying the
log records to the database. */
UNIV_INTERN ulint recv_n_pool_free_frames = 256;
UNIV_INTERN ulint recv_n_pool_free_frames;
/** The maximum lsn we see for a page during the recovery process. If this
is bigger than the lsn we are able to scan up to, that is an indication that
......@@ -170,7 +170,8 @@ recv_sys_create(void)
return;
}
recv_sys = mem_alloc(sizeof(recv_sys_t));
recv_sys = mem_alloc(sizeof(*recv_sys));
memset(recv_sys, 0x0, sizeof(*recv_sys));
mutex_create(&recv_sys->mutex, SYNC_RECV);
......@@ -179,6 +180,106 @@ recv_sys_create(void)
}
/********************************************************//**
Release recovery system mutexes. */
UNIV_INTERN
void
recv_sys_close(void)
/*================*/
{
if (recv_sys != NULL) {
if (recv_sys->addr_hash != NULL) {
hash_table_free(recv_sys->addr_hash);
}
if (recv_sys->heap != NULL) {
mem_heap_free(recv_sys->heap);
}
if (recv_sys->buf != NULL) {
ut_free(recv_sys->buf);
}
if (recv_sys->last_block_buf_start != NULL) {
mem_free(recv_sys->last_block_buf_start);
}
mutex_free(&recv_sys->mutex);
mem_free(recv_sys);
recv_sys = NULL;
}
}
/********************************************************//**
Frees the recovery system memory. */
UNIV_INTERN
void
recv_sys_mem_free(void)
/*===================*/
{
if (recv_sys != NULL) {
if (recv_sys->addr_hash != NULL) {
hash_table_free(recv_sys->addr_hash);
}
if (recv_sys->heap != NULL) {
mem_heap_free(recv_sys->heap);
}
if (recv_sys->buf != NULL) {
ut_free(recv_sys->buf);
}
if (recv_sys->last_block_buf_start != NULL) {
mem_free(recv_sys->last_block_buf_start);
}
mem_free(recv_sys);
recv_sys = NULL;
}
}
/************************************************************
Reset the state of the recovery system variables. */
UNIV_INTERN
void
recv_sys_var_init(void)
/*===================*/
{
recv_lsn_checks_on = FALSE;
recv_n_pool_free_frames = 256;
recv_recovery_on = FALSE;
#ifdef UNIV_LOG_ARCHIVE
recv_recovery_from_backup_on = FALSE;
#endif /* UNIV_LOG_ARCHIVE */
recv_needed_recovery = FALSE;
recv_lsn_checks_on = FALSE;
recv_log_scan_is_startup_type = FALSE;
recv_no_ibuf_operations = FALSE;
recv_scan_print_counter = 0;
recv_previous_parsed_rec_type = 999999;
recv_previous_parsed_rec_offset = 0;
recv_previous_parsed_rec_is_multi = 0;
recv_max_parsed_page_no = 0;
recv_n_pool_free_frames = 256;
recv_max_page_lsn = 0;
}
/************************************************************
Inits the recovery system for a recovery operation. */
UNIV_INTERN
void
......@@ -253,8 +354,8 @@ recv_sys_empty_hash(void)
Frees the recovery system. */
static
void
recv_sys_free(void)
/*===============*/
recv_sys_debug_free(void)
/*=====================*/
{
mutex_enter(&(recv_sys->mutex));
......@@ -263,8 +364,10 @@ recv_sys_free(void)
ut_free(recv_sys->buf);
mem_free(recv_sys->last_block_buf_start);
recv_sys->addr_hash = NULL;
recv_sys->buf = NULL;
recv_sys->heap = NULL;
recv_sys->addr_hash = NULL;
recv_sys->last_block_buf_start = NULL;
mutex_exit(&(recv_sys->mutex));
}
......@@ -3149,7 +3252,7 @@ recv_recovery_from_checkpoint_finish(void)
recv_recovery_on = FALSE;
#ifndef UNIV_LOG_DEBUG
recv_sys_free();
recv_sys_debug_free();
#endif
/* Roll back any recovered data dictionary transactions, so
that the data dictionary tables will be free of any locks.
......
......@@ -170,6 +170,17 @@ mem_init(
mem_comm_pool = mem_pool_create(size);
}
/******************************************************************//**
Closes the memory system. */
UNIV_INTERN
void
mem_close(void)
/*===========*/
{
mem_pool_free(mem_comm_pool);
mem_comm_pool = NULL;
}
#endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_MEM_DEBUG
......
......@@ -260,6 +260,18 @@ mem_pool_create(
return(pool);
}
/********************************************************************//**
Frees a memory pool. */
UNIV_INTERN
void
mem_pool_free(
/*==========*/
mem_pool_t* pool) /*!< in, own: memory pool */
{
ut_free(pool->buf);
ut_free(pool);
}
/********************************************************************//**
Fills the specified free list.
@return TRUE if we were able to insert a block to the free list */
......
......@@ -3029,6 +3029,34 @@ os_aio_array_create(
return(array);
}
/************************************************************************//**
Frees an aio wait array. */
static
void
os_aio_array_free(
/*==============*/
os_aio_array_t* array) /*!< in, own: array to free */
{
#ifdef WIN_ASYNC_IO
ulint i;
for (i = 0; i < array->n_slots; i++) {
os_aio_slot_t* slot = os_aio_array_get_nth_slot(array, i);
os_event_free(slot->event);
}
#endif /* WIN_ASYNC_IO */
#ifdef __WIN__
ut_free(array->native_events);
#endif /* __WIN__ */
os_mutex_free(array->mutex);
os_event_free(array->not_full);
os_event_free(array->is_empty);
ut_free(array->slots);
ut_free(array);
}
/***********************************************************************
Initializes the asynchronous io system. Creates one array each for ibuf
and log i/o. Also creates one array each for read and write where each
......@@ -3099,6 +3127,35 @@ os_aio_init(
}
/***********************************************************************
Frees the asynchronous io system. */
UNIV_INTERN
void
os_aio_free(void)
/*=============*/
{
ulint i;
os_aio_array_free(os_aio_ibuf_array);
os_aio_ibuf_array = NULL;
os_aio_array_free(os_aio_log_array);
os_aio_log_array = NULL;
os_aio_array_free(os_aio_read_array);
os_aio_read_array = NULL;
os_aio_array_free(os_aio_write_array);
os_aio_write_array = NULL;
os_aio_array_free(os_aio_sync_array);
os_aio_sync_array = NULL;
for (i = 0; i < os_aio_n_segments; i++) {
os_event_free(os_aio_segment_wait_events[i]);
}
ut_free(os_aio_segment_wait_events);
os_aio_segment_wait_events = 0;
os_aio_n_segments = 0;
}
#ifdef WIN_ASYNC_IO
/************************************************************************//**
Wakes up all async i/o threads in the array in Windows async i/o at
......
......@@ -86,6 +86,9 @@ os_sync_init(void)
UT_LIST_INIT(os_event_list);
UT_LIST_INIT(os_mutex_list);
os_sync_mutex = NULL;
os_sync_mutex_inited = FALSE;
os_sync_mutex = os_mutex_create(NULL);
os_sync_mutex_inited = TRUE;
......@@ -713,6 +716,7 @@ os_fast_mutex_free(
os_mutex_enter(os_sync_mutex);
}
ut_ad(os_fast_mutex_count > 0);
os_fast_mutex_count--;
if (UNIV_LIKELY(os_sync_mutex_inited)) {
......
......@@ -233,6 +233,7 @@ os_thread_exit(
#ifdef __WIN__
ExitThread((DWORD)exit_value);
#else
pthread_detach(pthread_self());
pthread_exit(exit_value);
#endif
}
......
......@@ -2778,3 +2778,16 @@ static void yyfree (void * ptr )
/**********************************************************************
Release any resources used by the lexer. */
UNIV_INTERN
void
pars_lexer_close(void)
/*==================*/
{
yylex_destroy();
free(stringbuf);
stringbuf = NULL;
stringbuf_len_alloc = stringbuf_len = 0;
}
......@@ -661,3 +661,16 @@ In the state 'id', only two actions are possible (defined below). */
}
%%
/**********************************************************************
Release any resources used by the lexer. */
UNIV_INTERN
void
pars_lexer_close(void)
/*==================*/
{
yylex_destroy();
free(stringbuf);
stringbuf = NULL;
stringbuf_len_alloc = stringbuf_len = 0;
}
......@@ -518,6 +518,7 @@ que_graph_free_recursive(
upd_node_t* upd;
tab_node_t* cre_tab;
ind_node_t* cre_ind;
purge_node_t* purge;
if (node == NULL) {
......@@ -579,6 +580,13 @@ que_graph_free_recursive(
mem_heap_free(ins->entry_sys_heap);
break;
case QUE_NODE_PURGE:
purge = node;
mem_heap_free(purge->heap);
break;
case QUE_NODE_UPDATE:
upd = node;
......
......@@ -1006,13 +1006,26 @@ srv_init(void)
}
/*********************************************************************//**
Frees the OS fast mutex created in srv_init(). */
Frees the data structures created in srv_init(). */
UNIV_INTERN
void
srv_free(void)
/*==========*/
{
os_fast_mutex_free(&srv_conc_mutex);
mem_free(srv_conc_slots);
srv_conc_slots = NULL;
mem_free(srv_sys->threads);
mem_free(srv_sys);
srv_sys = NULL;
mem_free(kernel_mutex_temp);
kernel_mutex_temp = NULL;
mem_free(srv_mysql_table);
srv_mysql_table = NULL;
trx_i_s_cache_free(trx_i_s_cache);
}
/*********************************************************************//**
......@@ -1024,6 +1037,8 @@ srv_general_init(void)
/*==================*/
{
ut_mem_init();
/* Reset the system variables in the recovery module. */
recv_sys_var_init();
os_sync_init();
sync_init();
mem_init(srv_mem_pool_size);
......
......@@ -103,6 +103,7 @@ Created 2/16/1996 Heikki Tuuri
# include "row0row.h"
# include "row0mysql.h"
# include "btr0pcur.h"
# include "thr0loc.h"
# include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */
/** Log sequence number immediately after startup */
......@@ -495,6 +496,8 @@ io_handler_thread(
mutex_exit(&ios_mutex);
}
thr_local_free(os_thread_get_curr_id());
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit.
The thread actually never comes here because it is exited in an
......@@ -531,32 +534,6 @@ srv_normalize_path_for_win(
#endif
}
/*********************************************************************//**
Adds a slash or a backslash to the end of a string if it is missing
and the string is not empty.
@return string which has the separator if the string is not empty */
UNIV_INTERN
char*
srv_add_path_separator_if_needed(
/*=============================*/
char* str) /*!< in: null-terminated character string */
{
char* out_str;
ulint len = ut_strlen(str);
if (len == 0 || str[len - 1] == SRV_PATH_SEPARATOR) {
return(str);
}
out_str = ut_malloc(len + 2);
memcpy(out_str, str, len);
out_str[len] = SRV_PATH_SEPARATOR;
out_str[len + 1] = 0;
return(out_str);
}
#ifndef UNIV_HOTBACKUP
/*********************************************************************//**
Calculates the low 32 bits when a file size which is given as a number
......@@ -605,19 +582,24 @@ open_or_create_log_file(
ulint size;
ulint size_high;
char name[10000];
ulint dirnamelen;
UT_NOT_USED(create_new_db);
*log_file_created = FALSE;
srv_normalize_path_for_win(srv_log_group_home_dirs[k]);
srv_log_group_home_dirs[k] = srv_add_path_separator_if_needed(
srv_log_group_home_dirs[k]);
ut_a(strlen(srv_log_group_home_dirs[k])
< (sizeof name) - 10 - sizeof "ib_logfile");
sprintf(name, "%s%s%lu", srv_log_group_home_dirs[k],
"ib_logfile", (ulong) i);
dirnamelen = strlen(srv_log_group_home_dirs[k]);
ut_a(dirnamelen < (sizeof name) - 10 - sizeof "ib_logfile");
memcpy(name, srv_log_group_home_dirs[k], dirnamelen);
/* Add a path separator if needed. */
if (dirnamelen && name[dirnamelen - 1] != SRV_PATH_SEPARATOR) {
name[dirnamelen++] = SRV_PATH_SEPARATOR;
}
sprintf(name + dirnamelen, "%s%lu", "ib_logfile", (ulong) i);
files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_NORMAL,
OS_LOG_FILE, &ret);
......@@ -780,14 +762,22 @@ open_or_create_data_files(
*create_new_db = FALSE;
srv_normalize_path_for_win(srv_data_home);
srv_data_home = srv_add_path_separator_if_needed(srv_data_home);
for (i = 0; i < srv_n_data_files; i++) {
ulint dirnamelen;
srv_normalize_path_for_win(srv_data_file_names[i]);
dirnamelen = strlen(srv_data_home);
ut_a(strlen(srv_data_home) + strlen(srv_data_file_names[i])
ut_a(dirnamelen + strlen(srv_data_file_names[i])
< (sizeof name) - 1);
sprintf(name, "%s%s", srv_data_home, srv_data_file_names[i]);
memcpy(name, srv_data_home, dirnamelen);
/* Add a path separator if needed. */
if (dirnamelen && name[dirnamelen - 1] != SRV_PATH_SEPARATOR) {
name[dirnamelen++] = SRV_PATH_SEPARATOR;
}
strcpy(name + dirnamelen, srv_data_file_names[i]);
if (srv_data_file_is_raw_partition[i] == 0) {
......@@ -1009,7 +999,7 @@ open_or_create_data_files(
return(DB_SUCCESS);
}
/****************************************************************//**
/********************************************************************
Starts InnoDB and creates a new database if database files
are not found and the user wants.
@return DB_SUCCESS or error code */
......@@ -1120,7 +1110,7 @@ innobase_start_or_create_for_mysql(void)
if (srv_start_has_been_called) {
fprintf(stderr,
"InnoDB: Error:startup called second time"
"InnoDB: Error: startup called second time"
" during the process lifetime.\n"
"InnoDB: In the MySQL Embedded Server Library"
" you cannot call server_init()\n"
......@@ -1959,8 +1949,10 @@ innobase_shutdown_for_mysql(void)
/* All the threads have exited or are just exiting;
NOTE that the threads may not have completed their
exit yet. Should we use pthread_join() to make sure
they have exited? Now we just sleep 0.1 seconds and
hope that is enough! */
they have exited? If we did, we would have to
remove the pthread_detach() from
os_thread_exit(). Now we just sleep 0.1
seconds and hope that is enough! */
os_mutex_exit(os_sync_mutex);
......@@ -1999,37 +1991,41 @@ innobase_shutdown_for_mysql(void)
srv_misc_tmpfile = 0;
}
/* This must be disabled before closing the buffer pool
and closing the data dictionary. */
btr_search_disable();
ibuf_close();
log_shutdown();
lock_sys_close();
thr_local_close();
trx_sys_file_format_close();
trx_sys_close();
mutex_free(&srv_monitor_file_mutex);
mutex_free(&srv_dict_tmpfile_mutex);
mutex_free(&srv_misc_tmpfile_mutex);
dict_close();
btr_search_sys_free();
/* 3. Free all InnoDB's own mutexes and the os_fast_mutexes inside
them */
os_aio_free();
sync_close();
srv_free();
fil_close();
/* 4. Free the os_conc_mutex and all os_events and os_mutexes */
srv_free();
os_sync_free();
/* Check that all read views are closed except read view owned
by a purge. */
if (UT_LIST_GET_LEN(trx_sys->view_list) > 1) {
fprintf(stderr,
"InnoDB: Error: all read views were not closed"
" before shutdown:\n"
"InnoDB: %lu read views open \n",
UT_LIST_GET_LEN(trx_sys->view_list) - 1);
}
/* 5. Free all allocated memory and the os_fast_mutex created in
ut0mem.c */
/* 5. Free all allocated memory */
pars_lexer_close();
log_mem_free();
buf_pool_free();
ut_free_all_mem();
mem_close();
if (os_thread_count != 0
|| os_event_count != 0
......@@ -2060,6 +2056,7 @@ innobase_shutdown_for_mysql(void)
}
srv_was_started = FALSE;
srv_start_has_been_called = FALSE;
return((int) DB_SUCCESS);
}
......
......@@ -227,24 +227,21 @@ sync_array_create(
SYNC_ARRAY_MUTEX: determines the type
of mutex protecting the data structure */
{
ulint sz;
sync_array_t* arr;
sync_cell_t* cell_array;
sync_cell_t* cell;
ulint i;
ut_a(n_cells > 0);
/* Allocate memory for the data structures */
arr = ut_malloc(sizeof(sync_array_t));
memset(arr, 0x0, sizeof(*arr));
cell_array = ut_malloc(sizeof(sync_cell_t) * n_cells);
sz = sizeof(sync_cell_t) * n_cells;
arr->array = ut_malloc(sz);
memset(arr->array, 0x0, sz);
arr->n_cells = n_cells;
arr->n_reserved = 0;
arr->array = cell_array;
arr->protection = protection;
arr->sg_count = 0;
arr->res_count = 0;
/* Then create the mutex to protect the wait array complex */
if (protection == SYNC_ARRAY_OS_MUTEX) {
......@@ -255,13 +252,6 @@ sync_array_create(
ut_error;
}
for (i = 0; i < n_cells; i++) {
cell = sync_array_get_nth_cell(arr, i);
cell->wait_object = NULL;
cell->waiting = FALSE;
cell->signal_count = 0;
}
return(arr);
}
......
......@@ -1377,7 +1377,12 @@ sync_close(void)
mutex_free(&mutex_list_mutex);
#ifdef UNIV_SYNC_DEBUG
mutex_free(&sync_thread_mutex);
/* Switch latching order checks on in sync0sync.c */
sync_order_checks_on = FALSE;
#endif /* UNIV_SYNC_DEBUG */
sync_initialized = FALSE;
}
/*******************************************************************//**
......
......@@ -246,3 +246,34 @@ thr_local_init(void)
mutex_create(&thr_local_mutex, SYNC_THR_LOCAL);
}
/********************************************************************
Close the thread local storage module. */
UNIV_INTERN
void
thr_local_close(void)
/*=================*/
{
ulint i;
ut_a(thr_local_hash != NULL);
/* Free the hash elements. We don't remove them from the table
because we are going to destroy the table anyway. */
for (i = 0; i < hash_get_n_cells(thr_local_hash); i++) {
thr_local_t* local;
local = HASH_GET_FIRST(thr_local_hash, i);
while (local) {
thr_local_t* prev_local = local;
local = HASH_GET_NEXT(hash, prev_local);
ut_a(prev_local->magic_n == THR_LOCAL_MAGIC_N);
mem_free(prev_local);
}
}
hash_table_free(thr_local_hash);
thr_local_hash = NULL;
}
......@@ -237,6 +237,27 @@ table_cache_init(
}
}
/*******************************************************************//**
Frees a table cache. */
static
void
table_cache_free(
/*=============*/
i_s_table_cache_t* table_cache) /*!< in/out: table cache */
{
ulint i;
for (i = 0; i < MEM_CHUNKS_IN_TABLE_CACHE; i++) {
/* the memory is actually allocated in
table_cache_create_empty_row() */
if (table_cache->chunks[i].base) {
mem_free(table_cache->chunks[i].base);
table_cache->chunks[i].base = NULL;
}
}
}
/*******************************************************************//**
Returns an empty row from a table cache. The row is allocated if no more
empty rows are available. The number of used rows is incremented.
......@@ -1251,6 +1272,22 @@ trx_i_s_cache_init(
cache->is_truncated = FALSE;
}
/*******************************************************************//**
Free the INFORMATION SCHEMA trx related cache. */
UNIV_INTERN
void
trx_i_s_cache_free(
/*===============*/
trx_i_s_cache_t* cache) /*!< in, own: cache to free */
{
hash_table_free(cache->locks_hash);
ha_storage_free(cache->storage);
table_cache_free(&cache->innodb_trx);
table_cache_free(&cache->innodb_locks);
table_cache_free(&cache->innodb_lock_waits);
memset(cache, 0, sizeof *cache);
}
/*******************************************************************//**
Issue a shared/read lock on the tables cache. */
UNIV_INTERN
......
......@@ -249,6 +249,44 @@ trx_purge_sys_create(void)
purge_sys->heap);
}
/************************************************************************
Frees the global purge system control structure. */
UNIV_INTERN
void
trx_purge_sys_close(void)
/*======================*/
{
ut_ad(!mutex_own(&kernel_mutex));
que_graph_free(purge_sys->query);
ut_a(purge_sys->sess->trx->is_purge);
purge_sys->sess->trx->conc_state = TRX_NOT_STARTED;
sess_close(purge_sys->sess);
purge_sys->sess = NULL;
if (purge_sys->view != NULL) {
/* Because acquiring the kernel mutex is a pre-condition
of read_view_close(). We don't really need it here. */
mutex_enter(&kernel_mutex);
read_view_close(purge_sys->view);
purge_sys->view = NULL;
mutex_exit(&kernel_mutex);
}
trx_undo_arr_free(purge_sys->arr);
rw_lock_free(&purge_sys->latch);
mutex_free(&purge_sys->mutex);
mem_heap_free(purge_sys->heap);
mem_free(purge_sys);
purge_sys = NULL;
}
/*================ UNDO LOG HISTORY LIST =============================*/
/********************************************************************//**
......
......@@ -132,6 +132,49 @@ trx_rseg_header_create(
}
/***********************************************************************//**
Free's an instance of the rollback segment in memory. */
UNIV_INTERN
void
trx_rseg_mem_free(
/*==============*/
trx_rseg_t* rseg) /* in, own: instance to free */
{
trx_undo_t* undo;
mutex_free(&rseg->mutex);
/* There can't be any active transactions. */
ut_a(UT_LIST_GET_LEN(rseg->update_undo_list) == 0);
ut_a(UT_LIST_GET_LEN(rseg->insert_undo_list) == 0);
undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);
while (undo != NULL) {
trx_undo_t* prev_undo = undo;
undo = UT_LIST_GET_NEXT(undo_list, undo);
UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, prev_undo);
trx_undo_mem_free(prev_undo);
}
undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);
while (undo != NULL) {
trx_undo_t* prev_undo = undo;
undo = UT_LIST_GET_NEXT(undo_list, undo);
UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, prev_undo);
trx_undo_mem_free(prev_undo);
}
trx_sys_set_nth_rseg(trx_sys, rseg->id, NULL);
mem_free(rseg);
}
/***************************************************************************
Creates and initializes a rollback segment object. The values for the
fields are read from the header. The object is inserted to the rseg
list of the trx system object and a pointer is inserted in the rseg
......
......@@ -40,6 +40,7 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0purge.h"
#include "log0log.h"
#include "os0file.h"
#include "read0read.h"
/** The file format tag structure with id and name. */
struct file_format_struct {
......@@ -1533,3 +1534,80 @@ trx_sys_file_format_id_to_name(
}
#endif /* !UNIV_HOTBACKUP */
/*********************************************************************
Shutdown/Close the transaction system. */
UNIV_INTERN
void
trx_sys_close(void)
/*===============*/
{
trx_rseg_t* rseg;
read_view_t* view;
ut_ad(trx_sys != NULL);
/* Check that all read views are closed except read view owned
by a purge. */
if (UT_LIST_GET_LEN(trx_sys->view_list) > 1) {
fprintf(stderr,
"InnoDB: Error: all read views were not closed"
" before shutdown:\n"
"InnoDB: %lu read views open \n",
UT_LIST_GET_LEN(trx_sys->view_list) - 1);
}
sess_close(trx_dummy_sess);
trx_dummy_sess = NULL;
trx_purge_sys_close();
mutex_enter(&kernel_mutex);
/* Free the double write data structures. */
ut_a(trx_doublewrite != NULL);
ut_free(trx_doublewrite->write_buf_unaligned);
trx_doublewrite->write_buf_unaligned = NULL;
mem_free(trx_doublewrite->buf_block_arr);
trx_doublewrite->buf_block_arr = NULL;
mutex_free(&trx_doublewrite->mutex);
mem_free(trx_doublewrite);
trx_doublewrite = NULL;
/* There can't be any active transactions. */
rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
while (rseg != NULL) {
trx_rseg_t* prev_rseg = rseg;
rseg = UT_LIST_GET_NEXT(rseg_list, prev_rseg);
UT_LIST_REMOVE(rseg_list, trx_sys->rseg_list, prev_rseg);
trx_rseg_mem_free(prev_rseg);
}
view = UT_LIST_GET_FIRST(trx_sys->view_list);
while (view != NULL) {
read_view_t* prev_view = view;
view = UT_LIST_GET_NEXT(view_list, prev_view);
/* Views are allocated from the trx_sys->global_read_view_heap.
So, we simply remove the element here. */
UT_LIST_REMOVE(view_list, trx_sys->view_list, prev_view);
}
ut_a(UT_LIST_GET_LEN(trx_sys->trx_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->rseg_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
mem_free(trx_sys);
trx_sys = NULL;
mutex_exit(&kernel_mutex);
}
......@@ -1522,7 +1522,7 @@ trx_undo_mem_init_for_reuse(
/********************************************************************//**
Frees an undo log memory copy. */
static
UNIV_INTERN
void
trx_undo_mem_free(
/*==============*/
......
......@@ -31,14 +31,6 @@ Created 6/25/1996 Heikki Tuuri
#include "trx0trx.h"
/*********************************************************************//**
Closes a session, freeing the memory occupied by it. */
static
void
sess_close(
/*=======*/
sess_t* sess); /*!< in, own: session object */
/*********************************************************************//**
Opens a session.
@return own: session object */
......@@ -64,35 +56,16 @@ sess_open(void)
/*********************************************************************//**
Closes a session, freeing the memory occupied by it. */
static
UNIV_INTERN
void
sess_close(
/*=======*/
sess_t* sess) /*!< in, own: session object */
{
ut_ad(mutex_own(&kernel_mutex));
ut_ad(sess->trx == NULL);
mem_free(sess);
}
/*********************************************************************//**
Closes a session, freeing the memory occupied by it, if it is in a state
where it should be closed.
@return TRUE if closed */
UNIV_INTERN
ibool
sess_try_close(
/*===========*/
sess_t* sess) /*!< in, own: session object */
{
ut_ad(mutex_own(&kernel_mutex));
ut_ad(!mutex_own(&kernel_mutex));
if (UT_LIST_GET_LEN(sess->graphs) == 0) {
sess_close(sess);
ut_a(UT_LIST_GET_LEN(sess->graphs) == 0);
return(TRUE);
}
return(FALSE);
trx_free_for_background(sess->trx);
mem_free(sess);
}
......@@ -433,6 +433,8 @@ ut_free_all_mem(void)
" total allocated memory is %lu\n",
(ulong) ut_total_allocated_memory);
}
ut_mem_block_list_inited = FALSE;
}
#endif /* !UNIV_HOTBACKUP */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment