summaryrefslogtreecommitdiffstats
path: root/storage/innobase/buf/buf0lru.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/buf/buf0lru.cc')
-rw-r--r--storage/innobase/buf/buf0lru.cc184
1 files changed, 59 insertions, 125 deletions
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index 2a8d6ff2..33d01b6b 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -385,142 +385,76 @@ we put it to free list to be used.
@return the free control block, in state BUF_BLOCK_MEMORY */
buf_block_t *buf_LRU_get_free_block(bool have_mutex)
{
- ulint n_iterations = 0;
- ulint flush_failures = 0;
- MONITOR_INC(MONITOR_LRU_GET_FREE_SEARCH);
- if (have_mutex) {
- mysql_mutex_assert_owner(&buf_pool.mutex);
- goto got_mutex;
- }
- 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();
- buf_block_t* block;
+ bool waited= false;
+ MONITOR_INC(MONITOR_LRU_GET_FREE_SEARCH);
+ if (!have_mutex)
+ mysql_mutex_lock(&buf_pool.mutex);
+
+ buf_LRU_check_size_of_non_data_objects();
- IF_DBUG(static bool buf_lru_free_blocks_error_printed,);
- DBUG_EXECUTE_IF("ib_lru_force_no_free_page",
- if (!buf_lru_free_blocks_error_printed) {
- n_iterations = 21;
- goto not_found;});
+ buf_block_t *block;
retry:
- /* If there is a block in the free list, take it */
- if ((block = buf_LRU_get_free_only()) != nullptr) {
+ /* If there is a block in the free list, take it */
+ block= buf_LRU_get_free_only();
+ if (block)
+ {
got_block:
- const ulint LRU_size = UT_LIST_GET_LEN(buf_pool.LRU);
- const ulint available = UT_LIST_GET_LEN(buf_pool.free);
- const ulint scan_depth = srv_LRU_scan_depth / 2;
- ut_ad(LRU_size <= BUF_LRU_MIN_LEN || available >= scan_depth
- || buf_pool.need_LRU_eviction());
-
- if (!have_mutex) {
- mysql_mutex_unlock(&buf_pool.mutex);
- }
-
- if (UNIV_UNLIKELY(available < scan_depth)
- && LRU_size > BUF_LRU_MIN_LEN) {
- mysql_mutex_lock(&buf_pool.flush_list_mutex);
- if (!buf_pool.page_cleaner_active()) {
- buf_pool.page_cleaner_wakeup(true);
- }
- mysql_mutex_unlock(&buf_pool.flush_list_mutex);
- }
-
- block->page.zip.clear();
- return block;
- }
+ const ulint LRU_size= UT_LIST_GET_LEN(buf_pool.LRU);
+ const ulint available= UT_LIST_GET_LEN(buf_pool.free);
+ const ulint scan_depth= srv_LRU_scan_depth / 2;
+ ut_ad(LRU_size <= BUF_LRU_MIN_LEN ||
+ available >= scan_depth || buf_pool.need_LRU_eviction());
- MONITOR_INC( MONITOR_LRU_GET_FREE_LOOPS );
- if (n_iterations || buf_pool.try_LRU_scan) {
- /* If no block was in the free list, search from the
- end of the LRU list and try to free a block there.
- If we are doing for the first time we'll scan only
- tail of the LRU list otherwise we scan the whole LRU
- list. */
- if (buf_LRU_scan_and_free_block(n_iterations
- ? ULINT_UNDEFINED : 100)) {
- goto retry;
- }
+ if (UNIV_UNLIKELY(available < scan_depth) && LRU_size > BUF_LRU_MIN_LEN)
+ {
+ mysql_mutex_lock(&buf_pool.flush_list_mutex);
+ if (!buf_pool.page_cleaner_active())
+ buf_pool.page_cleaner_wakeup(true);
+ mysql_mutex_unlock(&buf_pool.flush_list_mutex);
+ }
- /* Tell other threads that there is no point
- in scanning the LRU list. */
- buf_pool.try_LRU_scan = false;
- }
+ if (!have_mutex)
+ mysql_mutex_unlock(&buf_pool.mutex);
- for (;;) {
- if ((block = buf_LRU_get_free_only()) != nullptr) {
- goto got_block;
- }
- const bool wake = buf_pool.need_LRU_eviction();
- mysql_mutex_unlock(&buf_pool.mutex);
- mysql_mutex_lock(&buf_pool.flush_list_mutex);
- const auto n_flush = buf_pool.n_flush();
- if (wake && !buf_pool.page_cleaner_active()) {
- buf_pool.page_cleaner_wakeup(true);
- }
- 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) {
- my_cond_wait(&buf_pool.done_free,
- &buf_pool.mutex.m_mutex);
- }
- }
-
-not_found:
- if (n_iterations > 1) {
- MONITOR_INC( MONITOR_LRU_GET_FREE_WAITS );
- }
+ block->page.zip.clear();
+ return block;
+ }
- if (n_iterations == 21
- && srv_buf_pool_old_size == srv_buf_pool_size
- && buf_pool.LRU_warned.test_and_set(std::memory_order_acquire)) {
- IF_DBUG(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"
- " flush a page!"
- " Consider increasing innodb_buffer_pool_size."
- " Pending flushes (fsync): "
- << fil_n_pending_tablespace_flushes
- << ". " << os_n_file_reads << " OS file reads, "
- << os_n_file_writes << " OS file writes, "
- << os_n_fsyncs
- << " OS fsyncs.";
- mysql_mutex_lock(&buf_pool.mutex);
- }
+ MONITOR_INC(MONITOR_LRU_GET_FREE_LOOPS);
+ if (waited || buf_pool.try_LRU_scan)
+ {
+ /* If no block was in the free list, search from the end of the
+ LRU list and try to free a block there. If we are doing for the
+ first time we'll scan only tail of the LRU list otherwise we scan
+ the whole LRU list. */
+ if (buf_LRU_scan_and_free_block(waited ? ULINT_UNDEFINED : 100))
+ goto retry;
+
+ /* Tell other threads that there is no point in scanning the LRU
+ list. */
+ buf_pool.try_LRU_scan= false;
+ }
- /* No free block was found: try to flush the LRU list.
- The freed blocks will be up for grabs for all threads.
+ waited= true;
- TODO: A more elegant way would have been to return one freed
- up block to the caller here but the code that deals with
- removing the block from buf_pool.page_hash and buf_pool.LRU is fairly
- involved (particularly in case of ROW_FORMAT=COMPRESSED pages). We
- can do that in a separate patch sometime in future. */
-#ifndef DBUG_OFF
-flush_lru:
-#endif
- if (!buf_flush_LRU(innodb_lru_flush_size, true)) {
- MONITOR_INC(MONITOR_LRU_SINGLE_FLUSH_FAILURE_COUNT);
- ++flush_failures;
- }
+ while (!(block= buf_LRU_get_free_only()))
+ {
+ buf_pool.stat.LRU_waits++;
+
+ timespec abstime;
+ set_timespec(abstime, 1);
+
+ mysql_mutex_lock(&buf_pool.flush_list_mutex);
+ if (!buf_pool.page_cleaner_active())
+ buf_pool.page_cleaner_wakeup(true);
+ mysql_mutex_unlock(&buf_pool.flush_list_mutex);
+ if (my_cond_timedwait(&buf_pool.done_free, &buf_pool.mutex.m_mutex,
+ &abstime))
+ buf_pool.LRU_warn();
+ }
- n_iterations++;
- buf_pool.stat.LRU_waits++;
- mysql_mutex_unlock(&buf_pool.mutex);
- buf_dblwr.flush_buffered_writes();
- goto get_mutex;
+ goto got_block;
}
/** Move the LRU_old pointer so that the length of the old blocks list