diff options
Diffstat (limited to 'storage/innobase/buf/buf0lru.cc')
-rw-r--r-- | storage/innobase/buf/buf0lru.cc | 99 |
1 files changed, 58 insertions, 41 deletions
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 6c994b8c9bd..e4e20e8335f 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -136,7 +136,6 @@ static void buf_LRU_block_free_hashed_page(buf_block_t *block) @param[in] bpage control block */ static inline void incr_LRU_size_in_bytes(const buf_page_t* bpage) { - /* FIXME: use atomics, not mutex */ mysql_mutex_assert_owner(&buf_pool.mutex); buf_pool.stat.LRU_bytes += bpage->physical_size(); @@ -401,8 +400,10 @@ buf_block_t* buf_LRU_get_free_block(buf_LRU_get get) DBUG_EXECUTE_IF("recv_ran_out_of_buffer", if (recv_recovery_is_on() && recv_sys.apply_log_recs) { + mysql_mutex_lock(&buf_pool.mutex); goto flush_lru; }); +get_mutex: mysql_mutex_lock(&buf_pool.mutex); got_mutex: buf_LRU_check_size_of_non_data_objects(); @@ -451,20 +452,32 @@ got_block: if ((block = buf_LRU_get_free_only()) != nullptr) { goto got_block; } - if (!buf_pool.n_flush_LRU_) { - break; + mysql_mutex_unlock(&buf_pool.mutex); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + const auto n_flush = buf_pool.n_flush(); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + mysql_mutex_lock(&buf_pool.mutex); + if (!n_flush) { + goto not_found; + } + if (!buf_pool.try_LRU_scan) { + mysql_mutex_lock(&buf_pool.flush_list_mutex); + buf_pool.page_cleaner_wakeup(true); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + my_cond_wait(&buf_pool.done_free, + &buf_pool.mutex.m_mutex); } - my_cond_wait(&buf_pool.done_free, &buf_pool.mutex.m_mutex); } -#ifndef DBUG_OFF not_found: -#endif - mysql_mutex_unlock(&buf_pool.mutex); + if (n_iterations > 1) { + MONITOR_INC( MONITOR_LRU_GET_FREE_WAITS ); + } - if (n_iterations > 20 && !buf_lru_free_blocks_error_printed + if (n_iterations == 21 && !buf_lru_free_blocks_error_printed && srv_buf_pool_old_size == srv_buf_pool_size) { - + buf_lru_free_blocks_error_printed = true; + mysql_mutex_unlock(&buf_pool.mutex); ib::warn() << "Difficult to find free blocks in the buffer pool" " (" << n_iterations << " search iterations)! " << flush_failures << " failed attempts to" @@ -476,12 +489,7 @@ not_found: << os_n_file_writes << " OS file writes, " << os_n_fsyncs << " OS fsyncs."; - - buf_lru_free_blocks_error_printed = true; - } - - if (n_iterations > 1) { - MONITOR_INC( MONITOR_LRU_GET_FREE_WAITS ); + mysql_mutex_lock(&buf_pool.mutex); } /* No free block was found: try to flush the LRU list. @@ -495,15 +503,16 @@ not_found: #ifndef DBUG_OFF flush_lru: #endif - if (!buf_flush_LRU(innodb_lru_flush_size)) { + if (!buf_flush_LRU(innodb_lru_flush_size, true)) { MONITOR_INC(MONITOR_LRU_SINGLE_FLUSH_FAILURE_COUNT); ++flush_failures; } n_iterations++; - mysql_mutex_lock(&buf_pool.mutex); buf_pool.stat.LRU_waits++; - goto got_mutex; + mysql_mutex_unlock(&buf_pool.mutex); + buf_dblwr.flush_buffered_writes(); + goto get_mutex; } /** Move the LRU_old pointer so that the length of the old blocks list @@ -812,50 +821,57 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) /* We cannot use transactional_lock_guard here, because buf_buddy_relocate() in buf_buddy_free() could get stuck. */ hash_lock.lock(); - lsn_t oldest_modification = bpage->oldest_modification_acquire(); + const lsn_t oldest_modification = bpage->oldest_modification_acquire(); if (UNIV_UNLIKELY(!bpage->can_relocate())) { /* Do not free buffer fixed and I/O-fixed blocks. */ goto func_exit; } - if (oldest_modification == 1) { + switch (oldest_modification) { + case 2: + ut_ad(id.space() == SRV_TMP_SPACE_ID); + ut_ad(!bpage->zip.data); + if (!bpage->is_freed()) { + goto func_exit; + } + bpage->clear_oldest_modification(); + break; + case 1: mysql_mutex_lock(&buf_pool.flush_list_mutex); - oldest_modification = bpage->oldest_modification(); - if (oldest_modification) { - ut_ad(oldest_modification == 1); + if (const lsn_t om = bpage->oldest_modification()) { + ut_ad(om == 1); buf_pool.delete_from_flush_list(bpage); } mysql_mutex_unlock(&buf_pool.flush_list_mutex); ut_ad(!bpage->oldest_modification()); - oldest_modification = 0; - } - - if (zip || !bpage->zip.data) { - /* This would completely free the block. */ - /* Do not completely free dirty blocks. */ - - if (oldest_modification) { - goto func_exit; + /* fall through */ + case 0: + if (zip || !bpage->zip.data || !bpage->frame) { + break; } - } else if (oldest_modification && !bpage->frame) { -func_exit: - hash_lock.unlock(); - return(false); - - } else if (bpage->frame) { +relocate_compressed: 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->frame = nullptr; b->set_state(buf_page_t::UNFIXED + 1); + break; + default: + if (zip || !bpage->zip.data || !bpage->frame) { + /* This would completely free the block. */ + /* Do not completely free dirty blocks. */ +func_exit: + hash_lock.unlock(); + return(false); + } + goto relocate_compressed; } mysql_mutex_assert_owner(&buf_pool.mutex); - DBUG_PRINT("ib_buf", ("free page %u:%u", - id.space(), id.page_no())); + DBUG_PRINT("ib_buf", ("free page %u:%u", id.space(), id.page_no())); ut_ad(bpage->can_relocate()); @@ -1026,7 +1042,8 @@ buf_LRU_block_free_non_file_page( } else { UT_LIST_ADD_FIRST(buf_pool.free, &block->page); ut_d(block->page.in_free_list = true); - pthread_cond_signal(&buf_pool.done_free); + buf_pool.try_LRU_scan= true; + pthread_cond_broadcast(&buf_pool.done_free); } block->page.set_os_unused(); |