summaryrefslogtreecommitdiff
path: root/storage/innobase/fil/fil0fil.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/fil/fil0fil.c')
-rw-r--r--storage/innobase/fil/fil0fil.c135
1 files changed, 106 insertions, 29 deletions
diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c
index 710f0ac8603..196f4bd3f42 100644
--- a/storage/innobase/fil/fil0fil.c
+++ b/storage/innobase/fil/fil0fil.c
@@ -299,6 +299,34 @@ struct fil_system_struct {
initialized. */
static fil_system_t* fil_system = NULL;
+#ifdef UNIV_DEBUG
+/** Try fil_validate() every this many times */
+# define FIL_VALIDATE_SKIP 17
+
+/******************************************************************//**
+Checks the consistency of the tablespace cache some of the time.
+@return TRUE if ok or the check was skipped */
+static
+ibool
+fil_validate_skip(void)
+/*===================*/
+{
+ /** The fil_validate() call skip counter. Use a signed type
+ because of the race condition below. */
+ static int fil_validate_count = FIL_VALIDATE_SKIP;
+
+ /* There is a race condition below, but it does not matter,
+ because this call is only for heuristic purposes. We want to
+ reduce the call frequency of the costly fil_validate() check
+ in debug builds. */
+ if (--fil_validate_count > 0) {
+ return(TRUE);
+ }
+
+ fil_validate_count = FIL_VALIDATE_SKIP;
+ return(fil_validate());
+}
+#endif /* UNIV_DEBUG */
/********************************************************************//**
NOTE: you must call fil_mutex_enter_and_prepare_for_io() first!
@@ -339,14 +367,15 @@ fil_get_space_id_for_table(
/*******************************************************************//**
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. */
+flushes on the files.
+@return TRUE on success */
static
ibool
fil_space_free(
/*===========*/
- /* out: TRUE if success */
- ulint id, /* in: space id */
- ibool own_mutex);/* in: TRUE if own system->mutex */
+ ulint id, /* in: space id */
+ 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
blocks at the end of file are ignored: they are not taken into account when
@@ -827,7 +856,8 @@ fil_node_close_file(
ut_a(node->open);
ut_a(node->n_pending == 0);
ut_a(node->n_pending_flushes == 0);
- ut_a(node->modification_counter == node->flush_counter);
+ ut_a(node->modification_counter == node->flush_counter
+ || srv_fast_shutdown == 2);
ret = os_file_close(node->handle);
ut_a(ret);
@@ -1140,6 +1170,7 @@ try_again:
space = fil_space_get_by_name(name);
if (UNIV_LIKELY_NULL(space)) {
+ ibool success;
ulint namesake_id;
ut_print_timestamp(stderr);
@@ -1178,9 +1209,10 @@ try_again:
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;
}
@@ -1331,15 +1363,14 @@ fil_space_free(
/*===========*/
/* out: TRUE if success */
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* namespace;
fil_node_t* fil_node;
- if (!own_mutex) {
- mutex_enter(&fil_system->mutex);
- }
+ ut_ad(mutex_own(&fil_system->mutex));
space = fil_space_get_by_id(id);
@@ -1350,8 +1381,6 @@ fil_space_free(
" from the cache but\n"
"InnoDB: it is not there.\n", (ulong) id);
- mutex_exit(&fil_system->mutex);
-
return(FALSE);
}
@@ -1386,8 +1415,8 @@ fil_space_free(
ut_a(0 == UT_LIST_GET_LEN(space->chain));
- if (!own_mutex) {
- mutex_exit(&fil_system->mutex);
+ if (x_latched) {
+ rw_lock_x_unlock(&space->latch);
}
rw_lock_free(&(space->latch));
@@ -1633,25 +1662,27 @@ fil_close_all_files(void)
/*=====================*/
{
fil_space_t* space;
- fil_node_t* node;
mutex_enter(&fil_system->mutex);
space = UT_LIST_GET_FIRST(fil_system->space_list);
while (space != NULL) {
+ fil_node_t* node;
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) {
fil_node_close_file(node, fil_system);
}
- node = UT_LIST_GET_NEXT(chain, node);
}
+
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);
@@ -2271,6 +2302,19 @@ try_again:
path = mem_strdup(space->name);
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
/* Invalidate in the buffer pool all pages belonging to the
tablespace. Since we have set space->is_being_deleted = TRUE, readahead
@@ -2283,7 +2327,11 @@ try_again:
#endif
/* 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) {
success = os_file_delete(path);
@@ -2291,6 +2339,8 @@ try_again:
if (!success) {
success = os_file_delete_if_exists(path);
}
+ } else {
+ rw_lock_x_unlock(&space->latch);
}
if (success) {
@@ -2318,6 +2368,31 @@ try_again:
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
/*******************************************************************//**
Discards a single-table tablespace. The tablespace must be cached in the
@@ -4261,15 +4336,13 @@ fil_io(
#if (1 << UNIV_PAGE_SIZE_SHIFT) != UNIV_PAGE_SIZE
# error "(1 << UNIV_PAGE_SIZE_SHIFT) != UNIV_PAGE_SIZE"
#endif
- ut_ad(fil_validate());
+ ut_ad(fil_validate_skip());
#ifndef UNIV_HOTBACKUP
# ifndef UNIV_LOG_DEBUG
/* ibuf bitmap pages must be read in the sync aio mode: */
ut_ad(recv_no_ibuf_operations || (type == OS_FILE_WRITE)
|| !ibuf_bitmap_page(zip_size, block_offset)
|| sync || is_log);
- ut_ad(!ibuf_inside() || is_log || (type == OS_FILE_WRITE)
- || ibuf_page(space_id, zip_size, block_offset, NULL));
# endif /* UNIV_LOG_DEBUG */
if (sync) {
mode = OS_AIO_SYNC;
@@ -4420,7 +4493,7 @@ fil_io(
mutex_exit(&fil_system->mutex);
- ut_ad(fil_validate());
+ ut_ad(fil_validate_skip());
}
return(DB_SUCCESS);
@@ -4444,7 +4517,7 @@ fil_aio_wait(
void* message;
ulint type;
- ut_ad(fil_validate());
+ ut_ad(fil_validate_skip());
if (srv_use_native_aio) {
srv_set_io_thread_op_info(segment, "native aio handle");
@@ -4455,8 +4528,8 @@ fil_aio_wait(
ret = os_aio_linux_handle(segment, &fil_node,
&message, &type);
#else
- ret = 0; /* Eliminate compiler warning */
ut_error;
+ ret = 0; /* Eliminate compiler warning */
#endif
} else {
srv_set_io_thread_op_info(segment, "simulated aio handle");
@@ -4466,6 +4539,10 @@ fil_aio_wait(
}
ut_a(ret);
+ if (UNIV_UNLIKELY(fil_node == NULL)) {
+ ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
+ return;
+ }
srv_set_io_thread_op_info(segment, "complete io for fil node");
@@ -4475,7 +4552,7 @@ fil_aio_wait(
mutex_exit(&fil_system->mutex);
- ut_ad(fil_validate());
+ ut_ad(fil_validate_skip());
/* Do the i/o handling */
/* IMPORTANT: since i/o handling for reads will read also the insert
@@ -4788,7 +4865,7 @@ fil_page_get_type(
return(mach_read_from_2(page + FIL_PAGE_TYPE));
}
-/********************************************************************
+/****************************************************************//**
Initializes the tablespace memory cache. */
UNIV_INTERN
void