Commit 6bcad3dc authored by Sunny Bains's avatar Sunny Bains

Merge from mysql-5.1-innodb to mysql-5.5-innodb.

parents 9c8758b9 c64f9526
...@@ -339,14 +339,15 @@ fil_get_space_id_for_table( ...@@ -339,14 +339,15 @@ fil_get_space_id_for_table(
/*******************************************************************//** /*******************************************************************//**
Frees a space object from the tablespace memory cache. Closes the files in 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 the chain but does not delete them. There must not be any pending i/o's or
flushes on the files. */ flushes on the files.
@return TRUE on success */
static static
ibool ibool
fil_space_free( fil_space_free(
/*===========*/ /*===========*/
/* out: TRUE if success */
ulint id, /* in: space id */ ulint id, /* in: space id */
ibool own_mutex);/* in: TRUE if own system->mutex */ ibool x_latched); /* in: TRUE if caller has space->latch
in X mode */
/********************************************************************//** /********************************************************************//**
Reads data from a space to a buffer. Remember that the possible incomplete 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 blocks at the end of file are ignored: they are not taken into account when
...@@ -1140,6 +1141,7 @@ fil_space_create( ...@@ -1140,6 +1141,7 @@ fil_space_create(
space = fil_space_get_by_name(name); space = fil_space_get_by_name(name);
if (UNIV_LIKELY_NULL(space)) { if (UNIV_LIKELY_NULL(space)) {
ibool success;
ulint namesake_id; ulint namesake_id;
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
...@@ -1178,9 +1180,10 @@ fil_space_create( ...@@ -1178,9 +1180,10 @@ fil_space_create(
namesake_id = space->id; namesake_id = space->id;
mutex_exit(&fil_system->mutex); success = fil_space_free(namesake_id, FALSE);
ut_a(success);
fil_space_free(namesake_id, FALSE); mutex_exit(&fil_system->mutex);
goto try_again; goto try_again;
} }
...@@ -1331,15 +1334,14 @@ fil_space_free( ...@@ -1331,15 +1334,14 @@ fil_space_free(
/*===========*/ /*===========*/
/* out: TRUE if success */ /* out: TRUE if success */
ulint id, /* in: space id */ ulint id, /* in: space id */
ibool own_mutex) /* in: TRUE if own system->mutex */ ibool x_latched) /* in: TRUE if caller has space->latch
in X mode */
{ {
fil_space_t* space; fil_space_t* space;
fil_space_t* namespace; fil_space_t* namespace;
fil_node_t* fil_node; fil_node_t* fil_node;
if (!own_mutex) { ut_ad(mutex_own(&fil_system->mutex));
mutex_enter(&fil_system->mutex);
}
space = fil_space_get_by_id(id); space = fil_space_get_by_id(id);
...@@ -1350,8 +1352,6 @@ fil_space_free( ...@@ -1350,8 +1352,6 @@ fil_space_free(
" from the cache but\n" " from the cache but\n"
"InnoDB: it is not there.\n", (ulong) id); "InnoDB: it is not there.\n", (ulong) id);
mutex_exit(&fil_system->mutex);
return(FALSE); return(FALSE);
} }
...@@ -1386,8 +1386,8 @@ fil_space_free( ...@@ -1386,8 +1386,8 @@ fil_space_free(
ut_a(0 == UT_LIST_GET_LEN(space->chain)); ut_a(0 == UT_LIST_GET_LEN(space->chain));
if (!own_mutex) { if (x_latched) {
mutex_exit(&fil_system->mutex); rw_lock_x_unlock(&space->latch);
} }
rw_lock_free(&(space->latch)); rw_lock_free(&(space->latch));
...@@ -1633,25 +1633,27 @@ fil_close_all_files(void) ...@@ -1633,25 +1633,27 @@ fil_close_all_files(void)
/*=====================*/ /*=====================*/
{ {
fil_space_t* space; fil_space_t* space;
fil_node_t* node;
mutex_enter(&fil_system->mutex); mutex_enter(&fil_system->mutex);
space = UT_LIST_GET_FIRST(fil_system->space_list); space = UT_LIST_GET_FIRST(fil_system->space_list);
while (space != NULL) { while (space != NULL) {
fil_node_t* node;
fil_space_t* prev_space = space; fil_space_t* prev_space = space;
node = UT_LIST_GET_FIRST(space->chain); for (node = UT_LIST_GET_FIRST(space->chain);
node != NULL;
node = UT_LIST_GET_NEXT(chain, node)) {
while (node != NULL) {
if (node->open) { if (node->open) {
fil_node_close_file(node, fil_system); fil_node_close_file(node, fil_system);
} }
node = UT_LIST_GET_NEXT(chain, node);
} }
space = UT_LIST_GET_NEXT(space_list, space); space = UT_LIST_GET_NEXT(space_list, space);
fil_space_free(prev_space->id, TRUE);
fil_space_free(prev_space->id, FALSE);
} }
mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->mutex);
...@@ -2271,6 +2273,19 @@ fil_delete_tablespace( ...@@ -2271,6 +2273,19 @@ fil_delete_tablespace(
path = mem_strdup(space->name); path = mem_strdup(space->name);
mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->mutex);
/* Important: We rely on the data dictionary mutex to ensure
that a race is not possible here. It should serialize the tablespace
drop/free. We acquire an X latch only to avoid a race condition
when accessing the tablespace instance via:
fsp_get_available_space_in_free_extents().
There our main motivation is to reduce the contention on the
dictionary mutex. */
rw_lock_x_lock(&space->latch);
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/* Invalidate in the buffer pool all pages belonging to the /* Invalidate in the buffer pool all pages belonging to the
tablespace. Since we have set space->is_being_deleted = TRUE, readahead tablespace. Since we have set space->is_being_deleted = TRUE, readahead
...@@ -2283,7 +2298,11 @@ fil_delete_tablespace( ...@@ -2283,7 +2298,11 @@ fil_delete_tablespace(
#endif #endif
/* printf("Deleting tablespace %s id %lu\n", space->name, id); */ /* printf("Deleting tablespace %s id %lu\n", space->name, id); */
success = fil_space_free(id, FALSE); mutex_enter(&fil_system->mutex);
success = fil_space_free(id, TRUE);
mutex_exit(&fil_system->mutex);
if (success) { if (success) {
success = os_file_delete(path); success = os_file_delete(path);
...@@ -2291,6 +2310,8 @@ fil_delete_tablespace( ...@@ -2291,6 +2310,8 @@ fil_delete_tablespace(
if (!success) { if (!success) {
success = os_file_delete_if_exists(path); success = os_file_delete_if_exists(path);
} }
} else {
rw_lock_x_unlock(&space->latch);
} }
if (success) { if (success) {
...@@ -2318,6 +2339,31 @@ fil_delete_tablespace( ...@@ -2318,6 +2339,31 @@ fil_delete_tablespace(
return(FALSE); return(FALSE);
} }
/*******************************************************************//**
Returns TRUE if a single-table tablespace is being deleted.
@return TRUE if being deleted */
UNIV_INTERN
ibool
fil_tablespace_is_being_deleted(
/*============================*/
ulint id) /*!< in: space id */
{
fil_space_t* space;
ibool is_being_deleted;
mutex_enter(&fil_system->mutex);
space = fil_space_get_by_id(id);
ut_a(space != NULL);
is_being_deleted = space->is_being_deleted;
mutex_exit(&fil_system->mutex);
return(is_being_deleted);
}
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/*******************************************************************//** /*******************************************************************//**
Discards a single-table tablespace. The tablespace must be cached in the Discards a single-table tablespace. The tablespace must be cached in the
...@@ -4788,7 +4834,7 @@ fil_page_get_type( ...@@ -4788,7 +4834,7 @@ fil_page_get_type(
return(mach_read_from_2(page + FIL_PAGE_TYPE)); return(mach_read_from_2(page + FIL_PAGE_TYPE));
} }
/******************************************************************** /****************************************************************//**
Initializes the tablespace memory cache. */ Initializes the tablespace memory cache. */
UNIV_INTERN UNIV_INTERN
void void
......
...@@ -3097,13 +3097,63 @@ fsp_get_available_space_in_free_extents( ...@@ -3097,13 +3097,63 @@ fsp_get_available_space_in_free_extents(
ut_ad(!mutex_own(&kernel_mutex)); ut_ad(!mutex_own(&kernel_mutex));
/* The convoluted mutex acquire is to overcome latching order
issues: The problem is that the fil_mutex is at a lower level
than the tablespace latch and the buffer pool mutex. We have to
first prevent any operations on the file system by acquiring the
dictionary mutex. Then acquire the tablespace latch to obey the
latching order and then release the dictionary mutex. That way we
ensure that the tablespace instance can't be freed while we are
examining its contents (see fil_space_free()).
However, there is one further complication, we release the fil_mutex
when we need to invalidate the the pages in the buffer pool and we
reacquire the fil_mutex when deleting and freeing the tablespace
instance in fil0fil.c. Here we need to account for that situation
too. */
mutex_enter(&dict_sys->mutex);
/* At this stage there is no guarantee that the tablespace even
exists in the cache. */
if (fil_tablespace_deleted_or_being_deleted_in_mem(space, -1)) {
mutex_exit(&dict_sys->mutex);
return(ULLINT_UNDEFINED);
}
mtr_start(&mtr); mtr_start(&mtr);
latch = fil_space_get_latch(space, &flags); latch = fil_space_get_latch(space, &flags);
/* This should ensure that the tablespace instance can't be freed
by another thread. However, the tablespace pages can still be freed
from the buffer pool. We need to check for that again. */
zip_size = dict_table_flags_to_zip_size(flags); zip_size = dict_table_flags_to_zip_size(flags);
mtr_x_lock(latch, &mtr); mtr_x_lock(latch, &mtr);
mutex_exit(&dict_sys->mutex);
/* At this point it is possible for the tablespace to be deleted and
its pages removed from the buffer pool. We need to check for that
situation. However, the tablespace instance can't be deleted because
our latching above should ensure that. */
if (fil_tablespace_is_being_deleted(space)) {
mtr_commit(&mtr);
return(ULLINT_UNDEFINED);
}
/* From here on even if the user has dropped the tablespace, the
pages _must_ still exist in the buffer pool and the tablespace
instance _must_ be in the file system hash table. */
space_header = fsp_get_space_header(space, zip_size, &mtr); space_header = fsp_get_space_header(space, zip_size, &mtr);
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr); size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
......
...@@ -7825,19 +7825,12 @@ ha_innobase::info_low( ...@@ -7825,19 +7825,12 @@ ha_innobase::info_low(
innodb_crash_recovery is set to a high value. */ innodb_crash_recovery is set to a high value. */
stats.delete_length = 0; stats.delete_length = 0;
} else { } else {
/* lock the data dictionary to avoid races with ullint avail_space;
ibd_file_missing and tablespace_discarded */
row_mysql_lock_data_dictionary(prebuilt->trx);
/* ib_table->space must be an existent tablespace */
if (!ib_table->ibd_file_missing
&& !ib_table->tablespace_discarded) {
stats.delete_length = avail_space = fsp_get_available_space_in_free_extents(
fsp_get_available_space_in_free_extents( ib_table->space);
ib_table->space) * 1024;
} else {
if (avail_space == ULLINT_UNDEFINED) {
THD* thd; THD* thd;
thd = ha_thd(); thd = ha_thd();
...@@ -7854,9 +7847,9 @@ ha_innobase::info_low( ...@@ -7854,9 +7847,9 @@ ha_innobase::info_low(
ib_table->name); ib_table->name);
stats.delete_length = 0; stats.delete_length = 0;
} else {
stats.delete_length = avail_space * 1024;
} }
row_mysql_unlock_data_dictionary(prebuilt->trx);
} }
stats.check_time = 0; stats.check_time = 0;
......
...@@ -717,6 +717,14 @@ fil_page_get_type( ...@@ -717,6 +717,14 @@ fil_page_get_type(
/*==============*/ /*==============*/
const byte* page); /*!< in: file page */ const byte* page); /*!< in: file page */
/*******************************************************************//**
Returns TRUE if a single-table tablespace is being deleted.
@return TRUE if being deleted */
UNIV_INTERN
ibool
fil_tablespace_is_being_deleted(
/*============================*/
ulint id); /*!< in: space id */
typedef struct fil_space_struct fil_space_t; typedef struct fil_space_struct fil_space_t;
......
...@@ -374,6 +374,9 @@ typedef unsigned long long int ullint; ...@@ -374,6 +374,9 @@ typedef unsigned long long int ullint;
/** The generic InnoDB system object identifier data type */ /** The generic InnoDB system object identifier data type */
typedef ib_uint64_t ib_id_t; typedef ib_uint64_t ib_id_t;
/* The 'undefined' value for a ullint */
#define ULLINT_UNDEFINED ((ullint)(-1))
/* This 'ibool' type is used within Innobase. Remember that different included /* This 'ibool' type is used within Innobase. Remember that different included
headers may define 'bool' differently. Do not assume that 'bool' is a ulint! */ headers may define 'bool' differently. Do not assume that 'bool' is a ulint! */
#define ibool ulint #define ibool ulint
......
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