summaryrefslogtreecommitdiff
path: root/storage/xtradb/fil/fil0fil.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb/fil/fil0fil.c')
-rw-r--r--storage/xtradb/fil/fil0fil.c165
1 files changed, 134 insertions, 31 deletions
diff --git a/storage/xtradb/fil/fil0fil.c b/storage/xtradb/fil/fil0fil.c
index 4ab2c16d41f..397c4de4b6e 100644
--- a/storage/xtradb/fil/fil0fil.c
+++ b/storage/xtradb/fil/fil0fil.c
@@ -195,14 +195,16 @@ struct fil_space_struct {
requests on the file */
ibool stop_new_ops;
/*!< we set this TRUE when we start
- deleting a single-table tablespace */
- ibool is_being_deleted;
- /*!< this is set to TRUE when we start
- deleting a single-table tablespace and its
- file; when this flag is set no further i/o
- or flush requests can be placed on this space,
- though there may be such requests still being
- processed on this space */
+ deleting a single-table tablespace.
+ When this is set following new ops
+ are not allowed:
+ * read IO request
+ * ibuf merge
+ * file flush
+ Note that we can still possibly have
+ new write operations because we don't
+ check this flag when doing flush
+ batches. */
ulint purpose;/*!< FIL_TABLESPACE, FIL_LOG, or
FIL_ARCH_LOG */
UT_LIST_BASE_NODE_T(fil_node_t) chain;
@@ -865,7 +867,7 @@ fil_node_close_file(
ut_ad(node && system);
ut_ad(mutex_own(&(system->mutex)));
ut_a(node->open);
- ut_a(node->n_pending == 0 || node->space->is_being_deleted);
+ ut_a(node->n_pending == 0 || node->space->stop_new_ops);
ut_a(node->n_pending_flushes == 0);
#ifndef UNIV_HOTBACKUP
ut_a(node->modification_counter == node->flush_counter
@@ -1099,7 +1101,7 @@ fil_node_free(
ut_ad(node && system && space);
ut_ad(mutex_own(&(system->mutex)));
ut_a(node->magic_n == FIL_NODE_MAGIC_N);
- ut_a(node->n_pending == 0 || space->is_being_deleted);
+ ut_a(node->n_pending == 0 || space->stop_new_ops);
if (node->open) {
/* We fool the assertion in fil_node_close_file() to think
@@ -1297,7 +1299,6 @@ try_again:
space->stop_ios = FALSE;
space->stop_new_ops = FALSE;
- space->is_being_deleted = FALSE;
space->purpose = purpose;
space->size = 0;
space->flags = flags;
@@ -1478,7 +1479,7 @@ fil_space_get_size(
ut_ad(fil_system);
- fil_mutex_enter_and_prepare_for_io(id);
+ mutex_enter(&fil_system->mutex);
space = fil_space_get_by_id(id);
@@ -1493,6 +1494,23 @@ fil_space_get_size(
ut_a(1 == UT_LIST_GET_LEN(space->chain));
+ mutex_exit(&fil_system->mutex);
+
+ /* It is possible that the space gets evicted at this point
+ before the fil_mutex_enter_and_prepare_for_io() acquires
+ the fil_system->mutex. Check for this after completing the
+ call to fil_mutex_enter_and_prepare_for_io(). */
+ fil_mutex_enter_and_prepare_for_io(id);
+
+ /* We are still holding the fil_system->mutex. Check if
+ the space is still in memory cache. */
+ space = fil_space_get_by_id(id);
+
+ if (space == NULL) {
+ mutex_exit(&fil_system->mutex);
+ return(0);
+ }
+
node = UT_LIST_GET_FIRST(space->chain);
/* It must be a single-table tablespace and we have not opened
@@ -1530,7 +1548,7 @@ fil_space_get_flags(
return(0);
}
- fil_mutex_enter_and_prepare_for_io(id);
+ mutex_enter(&fil_system->mutex);
space = fil_space_get_by_id(id);
@@ -1545,6 +1563,23 @@ fil_space_get_flags(
ut_a(1 == UT_LIST_GET_LEN(space->chain));
+ mutex_exit(&fil_system->mutex);
+
+ /* It is possible that the space gets evicted at this point
+ before the fil_mutex_enter_and_prepare_for_io() acquires
+ the fil_system->mutex. Check for this after completing the
+ call to fil_mutex_enter_and_prepare_for_io(). */
+ fil_mutex_enter_and_prepare_for_io(id);
+
+ /* We are still holding the fil_system->mutex. Check if
+ the space is still in memory cache. */
+ space = fil_space_get_by_id(id);
+
+ if (space == NULL) {
+ mutex_exit(&fil_system->mutex);
+ return(0);
+ }
+
node = UT_LIST_GET_FIRST(space->chain);
/* It must be a single-table tablespace and we have not opened
@@ -2325,11 +2360,9 @@ try_again:
return(FALSE);
}
- ut_a(space);
+ ut_a(space->stop_new_ops);
ut_a(space->n_pending_ops == 0);
- space->is_being_deleted = TRUE;
-
ut_a(UT_LIST_GET_LEN(space->chain) == 1);
node = UT_LIST_GET_FIRST(space->chain);
@@ -2372,12 +2405,26 @@ try_again:
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
- or ibuf merge can no longer read more pages of this tablespace to the
- buffer pool. Thus we can clean the tablespace out of the buffer pool
- completely and permanently. The flag is_being_deleted also prevents
- fil_flush() from being applied to this tablespace. */
+ /* IMPORTANT: Because we have set space::stop_new_ops there
+ can't be any new ibuf merges, reads or flushes. We are here
+ because node::n_pending was zero above. However, it is still
+ possible to have pending read and write requests:
+
+ A read request can happen because the reader thread has
+ gone through the ::stop_new_ops check in buf_page_init_for_read()
+ before the flag was set and has not yet incremented ::n_pending
+ when we checked it above.
+
+ A write request can be issued any time because we don't check
+ the ::stop_new_ops flag when queueing a block for write.
+
+ We deal with pending write requests in the following function
+ where we'd minimally evict all dirty pages belonging to this
+ space from the flush_list. Not that if a block is IO-fixed
+ we'll wait for IO to complete.
+
+ To deal with potential read requests by checking the
+ ::stop_new_ops flag in fil_io() */
if (srv_lazy_drop_table) {
buf_LRU_mark_space_was_deleted(id);
@@ -2393,6 +2440,15 @@ try_again:
mutex_enter(&fil_system->mutex);
+ /* Double check the sanity of pending ops after reacquiring
+ the fil_system::mutex. */
+ if (fil_space_get_by_id(id)) {
+ ut_a(space->n_pending_ops == 0);
+ ut_a(UT_LIST_GET_LEN(space->chain) == 1);
+ node = UT_LIST_GET_FIRST(space->chain);
+ ut_a(node->n_pending == 0);
+ }
+
success = fil_space_free(id, TRUE);
mutex_exit(&fil_system->mutex);
@@ -2450,7 +2506,7 @@ fil_tablespace_is_being_deleted(
ut_a(space != NULL);
- is_being_deleted = space->is_being_deleted;
+ is_being_deleted = space->stop_new_ops;
mutex_exit(&fil_system->mutex);
@@ -2710,7 +2766,7 @@ retry:
mutex_exit(&fil_system->mutex);
#ifndef UNIV_HOTBACKUP
- if (success) {
+ if (success && !recv_recovery_on) {
mtr_t mtr;
mtr_start(&mtr);
@@ -4531,7 +4587,7 @@ fil_tablespace_deleted_or_being_deleted_in_mem(
space = fil_space_get_by_id(id);
- if (space == NULL || space->is_being_deleted) {
+ if (space == NULL || space->stop_new_ops) {
mutex_exit(&fil_system->mutex);
return(TRUE);
@@ -4809,6 +4865,24 @@ fil_extend_space_to_desired_size(
start_page_no = space->size;
file_start_page_no = space->size - node->size;
+#ifdef HAVE_POSIX_FALLOCATE
+ if (srv_use_posix_fallocate) {
+ offset_high = size_after_extend * page_size / (4ULL*1024*1024*1024);
+ offset_low = size_after_extend * page_size % (4ULL*1024*1024*1024);
+
+ mutex_exit(&fil_system->mutex);
+ success = os_file_set_size(node->name, node->handle,
+ offset_low, offset_high);
+ mutex_enter(&fil_system->mutex);
+ if (success) {
+ node->size += (size_after_extend - start_page_no);
+ space->size += (size_after_extend - start_page_no);
+ os_has_said_disk_full = FALSE;
+ }
+ goto complete_io;
+ }
+#endif
+
/* Extend at most 64 pages at a time */
buf_size = ut_min(64, size_after_extend - start_page_no) * page_size;
buf2 = mem_alloc(buf_size + page_size);
@@ -4865,6 +4939,10 @@ fil_extend_space_to_desired_size(
mem_free(buf2);
+#ifdef HAVE_POSIX_FALLOCATE
+complete_io:
+#endif
+
fil_node_complete_io(node, fil_system, OS_FILE_WRITE);
*actual_size = space->size;
@@ -5271,7 +5349,9 @@ _fil_io(
space = fil_space_get_by_id(space_id);
- if (!space) {
+ /* If we are deleting a tablespace we don't allow any read
+ operations on that. However, we do allow write operations. */
+ if (!space || (type == OS_FILE_READ && space->stop_new_ops)) {
mutex_exit(&fil_system->mutex);
ut_print_timestamp(stderr);
@@ -5362,8 +5442,8 @@ _fil_io(
/* Do aio */
- ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
- ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
+ ut_a(byte_offset % OS_MIN_LOG_BLOCK_SIZE == 0);
+ ut_a((len % OS_MIN_LOG_BLOCK_SIZE) == 0);
if (srv_pass_corrupt_table == 1 && space->is_corrupt) {
/* should ignore i/o for the crashed space */
@@ -5551,7 +5631,7 @@ fil_aio_wait(
&& ((buf_page_t*)message)->space_was_being_deleted) {
/* intended not to be uncompress read page */
- ut_a(buf_page_get_io_fix(message) == BUF_IO_WRITE
+ ut_a(buf_page_get_io_fix_unlocked(message) == BUF_IO_WRITE
|| !buf_page_get_zip_size(message)
|| buf_page_get_state(message) != BUF_BLOCK_FILE_PAGE);
@@ -5612,7 +5692,7 @@ fil_flush(
space = fil_space_get_by_id(space_id);
- if (!space || space->is_being_deleted) {
+ if (!space || space->stop_new_ops) {
mutex_exit(&fil_system->mutex);
return;
@@ -5743,7 +5823,7 @@ fil_flush_file_spaces(
space;
space = UT_LIST_GET_NEXT(unflushed_spaces, space)) {
- if (space->purpose == purpose && !space->is_being_deleted) {
+ if (space->purpose == purpose && !space->stop_new_ops) {
space_ids[n_space_ids++] = space->id;
}
@@ -5982,3 +6062,26 @@ fil_space_set_corrupt(
mutex_exit(&fil_system->mutex);
}
+/****************************************************************//**
+Generate redo logs for swapping two .ibd files */
+UNIV_INTERN
+void
+fil_mtr_rename_log(
+/*===============*/
+ ulint old_space_id, /*!< in: tablespace id of the old
+ table. */
+ const char* old_name, /*!< in: old table name */
+ ulint new_space_id, /*!< in: tablespace id of the new
+ table */
+ const char* new_name, /*!< in: new table name */
+ const char* tmp_name) /*!< in: temp table name used while
+ swapping */
+{
+ mtr_t mtr;
+ mtr_start(&mtr);
+ fil_op_write_log(MLOG_FILE_RENAME, old_space_id,
+ 0, 0, old_name, tmp_name, &mtr);
+ fil_op_write_log(MLOG_FILE_RENAME, new_space_id,
+ 0, 0, new_name, old_name, &mtr);
+ mtr_commit(&mtr);
+}