diff options
Diffstat (limited to 'storage/innobase/buf/buf0lru.cc')
-rw-r--r-- | storage/innobase/buf/buf0lru.cc | 239 |
1 files changed, 97 insertions, 142 deletions
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 250c12bea78..0658ca57c60 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -108,7 +108,7 @@ uint buf_LRU_old_threshold_ms; /** Remove bpage from buf_pool.LRU and buf_pool.page_hash. -If bpage->state() == BUF_BLOCK_ZIP_PAGE && bpage->oldest_modification() <= 1, +If !bpage->frame && bpage->oldest_modification() <= 1, the object will be freed. @param bpage buffer block @@ -117,9 +117,9 @@ the object will be freed. @param zip whether bpage->zip of BUF_BLOCK_FILE_PAGE should be freed If a compressed page is freed other compressed pages may be relocated. -@retval true if BUF_BLOCK_FILE_PAGE was removed from page_hash. The +@retval true if bpage with bpage->frame was removed from page_hash. The caller needs to free the page to the free list -@retval false if BUF_BLOCK_ZIP_PAGE was removed from page_hash. In +@retval false if block without bpage->frame was removed from page_hash. In this case the block is already returned to the buddy allocator. */ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, buf_pool_t::hash_chain &chain, @@ -203,7 +203,8 @@ static bool buf_LRU_free_from_unzip_LRU_list(ulint limit) block && scanned < limit; ++scanned) { buf_block_t* prev_block = UT_LIST_GET_PREV(unzip_LRU, block); - ut_ad(block->page.state() == BUF_BLOCK_FILE_PAGE); + ut_ad(block->page.in_file()); + ut_ad(block->page.belongs_to_unzip_LRU()); ut_ad(block->in_unzip_LRU_list); ut_ad(block->page.in_LRU_list); @@ -268,17 +269,6 @@ static bool buf_LRU_free_from_common_LRU_list(ulint limit) return(freed); } -/** Try to free a replaceable block. -@param limit maximum number of blocks to scan -@return true if found and freed */ -bool buf_LRU_scan_and_free_block(ulint limit) -{ - mysql_mutex_assert_owner(&buf_pool.mutex); - - return buf_LRU_free_from_unzip_LRU_list(limit) || - buf_LRU_free_from_common_LRU_list(limit); -} - /** @return a buffer block from the buf_pool.free list @retval NULL if the free list is empty */ buf_block_t* buf_LRU_get_free_only() @@ -306,15 +296,13 @@ buf_block_t* buf_LRU_get_free_only() a free block. */ assert_block_ahi_empty(block); - block->page.set_state(BUF_BLOCK_MEMORY); - MEM_MAKE_ADDRESSABLE(block->frame, srv_page_size); + block->page.set_state(buf_page_t::MEMORY); + MEM_MAKE_ADDRESSABLE(block->page.frame, srv_page_size); break; } /* This should be withdrawn */ - UT_LIST_ADD_LAST( - buf_pool.withdraw, - &block->page); + UT_LIST_ADD_LAST(buf_pool.withdraw, &block->page); ut_d(block->in_withdraw_list = true); block = reinterpret_cast<buf_block_t*>( @@ -428,7 +416,7 @@ got_block: if (!have_mutex) { mysql_mutex_unlock(&buf_pool.mutex); } - memset(&block->page.zip, 0, sizeof block->page.zip); + block->page.zip.clear(); return block; } @@ -771,6 +759,9 @@ buf_LRU_add_block( /** Move a block to the start of the LRU list. */ void buf_page_make_young(buf_page_t *bpage) { + if (bpage->is_read_fixed()) + return; + ut_ad(bpage->in_file()); mysql_mutex_lock(&buf_pool.mutex); @@ -793,12 +784,10 @@ The caller must hold buf_pool.mutex. @retval false if the page was not freed */ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) { - const page_id_t id(bpage->id()); + const page_id_t id{bpage->id()}; buf_page_t* b = nullptr; mysql_mutex_assert_owner(&buf_pool.mutex); - ut_ad(bpage->in_file()); - ut_ad(bpage->in_LRU_list); /* First, perform a quick check before we acquire hash_lock. */ if (!bpage->can_relocate()) { @@ -839,23 +828,21 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) if (oldest_modification) { goto func_exit; } - } else if (oldest_modification - && bpage->state() != BUF_BLOCK_FILE_PAGE) { + } else if (oldest_modification && !bpage->frame) { func_exit: hash_lock.unlock(); return(false); - } else if (bpage->state() == BUF_BLOCK_FILE_PAGE) { - b = buf_page_alloc_descriptor(); + } else if (bpage->frame) { + b = static_cast<buf_page_t*>(ut_zalloc_nokey(sizeof *b)); ut_a(b); mysql_mutex_lock(&buf_pool.flush_list_mutex); new (b) buf_page_t(*bpage); - b->set_state(BUF_BLOCK_ZIP_PAGE); + b->frame = nullptr; + b->set_state(buf_page_t::UNFIXED + 1); } mysql_mutex_assert_owner(&buf_pool.mutex); - ut_ad(bpage->in_file()); - ut_ad(bpage->in_LRU_list); DBUG_PRINT("ib_buf", ("free page %u:%u", id.space(), id.page_no())); @@ -887,9 +874,7 @@ func_exit: buf_LRU_block_remove_hashed(), which invokes buf_LRU_remove_block(). */ ut_ad(!bpage->in_LRU_list); - - /* bpage->state was BUF_BLOCK_FILE_PAGE because - b != nullptr. The type cast below is thus valid. */ + ut_ad(bpage->frame); ut_ad(!((buf_block_t*) bpage)->in_unzip_LRU_list); /* The fields of bpage were copied to b before @@ -952,13 +937,9 @@ func_exit: page_zip_set_size(&bpage->zip, 0); - /* Prevent buf_page_get_gen() from - decompressing the block while we release - hash_lock. */ - b->set_io_fix(BUF_IO_PIN); - goto release; + b->lock.x_lock(); + hash_lock.unlock(); } else if (!zip) { -release: hash_lock.unlock(); } @@ -974,21 +955,16 @@ release: the contents of the page valid (which it still is) in order to avoid bogus Valgrind or MSAN warnings.*/ - MEM_MAKE_DEFINED(block->frame, srv_page_size); + MEM_MAKE_DEFINED(block->page.frame, srv_page_size); btr_search_drop_page_hash_index(block); - MEM_UNDEFINED(block->frame, srv_page_size); - - if (UNIV_LIKELY_NULL(b)) { - ut_ad(b->zip_size()); - b->io_unfix(); - } - + MEM_UNDEFINED(block->page.frame, srv_page_size); mysql_mutex_lock(&buf_pool.mutex); - } else + } #endif if (UNIV_LIKELY_NULL(b)) { ut_ad(b->zip_size()); - b->io_unfix(); + b->lock.x_unlock(); + b->unfix(); } buf_LRU_block_free_hashed_page(block); @@ -1005,22 +981,22 @@ buf_LRU_block_free_non_file_page( { void* data; - ut_ad(block->page.state() == BUF_BLOCK_MEMORY); + ut_ad(block->page.state() == buf_page_t::MEMORY); assert_block_ahi_empty(block); ut_ad(!block->page.in_free_list); ut_ad(!block->page.oldest_modification()); ut_ad(!block->page.in_LRU_list); ut_ad(!block->page.hash); - block->page.set_state(BUF_BLOCK_NOT_USED); + block->page.set_state(buf_page_t::NOT_USED); - MEM_UNDEFINED(block->frame, srv_page_size); + MEM_UNDEFINED(block->page.frame, srv_page_size); /* Wipe page_no and space_id */ static_assert(FIL_PAGE_OFFSET % 4 == 0, "alignment"); - memset_aligned<4>(block->frame + FIL_PAGE_OFFSET, 0xfe, 4); + memset_aligned<4>(block->page.frame + FIL_PAGE_OFFSET, 0xfe, 4); static_assert(FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID % 4 == 2, "not perfect alignment"); - memset_aligned<2>(block->frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, + memset_aligned<2>(block->page.frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xfe, 4); data = block->page.zip.data; @@ -1050,7 +1026,7 @@ buf_LRU_block_free_non_file_page( pthread_cond_signal(&buf_pool.done_free); } - MEM_NOACCESS(block->frame, srv_page_size); + MEM_NOACCESS(block->page.frame, srv_page_size); } /** Release a memory block to the buffer pool. */ @@ -1065,8 +1041,7 @@ ATTRIBUTE_COLD void buf_pool_t::free_block(buf_block_t *block) /** Remove bpage from buf_pool.LRU and buf_pool.page_hash. -If bpage->state() == BUF_BLOCK_ZIP_PAGE && !bpage->oldest_modification(), -the object will be freed. +If !bpage->frame && !bpage->oldest_modification(), the object will be freed. @param bpage buffer block @param id page identifier @@ -1082,24 +1057,19 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, buf_pool_t::hash_chain &chain, bool zip) { - mysql_mutex_assert_owner(&buf_pool.mutex); + ut_a(bpage->can_relocate()); ut_ad(buf_pool.page_hash.lock_get(chain).is_write_locked()); - ut_a(bpage->io_fix() == BUF_IO_NONE); - ut_a(!bpage->buf_fix_count()); - buf_LRU_remove_block(bpage); buf_pool.freed_page_clock += 1; - switch (bpage->state()) { - case BUF_BLOCK_FILE_PAGE: + if (UNIV_LIKELY(bpage->frame != nullptr)) { MEM_CHECK_ADDRESSABLE(bpage, sizeof(buf_block_t)); - MEM_CHECK_ADDRESSABLE(((buf_block_t*) bpage)->frame, - srv_page_size); + MEM_CHECK_ADDRESSABLE(bpage->frame, srv_page_size); buf_block_modify_clock_inc((buf_block_t*) bpage); - if (bpage->zip.data) { - const page_t* page = ((buf_block_t*) bpage)->frame; + if (UNIV_LIKELY_NULL(bpage->zip.data)) { + const page_t* page = bpage->frame; ut_a(!zip || !bpage->oldest_modification()); ut_ad(bpage->zip_size()); @@ -1147,27 +1117,20 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, putc('\n', stderr); ut_error; } - - break; + } else { + goto evict_zip; } - /* fall through */ - case BUF_BLOCK_ZIP_PAGE: + } else { +evict_zip: ut_a(!bpage->oldest_modification()); MEM_CHECK_ADDRESSABLE(bpage->zip.data, bpage->zip_size()); - break; - case BUF_BLOCK_NOT_USED: - case BUF_BLOCK_MEMORY: - case BUF_BLOCK_REMOVE_HASH: - ut_error; - break; } ut_ad(!bpage->in_zip_hash); buf_pool.page_hash.remove(chain, bpage); - page_hash_latch& hash_lock = buf_pool.page_hash.lock_get(chain); + page_hash_latch& hash_lock = buf_pool.page_hash.lock_get(chain); - switch (bpage->state()) { - case BUF_BLOCK_ZIP_PAGE: + if (UNIV_UNLIKELY(!bpage->frame)) { ut_ad(!bpage->in_free_list); ut_ad(!bpage->in_LRU_list); ut_a(bpage->zip.data); @@ -1180,20 +1143,19 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, buf_buddy_free(bpage->zip.data, bpage->zip_size()); buf_pool_mutex_exit_allow(); - buf_page_free_descriptor(bpage); - return(false); - - case BUF_BLOCK_FILE_PAGE: + bpage->lock.free(); + ut_free(bpage); + return false; + } else { static_assert(FIL_NULL == 0xffffffffU, "fill pattern"); static_assert(FIL_PAGE_OFFSET % 4 == 0, "alignment"); - memset_aligned<4>(reinterpret_cast<buf_block_t*>(bpage)->frame - + FIL_PAGE_OFFSET, 0xff, 4); + memset_aligned<4>(bpage->frame + FIL_PAGE_OFFSET, 0xff, 4); static_assert(FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID % 4 == 2, "not perfect alignment"); - memset_aligned<2>(reinterpret_cast<buf_block_t*>(bpage)->frame + memset_aligned<2>(bpage->frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xff, 4); - MEM_UNDEFINED(((buf_block_t*) bpage)->frame, srv_page_size); - bpage->set_state(BUF_BLOCK_REMOVE_HASH); + MEM_UNDEFINED(bpage->frame, srv_page_size); + bpage->set_state(buf_page_t::REMOVE_HASH); if (!zip) { return true; @@ -1237,41 +1199,36 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, page_zip_set_size(&bpage->zip, 0); } - return(true); - - case BUF_BLOCK_NOT_USED: - case BUF_BLOCK_MEMORY: - case BUF_BLOCK_REMOVE_HASH: - break; + return true; } - - ut_error; - return(false); } /** Release and evict a corrupted page. @param bpage page that was being read */ ATTRIBUTE_COLD void buf_pool_t::corrupted_evict(buf_page_t *bpage) { - const page_id_t id(bpage->id()); + const page_id_t id{bpage->id()}; buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(id.fold()); page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain); mysql_mutex_lock(&mutex); hash_lock.lock(); - ut_ad(bpage->io_fix() == BUF_IO_READ); ut_ad(!bpage->oldest_modification()); bpage->set_corrupt_id(); - bpage->io_unfix(); - - if (bpage->state() == BUF_BLOCK_FILE_PAGE) - reinterpret_cast<buf_block_t*>(bpage)->lock.x_unlock(true); + constexpr auto read_unfix= buf_page_t::READ_FIX - buf_page_t::UNFIXED; + auto s= bpage->zip.fix.fetch_sub(read_unfix) - read_unfix; + bpage->lock.x_unlock(true); - while (bpage->buf_fix_count()) + while (s != buf_page_t::UNFIXED) + { + ut_ad(s > buf_page_t::UNFIXED); + ut_ad(s < buf_page_t::READ_FIX); /* Wait for other threads to release the fix count before releasing the bpage from LRU list. */ (void) LF_BACKOFF(); + s= bpage->state(); + } /* remove from LRU and page_hash */ if (buf_LRU_block_remove_hashed(bpage, id, chain, true)) @@ -1357,6 +1314,23 @@ func_exit: memset(&buf_LRU_stat_cur, 0, sizeof buf_LRU_stat_cur); } +#if defined __aarch64__&&defined __GNUC__&&__GNUC__==4&&!defined __clang__ +/* Avoid GCC 4.8.5 internal compiler error "could not split insn". +We would only need this for buf_LRU_scan_and_free_block(), +but GCC 4.8.5 does not support pop_options. */ +# pragma GCC optimize ("no-expensive-optimizations") +#endif +/** Try to free a replaceable block. +@param limit maximum number of blocks to scan +@return true if found and freed */ +bool buf_LRU_scan_and_free_block(ulint limit) +{ + mysql_mutex_assert_owner(&buf_pool.mutex); + + return buf_LRU_free_from_unzip_LRU_list(limit) || + buf_LRU_free_from_common_LRU_list(limit); +} + #ifdef UNIV_DEBUG /** Validate the LRU list. */ void buf_LRU_validate() @@ -1389,20 +1363,11 @@ void buf_LRU_validate() for (buf_page_t* bpage = UT_LIST_GET_FIRST(buf_pool.LRU); bpage != NULL; bpage = UT_LIST_GET_NEXT(LRU, bpage)) { - - switch (bpage->state()) { - case BUF_BLOCK_NOT_USED: - case BUF_BLOCK_MEMORY: - case BUF_BLOCK_REMOVE_HASH: - ut_error; - break; - case BUF_BLOCK_FILE_PAGE: - ut_ad(reinterpret_cast<buf_block_t*>(bpage) - ->in_unzip_LRU_list - == bpage->belongs_to_unzip_LRU()); - case BUF_BLOCK_ZIP_PAGE: - break; - } + ut_ad(bpage->in_file()); + ut_ad(!bpage->frame + || reinterpret_cast<buf_block_t*>(bpage) + ->in_unzip_LRU_list + == bpage->belongs_to_unzip_LRU()); if (bpage->is_old()) { const buf_page_t* prev @@ -1428,7 +1393,7 @@ void buf_LRU_validate() bpage != NULL; bpage = UT_LIST_GET_NEXT(list, bpage)) { - ut_a(bpage->state() == BUF_BLOCK_NOT_USED); + ut_a(bpage->state() == buf_page_t::NOT_USED); } CheckUnzipLRUAndLRUList::validate(); @@ -1464,38 +1429,28 @@ void buf_LRU_print() fputs("old ", stderr); } - if (const uint32_t buf_fix_count = bpage->buf_fix_count()) { - fprintf(stderr, "buffix count %u ", buf_fix_count); - } - - if (const auto io_fix = bpage->io_fix()) { - fprintf(stderr, "io_fix %d ", io_fix); + const unsigned s = bpage->state(); + if (s > buf_page_t::UNFIXED) { + fprintf(stderr, "fix %u ", s - buf_page_t::UNFIXED); + } else { + ut_ad(s == buf_page_t::UNFIXED + || s == buf_page_t::REMOVE_HASH); } if (bpage->oldest_modification()) { fputs("modif. ", stderr); } - switch (const auto state = bpage->state()) { - const byte* frame; - case BUF_BLOCK_FILE_PAGE: - frame = buf_block_get_frame((buf_block_t*) bpage); - fprintf(stderr, "\ntype %u index id " IB_ID_FMT "\n", - fil_page_get_type(frame), - btr_page_get_index_id(frame)); - break; - case BUF_BLOCK_ZIP_PAGE: - frame = bpage->zip.data; + if (const byte* frame = bpage->zip.data) { fprintf(stderr, "\ntype %u size " ULINTPF " index id " IB_ID_FMT "\n", fil_page_get_type(frame), bpage->zip_size(), btr_page_get_index_id(frame)); - break; - - default: - fprintf(stderr, "\n!state %d!\n", state); - break; + } else { + fprintf(stderr, "\ntype %u index id " IB_ID_FMT "\n", + fil_page_get_type(bpage->frame), + btr_page_get_index_id(bpage->frame)); } } |