summaryrefslogtreecommitdiff
path: root/storage/innobase/buf/buf0lru.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/buf/buf0lru.c')
-rw-r--r--storage/innobase/buf/buf0lru.c129
1 files changed, 86 insertions, 43 deletions
diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c
index 4f19fd13fa5..c7feb3ae79b 100644
--- a/storage/innobase/buf/buf0lru.c
+++ b/storage/innobase/buf/buf0lru.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2010, Innobase Oy. 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 the Free Software
@@ -350,17 +350,31 @@ scan_again:
bpage = UT_LIST_GET_LAST(buf_pool->LRU);
while (bpage != NULL) {
- mutex_t* block_mutex = buf_page_get_mutex(bpage);
buf_page_t* prev_bpage;
+ ibool prev_bpage_buf_fix = FALSE;
ut_a(buf_page_in_file(bpage));
- mutex_enter(block_mutex);
prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
- if (buf_page_get_space(bpage) == id) {
- if (bpage->buf_fix_count > 0
- || buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
+ /* 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_space(bpage) != id) {
+ /* Skip this block, as it does not belong to
+ the space that is being invalidated. */
+ } else 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 */
+
+ all_freed = FALSE;
+ } else {
+ mutex_t* block_mutex = buf_page_get_mutex(bpage);
+ mutex_enter(block_mutex);
+
+ if (bpage->buf_fix_count > 0) {
/* We cannot remove this page during
this scan yet; maybe the system is
@@ -380,8 +394,40 @@ scan_again:
(ulong) buf_page_get_page_no(bpage));
}
#endif
- if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE
- && ((buf_block_t*) bpage)->is_hashed) {
+ if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
+ /* This is a compressed-only block
+ descriptor. Ensure that prev_bpage
+ cannot be relocated when bpage is freed. */
+ if (UNIV_LIKELY(prev_bpage != NULL)) {
+ switch (buf_page_get_state(
+ prev_bpage)) {
+ case BUF_BLOCK_FILE_PAGE:
+ /* Descriptors of uncompressed
+ blocks will not be relocated,
+ because we are holding the
+ buf_pool_mutex. */
+ break;
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_ZIP_DIRTY:
+ /* Descriptors of compressed-
+ only blocks can be relocated,
+ unless they are buffer-fixed.
+ Because both bpage and
+ prev_bpage are protected by
+ buf_pool_zip_mutex, it is
+ not necessary to acquire
+ further mutexes. */
+ ut_ad(&buf_pool_zip_mutex
+ == block_mutex);
+ ut_ad(mutex_own(block_mutex));
+ prev_bpage_buf_fix = TRUE;
+ prev_bpage->buf_fix_count++;
+ break;
+ default:
+ ut_error;
+ }
+ }
+ } else if (((buf_block_t*) bpage)->is_hashed) {
ulint page_no;
ulint zip_size;
@@ -405,7 +451,8 @@ scan_again:
buf_flush_remove(bpage);
}
- /* Remove from the LRU list */
+ /* Remove from the LRU list. */
+
if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
!= BUF_BLOCK_ZIP_FREE) {
buf_LRU_block_free_hashed_page((buf_block_t*)
@@ -417,18 +464,27 @@ scan_again:
ut_ad(block_mutex == &buf_pool_zip_mutex);
ut_ad(!mutex_own(block_mutex));
- /* The compressed block descriptor
- (bpage) has been deallocated and
- block_mutex released. Also,
- buf_buddy_free() may have relocated
- prev_bpage. Rescan the LRU list. */
+ if (prev_bpage_buf_fix) {
+ /* We temporarily buffer-fixed
+ prev_bpage, so that
+ buf_buddy_free() could not
+ relocate it, in case it was a
+ compressed-only block
+ descriptor. */
+
+ mutex_enter(block_mutex);
+ ut_ad(prev_bpage->buf_fix_count > 0);
+ prev_bpage->buf_fix_count--;
+ mutex_exit(block_mutex);
+ }
- bpage = UT_LIST_GET_LAST(buf_pool->LRU);
- continue;
+ goto next_page_no_mutex;
}
- }
next_page:
- mutex_exit(block_mutex);
+ mutex_exit(block_mutex);
+ }
+
+next_page_no_mutex:
bpage = prev_bpage;
}
@@ -1398,8 +1454,10 @@ alloc:
buf_page_t* prev_b = UT_LIST_GET_PREV(LRU, b);
const ulint fold = buf_page_address_fold(
bpage->space, bpage->offset);
+ buf_page_t* hash_b = buf_page_hash_get_low(
+ bpage->space, bpage->offset, fold);
- ut_a(!buf_page_hash_get(bpage->space, bpage->offset));
+ ut_a(!hash_b);
b->state = b->oldest_modification
? BUF_BLOCK_ZIP_DIRTY
@@ -1474,26 +1532,8 @@ alloc:
if (b->state == BUF_BLOCK_ZIP_PAGE) {
buf_LRU_insert_zip_clean(b);
} else {
- buf_page_t* prev;
-
- ut_ad(b->in_flush_list);
- ut_d(bpage->in_flush_list = FALSE);
-
- prev = UT_LIST_GET_PREV(list, b);
- UT_LIST_REMOVE(list, buf_pool->flush_list, b);
-
- if (prev) {
- ut_ad(prev->in_flush_list);
- UT_LIST_INSERT_AFTER(
- list,
- buf_pool->flush_list,
- prev, b);
- } else {
- UT_LIST_ADD_FIRST(
- list,
- buf_pool->flush_list,
- b);
- }
+ /* Relocate on buf_pool->flush_list. */
+ buf_flush_relocate_on_flush_list(bpage, b);
}
bpage->zip.data = NULL;
@@ -1642,6 +1682,7 @@ buf_LRU_block_remove_hashed_page(
ibool zip) /*!< in: TRUE if should remove also the
compressed page of an uncompressed page */
{
+ ulint fold;
const buf_page_t* hashed_bpage;
ut_ad(bpage);
ut_ad(buf_pool_mutex_own());
@@ -1725,7 +1766,9 @@ buf_LRU_block_remove_hashed_page(
break;
}
- hashed_bpage = buf_page_hash_get(bpage->space, bpage->offset);
+ fold = buf_page_address_fold(bpage->space, bpage->offset);
+ hashed_bpage = buf_page_hash_get_low(bpage->space, bpage->offset,
+ fold);
if (UNIV_UNLIKELY(bpage != hashed_bpage)) {
fprintf(stderr,
@@ -1757,9 +1800,7 @@ buf_LRU_block_remove_hashed_page(
ut_ad(!bpage->in_zip_hash);
ut_ad(bpage->in_page_hash);
ut_d(bpage->in_page_hash = FALSE);
- HASH_DELETE(buf_page_t, hash, buf_pool->page_hash,
- buf_page_address_fold(bpage->space, bpage->offset),
- bpage);
+ HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, bpage);
switch (buf_page_get_state(bpage)) {
case BUF_BLOCK_ZIP_PAGE:
ut_ad(!bpage->in_free_list);
@@ -2036,6 +2077,7 @@ buf_LRU_print(void)
while (bpage != NULL) {
+ mutex_enter(buf_page_get_mutex(bpage));
fprintf(stderr, "BLOCK space %lu page %lu ",
(ulong) buf_page_get_space(bpage),
(ulong) buf_page_get_page_no(bpage));
@@ -2084,6 +2126,7 @@ buf_LRU_print(void)
break;
}
+ mutex_exit(buf_page_get_mutex(bpage));
bpage = UT_LIST_GET_NEXT(LRU, bpage);
}