summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorGeorgi Kodinov <Georgi.Kodinov@Oracle.com>2012-04-10 14:23:17 +0300
committerGeorgi Kodinov <Georgi.Kodinov@Oracle.com>2012-04-10 14:23:17 +0300
commit7fa28bcf568f6873346a4c222bb95a60556876e9 (patch)
tree2238a3d5fa70dcbe2a1e176ceef8ce7394842463 /storage
parent1d860ec51a3414259d349efba3dec68c295c79a2 (diff)
parent20459a71e3e0d5d6607bde122f27f752de053dd4 (diff)
downloadmariadb-git-7fa28bcf568f6873346a4c222bb95a60556876e9.tar.gz
merge mysql-5.5->mysql-5.5-security
Diffstat (limited to 'storage')
-rw-r--r--storage/innobase/buf/buf0lru.c414
-rw-r--r--storage/innobase/fil/fil0fil.c13
-rw-r--r--storage/innobase/handler/ha_innodb.cc97
-rw-r--r--storage/innobase/include/buf0lru.h11
-rw-r--r--storage/innobase/include/buf0types.h9
-rw-r--r--storage/innobase/include/fil0fil.h4
-rw-r--r--storage/innobase/include/trx0purge.h4
-rw-r--r--storage/innobase/row/row0mysql.c5
-rw-r--r--storage/innobase/trx/trx0purge.c2
-rw-r--r--storage/perfschema/pfs_instr.cc49
10 files changed, 455 insertions, 153 deletions
diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c
index 15b0ad40aaa..8e787fdba17 100644
--- a/storage/innobase/buf/buf0lru.c
+++ b/storage/innobase/buf/buf0lru.c
@@ -335,39 +335,275 @@ next_page:
}
/******************************************************************//**
+While flushing (or removing dirty) pages from a tablespace we don't
+want to hog the CPU and resources. Release the buffer pool and block
+mutex and try to force a context switch. Then reacquire the same mutexes.
+The current page is "fixed" before the release of the mutexes and then
+"unfixed" again once we have reacquired the mutexes. */
+static
+void
+buf_flush_yield(
+/*============*/
+ buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */
+ buf_page_t* bpage) /*!< in/out: current page */
+{
+ mutex_t* block_mutex;
+
+ ut_ad(buf_pool_mutex_own(buf_pool));
+ ut_ad(buf_page_in_file(bpage));
+
+ block_mutex = buf_page_get_mutex(bpage);
+
+ mutex_enter(block_mutex);
+ /* "Fix" the block so that the position cannot be
+ changed after we release the buffer pool and
+ block mutexes. */
+ buf_page_set_sticky(bpage);
+
+ /* Now it is safe to release the buf_pool->mutex. */
+ buf_pool_mutex_exit(buf_pool);
+
+ mutex_exit(block_mutex);
+ /* Try and force a context switch. */
+ os_thread_yield();
+
+ buf_pool_mutex_enter(buf_pool);
+
+ mutex_enter(block_mutex);
+ /* "Unfix" the block now that we have both the
+ buffer pool and block mutex again. */
+ buf_page_unset_sticky(bpage);
+ mutex_exit(block_mutex);
+}
+
+/******************************************************************//**
+If we have hogged the resources for too long then release the buffer
+pool and flush list mutex and do a thread yield. Set the current page
+to "sticky" so that it is not relocated during the yield.
+@return TRUE if yielded */
+static
+ibool
+buf_flush_try_yield(
+/*================*/
+ buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */
+ buf_page_t* bpage, /*!< in/out: bpage to remove */
+ ulint processed) /*!< in: number of pages processed */
+{
+ /* Every BUF_LRU_DROP_SEARCH_SIZE iterations in the
+ loop we release buf_pool->mutex to let other threads
+ do their job but only if the block is not IO fixed. This
+ ensures that the block stays in its position in the
+ flush_list. */
+
+ if (bpage != NULL
+ && processed >= BUF_LRU_DROP_SEARCH_SIZE
+ && buf_page_get_io_fix(bpage) == BUF_IO_NONE) {
+
+ buf_flush_list_mutex_exit(buf_pool);
+
+ /* Release the buffer pool and block mutex
+ to give the other threads a go. */
+
+ buf_flush_yield(buf_pool, bpage);
+
+ buf_flush_list_mutex_enter(buf_pool);
+
+ /* Should not have been removed from the flush
+ list during the yield. However, this check is
+ not sufficient to catch a remove -> add. */
+
+ ut_ad(bpage->in_flush_list);
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/******************************************************************//**
+Removes a single page from a given tablespace inside a specific
+buffer pool instance.
+@return TRUE if page was removed. */
+static
+ibool
+buf_flush_or_remove_page(
+/*=====================*/
+ buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */
+ buf_page_t* bpage) /*!< in/out: bpage to remove */
+{
+ mutex_t* block_mutex;
+ ibool processed = FALSE;
+
+ ut_ad(buf_pool_mutex_own(buf_pool));
+ ut_ad(buf_flush_list_mutex_own(buf_pool));
+
+ block_mutex = buf_page_get_mutex(bpage);
+
+ /* bpage->space and bpage->io_fix are protected by
+ buf_pool->mutex and block_mutex. It is safe to check
+ them while holding buf_pool->mutex only. */
+
+ if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
+
+ /* We cannot remove this page during this scan
+ yet; maybe the system is currently reading it
+ in, or flushing the modifications to the file */
+
+ } else {
+
+ /* We have to release the flush_list_mutex to obey the
+ latching order. We are however guaranteed that the page
+ will stay in the flush_list because buf_flush_remove()
+ needs buf_pool->mutex as well (for the non-flush case). */
+
+ buf_flush_list_mutex_exit(buf_pool);
+
+ mutex_enter(block_mutex);
+
+ ut_ad(bpage->oldest_modification != 0);
+
+ if (bpage->buf_fix_count == 0) {
+
+ buf_flush_remove(bpage);
+
+ processed = TRUE;
+ }
+
+ mutex_exit(block_mutex);
+
+ buf_flush_list_mutex_enter(buf_pool);
+ }
+
+ ut_ad(!mutex_own(block_mutex));
+
+ return(processed);
+}
+
+/******************************************************************//**
Remove all dirty pages belonging to a given tablespace inside a specific
buffer pool instance when we are deleting the data file(s) of that
tablespace. The pages still remain a part of LRU and are evicted from
-the list as they age towards the tail of the LRU. */
+the list as they age towards the tail of the LRU.
+@return TRUE if all freed. */
+static
+ibool
+buf_flush_or_remove_pages(
+/*======================*/
+ buf_pool_t* buf_pool, /*!< buffer pool instance */
+ ulint id) /*!< in: target space id for which
+ to remove or flush pages */
+{
+ buf_page_t* prev;
+ buf_page_t* bpage;
+ ulint processed = 0;
+ ibool all_freed = TRUE;
+
+ buf_flush_list_mutex_enter(buf_pool);
+
+ for (bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
+ bpage != NULL;
+ bpage = prev) {
+
+ ut_a(buf_page_in_file(bpage));
+ ut_ad(bpage->in_flush_list);
+
+ /* Save the previous link because once we free the
+ page we can't rely on the links. */
+
+ prev = UT_LIST_GET_PREV(list, bpage);
+
+ if (buf_page_get_space(bpage) != id) {
+
+ /* Skip this block, as it does not belong to
+ the target space. */
+
+ } else if (!buf_flush_or_remove_page(buf_pool, bpage)) {
+
+ /* Remove was unsuccessful, we have to try again
+ by scanning the entire list from the end. */
+
+ all_freed = FALSE;
+ }
+
+ ++processed;
+
+ /* Yield if we have hogged the CPU and mutexes for too long. */
+ if (buf_flush_try_yield(buf_pool, prev, processed)) {
+
+ /* Reset the batch size counter if we had to yield. */
+
+ processed = 0;
+ }
+
+ }
+
+ buf_flush_list_mutex_exit(buf_pool);
+
+ return(all_freed);
+}
+
+/******************************************************************//**
+Remove or flush all the dirty pages that belong to a given tablespace
+inside a specific buffer pool instance. The pages will remain in the LRU
+list and will be evicted from the LRU list as they age and move towards
+the tail of the LRU list. */
static
void
-buf_LRU_remove_dirty_pages_for_tablespace(
-/*======================================*/
+buf_flush_dirty_pages(
+/*==================*/
+ buf_pool_t* buf_pool, /*!< buffer pool instance */
+ ulint id) /*!< in: space id */
+{
+ ibool all_freed;
+
+ do {
+ buf_pool_mutex_enter(buf_pool);
+
+ all_freed = buf_flush_or_remove_pages(buf_pool, id);
+
+ buf_pool_mutex_exit(buf_pool);
+
+ ut_ad(buf_flush_validate(buf_pool));
+
+ if (!all_freed) {
+ os_thread_sleep(20000);
+ }
+
+ } while (!all_freed);
+}
+
+/******************************************************************//**
+Remove all pages that belong to a given tablespace inside a specific
+buffer pool instance when we are DISCARDing the tablespace. */
+static
+void
+buf_LRU_remove_all_pages(
+/*=====================*/
buf_pool_t* buf_pool, /*!< buffer pool instance */
ulint id) /*!< in: space id */
{
buf_page_t* bpage;
ibool all_freed;
- ulint i;
scan_again:
buf_pool_mutex_enter(buf_pool);
- buf_flush_list_mutex_enter(buf_pool);
all_freed = TRUE;
- for (bpage = UT_LIST_GET_LAST(buf_pool->flush_list), i = 0;
- bpage != NULL; ++i) {
+ for (bpage = UT_LIST_GET_LAST(buf_pool->LRU);
+ bpage != NULL;
+ /* No op */) {
buf_page_t* prev_bpage;
mutex_t* block_mutex = NULL;
ut_a(buf_page_in_file(bpage));
+ ut_ad(bpage->in_LRU_list);
- prev_bpage = UT_LIST_GET_PREV(list, bpage);
+ prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
/* bpage->space and bpage->io_fix are protected by
- buf_pool->mutex and block_mutex. It is safe to check
+ buf_pool->mutex and the block_mutex. It is safe to check
them while holding buf_pool->mutex only. */
if (buf_page_get_space(bpage) != id) {
@@ -381,83 +617,87 @@ scan_again:
all_freed = FALSE;
goto next_page;
- }
+ } else {
- /* We have to release the flush_list_mutex to obey the
- latching order. We are however guaranteed that the page
- will stay in the flush_list because buf_flush_remove()
- needs buf_pool->mutex as well. */
- buf_flush_list_mutex_exit(buf_pool);
- block_mutex = buf_page_get_mutex(bpage);
- mutex_enter(block_mutex);
+ block_mutex = buf_page_get_mutex(bpage);
+ mutex_enter(block_mutex);
- if (bpage->buf_fix_count > 0) {
- mutex_exit(block_mutex);
- buf_flush_list_mutex_enter(buf_pool);
+ if (bpage->buf_fix_count > 0) {
- /* We cannot remove this page during
- this scan yet; maybe the system is
- currently reading it in, or flushing
- the modifications to the file */
+ mutex_exit(block_mutex);
- all_freed = FALSE;
- goto next_page;
- }
+ /* We cannot remove this page during
+ this scan yet; maybe the system is
+ currently reading it in, or flushing
+ the modifications to the file */
- ut_ad(bpage->oldest_modification != 0);
+ all_freed = FALSE;
- buf_flush_remove(bpage);
+ goto next_page;
+ }
+ }
- mutex_exit(block_mutex);
- buf_flush_list_mutex_enter(buf_pool);
-next_page:
- bpage = prev_bpage;
+ ut_ad(mutex_own(block_mutex));
- if (!bpage) {
- break;
+#ifdef UNIV_DEBUG
+ if (buf_debug_prints) {
+ fprintf(stderr,
+ "Dropping space %lu page %lu\n",
+ (ulong) buf_page_get_space(bpage),
+ (ulong) buf_page_get_page_no(bpage));
}
+#endif
+ if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
+ /* Do nothing, because the adaptive hash index
+ covers uncompressed pages only. */
+ } else if (((buf_block_t*) bpage)->index) {
+ ulint page_no;
+ ulint zip_size;
- /* Every BUF_LRU_DROP_SEARCH_SIZE iterations in the
- loop we release buf_pool->mutex to let other threads
- do their job. */
- if (i < BUF_LRU_DROP_SEARCH_SIZE) {
- continue;
+ buf_pool_mutex_exit(buf_pool);
+
+ zip_size = buf_page_get_zip_size(bpage);
+ page_no = buf_page_get_page_no(bpage);
+
+ mutex_exit(block_mutex);
+
+ /* Note that the following call will acquire
+ and release block->lock X-latch. */
+
+ btr_search_drop_page_hash_when_freed(
+ id, zip_size, page_no);
+
+ goto scan_again;
}
- /* We IO-fix the block to make sure that the block
- stays in its position in the flush_list. */
- if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
- /* Block is already IO-fixed. We don't
- want to change the value. Lets leave
- this block alone. */
- continue;
+ if (bpage->oldest_modification != 0) {
+ buf_flush_remove(bpage);
}
- buf_flush_list_mutex_exit(buf_pool);
- block_mutex = buf_page_get_mutex(bpage);
- mutex_enter(block_mutex);
- buf_page_set_sticky(bpage);
- mutex_exit(block_mutex);
+ ut_ad(!bpage->in_flush_list);
- /* Now it is safe to release the buf_pool->mutex. */
- buf_pool_mutex_exit(buf_pool);
- os_thread_yield();
- buf_pool_mutex_enter(buf_pool);
+ /* Remove from the LRU list. */
- mutex_enter(block_mutex);
- buf_page_unset_sticky(bpage);
- mutex_exit(block_mutex);
+ if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
+ != BUF_BLOCK_ZIP_FREE) {
- buf_flush_list_mutex_enter(buf_pool);
- ut_ad(bpage->in_flush_list);
+ buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
+ mutex_exit(block_mutex);
+
+ } else {
+ /* The block_mutex should have been released
+ by buf_LRU_block_remove_hashed_page() when it
+ returns BUF_BLOCK_ZIP_FREE. */
+ ut_ad(block_mutex == &buf_pool->zip_mutex);
+ }
- i = 0;
+ ut_ad(!mutex_own(block_mutex));
+
+next_page:
+ bpage = prev_bpage;
}
buf_pool_mutex_exit(buf_pool);
- buf_flush_list_mutex_exit(buf_pool);
-
- ut_ad(buf_flush_validate(buf_pool));
if (!all_freed) {
os_thread_sleep(20000);
@@ -467,28 +707,46 @@ next_page:
}
/******************************************************************//**
-Invalidates all pages belonging to a given tablespace when we are deleting
-the data file(s) of that tablespace. */
+Removes all pages belonging to a given tablespace. */
UNIV_INTERN
void
-buf_LRU_invalidate_tablespace(
+buf_LRU_flush_or_remove_pages(
/*==========================*/
- ulint id) /*!< in: space id */
+ ulint id, /*!< in: space id */
+ enum buf_remove_t buf_remove)/*!< in: remove or flush
+ strategy */
{
- ulint i;
+ ulint i;
- /* Before we attempt to drop pages one by one we first
- attempt to drop page hash index entries in batches to make
- it more efficient. The batching attempt is a best effort
- attempt and does not guarantee that all pages hash entries
- will be dropped. We get rid of remaining page hash entries
- one by one below. */
for (i = 0; i < srv_buf_pool_instances; i++) {
buf_pool_t* buf_pool;
buf_pool = buf_pool_from_array(i);
- buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
- buf_LRU_remove_dirty_pages_for_tablespace(buf_pool, id);
+
+ switch (buf_remove) {
+ case BUF_REMOVE_ALL_NO_WRITE:
+ /* A DISCARD tablespace case. Remove AHI entries
+ and evict all pages from LRU. */
+
+ /* Before we attempt to drop pages hash entries
+ one by one we first attempt to drop page hash
+ index entries in batches to make it more
+ efficient. The batching attempt is a best effort
+ attempt and does not guarantee that all pages
+ hash entries will be dropped. We get rid of
+ remaining page hash entries one by one below. */
+ buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
+ buf_LRU_remove_all_pages(buf_pool, id);
+ break;
+
+ case BUF_REMOVE_FLUSH_NO_WRITE:
+ /* A DROP table case. AHI entries are already
+ removed. No need to evict all pages from LRU
+ list. Just evict pages from flush list without
+ writing. */
+ buf_flush_dirty_pages(buf_pool, id);
+ break;
+ }
}
}
diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c
index d8ad5c4f432..2390333b393 100644
--- a/storage/innobase/fil/fil0fil.c
+++ b/storage/innobase/fil/fil0fil.c
@@ -2159,7 +2159,7 @@ fil_op_log_parse_or_replay(
switch (type) {
case MLOG_FILE_DELETE:
if (fil_tablespace_exists_in_mem(space_id)) {
- ut_a(fil_delete_tablespace(space_id));
+ ut_a(fil_delete_tablespace(space_id, TRUE));
}
break;
@@ -2229,7 +2229,9 @@ UNIV_INTERN
ibool
fil_delete_tablespace(
/*==================*/
- ulint id) /*!< in: space id */
+ ulint id, /*!< in: space id */
+ ibool evict_all) /*!< in: TRUE if we want all pages
+ evicted from LRU. */
{
ibool success;
fil_space_t* space;
@@ -2351,7 +2353,10 @@ try_again:
completely and permanently. The flag is_being_deleted also prevents
fil_flush() from being applied to this tablespace. */
- buf_LRU_invalidate_tablespace(id);
+ buf_LRU_flush_or_remove_pages(
+ id, evict_all
+ ? BUF_REMOVE_ALL_NO_WRITE
+ : BUF_REMOVE_FLUSH_NO_WRITE);
#endif
/* printf("Deleting tablespace %s id %lu\n", space->name, id); */
@@ -2439,7 +2444,7 @@ fil_discard_tablespace(
{
ibool success;
- success = fil_delete_tablespace(id);
+ success = fil_delete_tablespace(id, TRUE);
if (!success) {
fprintf(stderr,
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 9625fdab8e9..dcfac0e0205 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -1450,70 +1450,87 @@ values we want to reserve for multi-value inserts e.g.,
INSERT INTO T VALUES(), (), ();
-innobase_next_autoinc() will be called with increment set to
-n * 3 where autoinc_lock_mode != TRADITIONAL because we want
-to reserve 3 values for the multi-value INSERT above.
+innobase_next_autoinc() will be called with increment set to 3 where
+autoinc_lock_mode != TRADITIONAL because we want to reserve 3 values for
+the multi-value INSERT above.
@return the next value */
static
ulonglong
innobase_next_autoinc(
/*==================*/
ulonglong current, /*!< in: Current value */
- ulonglong increment, /*!< in: increment current by */
+ ulonglong need, /*!< in: count of values needed */
+ ulonglong step, /*!< in: AUTOINC increment step */
ulonglong offset, /*!< in: AUTOINC offset */
ulonglong max_value) /*!< in: max value for type */
{
ulonglong next_value;
+ ulonglong block = need * step;
/* Should never be 0. */
- ut_a(increment > 0);
+ ut_a(need > 0);
+ ut_a(block > 0);
+ ut_a(max_value > 0);
+
+ /* Current value should never be greater than the maximum. */
+ ut_a(current <= max_value);
/* According to MySQL documentation, if the offset is greater than
- the increment then the offset is ignored. */
- if (offset > increment) {
+ the step then the offset is ignored. */
+ if (offset > block) {
offset = 0;
}
- if (max_value <= current) {
+ /* Check for overflow. */
+ if (block >= max_value
+ || offset > max_value
+ || current == max_value
+ || max_value - offset <= offset) {
+
next_value = max_value;
- } else if (offset <= 1) {
- /* Offset 0 and 1 are the same, because there must be at
- least one node in the system. */
- if (max_value - current <= increment) {
+ } else {
+ ut_a(max_value > current);
+
+ ulonglong free = max_value - current;
+
+ if (free < offset || free - offset <= block) {
next_value = max_value;
} else {
- next_value = current + increment;
+ next_value = 0;
}
- } else if (max_value > current) {
+ }
+
+ if (next_value == 0) {
+ ulonglong next;
+
if (current > offset) {
- next_value = ((current - offset) / increment) + 1;
+ next = (current - offset) / step;
} else {
- next_value = ((offset - current) / increment) + 1;
+ next = (offset - current) / step;
}
- ut_a(increment > 0);
- ut_a(next_value > 0);
-
+ ut_a(max_value > next);
+ next_value = next * step;
/* Check for multiplication overflow. */
- if (increment > (max_value / next_value)) {
+ ut_a(next_value >= next);
+ ut_a(max_value > next_value);
- next_value = max_value;
- } else {
- next_value *= increment;
+ /* Check for overflow */
+ if (max_value - next_value >= block) {
- ut_a(max_value >= next_value);
+ next_value += block;
- /* Check for overflow. */
- if (max_value - next_value <= offset) {
- next_value = max_value;
- } else {
+ if (max_value - next_value >= offset) {
next_value += offset;
+ } else {
+ next_value = max_value;
}
+ } else {
+ next_value = max_value;
}
- } else {
- next_value = max_value;
}
+ ut_a(next_value != 0);
ut_a(next_value <= max_value);
return(next_value);
@@ -3749,7 +3766,7 @@ ha_innobase::innobase_initialize_autoinc()
nor the offset, so use a default increment of 1. */
auto_inc = innobase_next_autoinc(
- read_auto_inc, 1, 1, col_max_value);
+ read_auto_inc, 1, 1, 0, col_max_value);
break;
}
@@ -5249,15 +5266,16 @@ set_max_autoinc:
if (auto_inc <= col_max_value) {
ut_a(prebuilt->autoinc_increment > 0);
- ulonglong need;
ulonglong offset;
+ ulonglong increment;
offset = prebuilt->autoinc_offset;
- need = prebuilt->autoinc_increment;
+ increment = prebuilt->autoinc_increment;
auto_inc = innobase_next_autoinc(
auto_inc,
- need, offset, col_max_value);
+ 1, increment, offset,
+ col_max_value);
err = innobase_set_max_autoinc(
auto_inc);
@@ -5525,14 +5543,14 @@ ha_innobase::update_row(
if (auto_inc <= col_max_value && auto_inc != 0) {
- ulonglong need;
ulonglong offset;
+ ulonglong increment;
offset = prebuilt->autoinc_offset;
- need = prebuilt->autoinc_increment;
+ increment = prebuilt->autoinc_increment;
auto_inc = innobase_next_autoinc(
- auto_inc, need, offset, col_max_value);
+ auto_inc, 1, increment, offset, col_max_value);
error = innobase_set_max_autoinc(auto_inc);
}
@@ -10145,16 +10163,15 @@ ha_innobase::get_auto_increment(
/* With old style AUTOINC locking we only update the table's
AUTOINC counter after attempting to insert the row. */
if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
- ulonglong need;
ulonglong current;
ulonglong next_value;
current = *first_value > col_max_value ? autoinc : *first_value;
- need = *nb_reserved_values * increment;
/* Compute the last value in the interval */
next_value = innobase_next_autoinc(
- current, need, offset, col_max_value);
+ current, *nb_reserved_values, increment, offset,
+ col_max_value);
prebuilt->autoinc_last_value = next_value;
diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h
index eb40621abbe..9ecb9de2afe 100644
--- a/storage/innobase/include/buf0lru.h
+++ b/storage/innobase/include/buf0lru.h
@@ -64,15 +64,14 @@ These are low-level functions
#define BUF_LRU_FREE_SEARCH_LEN(b) (5 + 2 * BUF_READ_AHEAD_AREA(b))
/******************************************************************//**
-Invalidates all pages belonging to a given tablespace when we are deleting
-the data file(s) of that tablespace. A PROBLEM: if readahead is being started,
-what guarantees that it will not try to read in pages after this operation has
-completed? */
+Removes all pages belonging to a given tablespace. */
UNIV_INTERN
void
-buf_LRU_invalidate_tablespace(
+buf_LRU_flush_or_remove_pages(
/*==========================*/
- ulint id); /*!< in: space id */
+ ulint id, /*!< in: space id */
+ enum buf_remove_t buf_remove);/*!< in: remove or flush
+ strategy */
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
/********************************************************************//**
Insert a compressed block into buf_pool->zip_clean in the LRU order. */
diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h
index 12b9e22f673..2916f39f3fe 100644
--- a/storage/innobase/include/buf0types.h
+++ b/storage/innobase/include/buf0types.h
@@ -63,6 +63,15 @@ enum buf_io_fix {
the flush_list */
};
+/** Algorithm to remove the pages for a tablespace from the buffer pool.
+@See buf_LRU_flush_or_remove_pages(). */
+enum buf_remove_t {
+ BUF_REMOVE_ALL_NO_WRITE, /*!< Remove all pages from the buffer
+ pool, don't write or sync to disk */
+ BUF_REMOVE_FLUSH_NO_WRITE /*!< Remove only, from the flush list,
+ don't write or sync to disk */
+};
+
/** Parameters of binary buddy system for compressed pages (buf0buddy.h) */
/* @{ */
#define BUF_BUDDY_LOW_SHIFT PAGE_ZIP_MIN_SIZE_SHIFT
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index bd9d6e6ebba..610bd4b0e5c 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -397,7 +397,9 @@ UNIV_INTERN
ibool
fil_delete_tablespace(
/*==================*/
- ulint id); /*!< in: space id */
+ ulint id, /*!< in: space id */
+ ibool evict_all); /*!< in: TRUE if we want all pages
+ evicted from LRU. */
#ifndef UNIV_HOTBACKUP
/*******************************************************************//**
Discards a single-table tablespace. The tablespace must be cached in the
diff --git a/storage/innobase/include/trx0purge.h b/storage/innobase/include/trx0purge.h
index 0b83a76cab7..2bd9e64476b 100644
--- a/storage/innobase/include/trx0purge.h
+++ b/storage/innobase/include/trx0purge.h
@@ -143,9 +143,9 @@ struct trx_purge_struct{
obtaining an s-latch here. */
read_view_t* view; /*!< The purge will not remove undo logs
which are >= this view (purge view) */
- ulint n_pages_handled;/*!< Approximate number of undo log
+ ulonglong n_pages_handled;/*!< Approximate number of undo log
pages processed in purge */
- ulint handle_limit; /*!< Target of how many pages to get
+ ulonglong handle_limit; /*!< Target of how many pages to get
processed in the current purge */
/*------------------------------*/
/* The following two fields form the 'purge pointer' which advances
diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
index 73666d59742..20e8c13ea70 100644
--- a/storage/innobase/row/row0mysql.c
+++ b/storage/innobase/row/row0mysql.c
@@ -1999,7 +1999,8 @@ err_exit:
case DB_TOO_MANY_CONCURRENT_TRXS:
/* We already have .ibd file here. it should be deleted. */
- if (table->space && !fil_delete_tablespace(table->space)) {
+ if (table->space && !fil_delete_tablespace(table->space,
+ FALSE)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: not able to"
@@ -3438,7 +3439,7 @@ check_next_foreign:
"InnoDB: of table ");
ut_print_name(stderr, trx, TRUE, name);
fprintf(stderr, ".\n");
- } else if (!fil_delete_tablespace(space_id)) {
+ } else if (!fil_delete_tablespace(space_id, FALSE)) {
fprintf(stderr,
"InnoDB: We removed now the InnoDB"
" internal data dictionary entry\n"
diff --git a/storage/innobase/trx/trx0purge.c b/storage/innobase/trx/trx0purge.c
index 2370d3deab0..96f01ea81b5 100644
--- a/storage/innobase/trx/trx0purge.c
+++ b/storage/innobase/trx/trx0purge.c
@@ -1202,7 +1202,7 @@ trx_purge(
(ulong) purge_sys->n_pages_handled);
}
- return(purge_sys->n_pages_handled - old_pages_handled);
+ return((ulint) (purge_sys->n_pages_handled - old_pages_handled));
}
/******************************************************************//**
diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc
index a877ea61198..c83628cb7cd 100644
--- a/storage/perfschema/pfs_instr.cc
+++ b/storage/perfschema/pfs_instr.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -802,6 +802,22 @@ void destroy_thread(PFS_thread *pfs)
}
/**
+ Get the hash pins for @filename_hash.
+ @param thread The running thread.
+ @returns The LF_HASH pins for the thread.
+*/
+LF_PINS* get_filename_hash_pins(PFS_thread *thread)
+{
+ if (unlikely(thread->m_filename_hash_pins == NULL))
+ {
+ if (! filename_hash_inited)
+ return NULL;
+ thread->m_filename_hash_pins= lf_hash_get_pins(&filename_hash);
+ }
+ return thread->m_filename_hash_pins;
+}
+
+/**
Find or create instrumentation for a file instance by file name.
@param thread the executing instrumented thread
@param klass the file class
@@ -816,23 +832,13 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
PFS_file *pfs;
PFS_scan scan;
- if (! filename_hash_inited)
+ LF_PINS *pins= get_filename_hash_pins(thread);
+ if (unlikely(pins == NULL))
{
- /* File instrumentation can be turned off. */
file_lost++;
return NULL;
}
- if (unlikely(thread->m_filename_hash_pins == NULL))
- {
- thread->m_filename_hash_pins= lf_hash_get_pins(&filename_hash);
- if (unlikely(thread->m_filename_hash_pins == NULL))
- {
- file_lost++;
- return NULL;
- }
- }
-
char safe_buffer[FN_REFLEN];
const char *safe_filename;
@@ -904,7 +910,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
/* Append the unresolved file name to the resolved path */
char *ptr= buffer + strlen(buffer);
char *buf_end= &buffer[sizeof(buffer)-1];
- if (buf_end > ptr)
+ if ((buf_end > ptr) && (*(ptr-1) != FN_LIBCHAR))
*ptr++= FN_LIBCHAR;
if (buf_end > ptr)
strncpy(ptr, safe_filename + dirlen, buf_end - ptr);
@@ -918,16 +924,18 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
const uint retry_max= 3;
search:
entry= reinterpret_cast<PFS_file**>
- (lf_hash_search(&filename_hash, thread->m_filename_hash_pins,
+ (lf_hash_search(&filename_hash, pins,
normalized_filename, normalized_length));
if (entry && (entry != MY_ERRPTR))
{
pfs= *entry;
pfs->m_file_stat.m_open_count++;
- lf_hash_search_unpin(thread->m_filename_hash_pins);
+ lf_hash_search_unpin(pins);
return pfs;
}
+ lf_hash_search_unpin(pins);
+
/* filename is not constant, just using it for noise on create */
uint random= randomized_index(filename, file_max);
@@ -954,7 +962,7 @@ search:
reset_single_stat_link(&pfs->m_wait_stat);
int res;
- res= lf_hash_insert(&filename_hash, thread->m_filename_hash_pins,
+ res= lf_hash_insert(&filename_hash, pins,
&pfs);
if (likely(res == 0))
{
@@ -1006,9 +1014,12 @@ void release_file(PFS_file *pfs)
void destroy_file(PFS_thread *thread, PFS_file *pfs)
{
DBUG_ASSERT(thread != NULL);
- DBUG_ASSERT(thread->m_filename_hash_pins != NULL);
DBUG_ASSERT(pfs != NULL);
- lf_hash_delete(&filename_hash, thread->m_filename_hash_pins,
+
+ LF_PINS *pins= get_filename_hash_pins(thread);
+ DBUG_ASSERT(pins != NULL);
+
+ lf_hash_delete(&filename_hash, pins,
pfs->m_filename, pfs->m_filename_length);
pfs->m_lock.allocated_to_free();
}