summaryrefslogtreecommitdiffstats
path: root/storage/innobase/buf/buf0flu.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/buf/buf0flu.cc')
-rw-r--r--storage/innobase/buf/buf0flu.cc144
1 files changed, 101 insertions, 43 deletions
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index b6357989..d4628985 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -655,7 +655,7 @@ static byte *buf_page_encrypt(fil_space_t* space, buf_page_t* bpage, byte* s,
ut_ad(!bpage->zip_size() || !page_compressed);
/* Find free slot from temporary memory array */
- *slot= buf_pool.io_buf_reserve();
+ *slot= buf_pool.io_buf_reserve(true);
ut_a(*slot);
(*slot)->allocate();
@@ -754,16 +754,20 @@ bool buf_page_t::flush(bool evict, fil_space_t *space)
ut_ad(space->referenced());
const auto s= state();
- ut_a(s >= FREED);
+
+ const lsn_t lsn=
+ mach_read_from_8(my_assume_aligned<8>
+ (FIL_PAGE_LSN + (zip.data ? zip.data : frame)));
+ ut_ad(lsn
+ ? lsn >= oldest_modification() || oldest_modification() == 2
+ : space->purpose != FIL_TYPE_TABLESPACE);
if (s < UNFIXED)
{
+ ut_a(s >= FREED);
if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE))
{
- const lsn_t lsn=
- mach_read_from_8(my_assume_aligned<8>
- (FIL_PAGE_LSN + (zip.data ? zip.data : frame)));
- ut_ad(lsn >= oldest_modification());
+ freed:
if (lsn > log_sys.get_flushed_lsn())
{
mysql_mutex_unlock(&buf_pool.mutex);
@@ -775,6 +779,12 @@ bool buf_page_t::flush(bool evict, fil_space_t *space)
return false;
}
+ if (UNIV_UNLIKELY(lsn < space->get_create_lsn()))
+ {
+ ut_ad(space->purpose == FIL_TYPE_TABLESPACE);
+ goto freed;
+ }
+
ut_d(const auto f=) zip.fix.fetch_add(WRITE_FIX - UNFIXED);
ut_ad(f >= UNFIXED);
ut_ad(f < READ_FIX);
@@ -869,15 +879,9 @@ bool buf_page_t::flush(bool evict, fil_space_t *space)
if ((s & LRU_MASK) == REINIT || !space->use_doublewrite())
{
- if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE))
- {
- const lsn_t lsn=
- mach_read_from_8(my_assume_aligned<8>(FIL_PAGE_LSN +
- (write_frame ? write_frame
- : frame)));
- ut_ad(lsn >= oldest_modification());
+ if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE) &&
+ lsn > log_sys.get_flushed_lsn())
log_write_up_to(lsn, true);
- }
space->io(IORequest{type, this, slot}, physical_offset(), size,
write_frame, this);
}
@@ -1057,11 +1061,25 @@ static ulint buf_flush_try_neighbors(fil_space_t *space,
bool contiguous, bool evict,
ulint n_flushed, ulint n_to_flush)
{
- mysql_mutex_unlock(&buf_pool.mutex);
-
ut_ad(space->id == page_id.space());
ut_ad(bpage->id() == page_id);
+ {
+ const lsn_t lsn=
+ mach_read_from_8(my_assume_aligned<8>
+ (FIL_PAGE_LSN +
+ (bpage->zip.data ? bpage->zip.data : bpage->frame)));
+ ut_ad(lsn >= bpage->oldest_modification());
+ if (UNIV_UNLIKELY(lsn < space->get_create_lsn()))
+ {
+ ut_a(!bpage->flush(evict, space));
+ mysql_mutex_unlock(&buf_pool.mutex);
+ return 0;
+ }
+ }
+
+ mysql_mutex_unlock(&buf_pool.mutex);
+
ulint count= 0;
page_id_t id= page_id;
page_id_t high= buf_flush_check_neighbors(*space, id, contiguous, evict);
@@ -1741,6 +1759,28 @@ ulint buf_flush_LRU(ulint max_n, bool evict)
buf_pool.try_LRU_scan= true;
pthread_cond_broadcast(&buf_pool.done_free);
}
+ else if (!pages && !buf_pool.try_LRU_scan &&
+ !buf_pool.LRU_warned.test_and_set(std::memory_order_acquire))
+ {
+ /* For example, with the minimum innodb_buffer_pool_size=5M and
+ the default innodb_page_size=16k there are only a little over 316
+ pages in the buffer pool. The buffer pool can easily be exhausted
+ by a workload of some dozen concurrent connections. The system could
+ reach a deadlock like the following:
+
+ (1) Many threads are waiting in buf_LRU_get_free_block()
+ for buf_pool.done_free.
+ (2) Some threads are waiting for a page latch which is held by
+ another thread that is waiting in buf_LRU_get_free_block().
+ (3) This thread is the only one that could make progress, but
+ we fail to do so because all the pages that we scanned are
+ buffer-fixed or latched by some thread. */
+ sql_print_warning("InnoDB: Could not free any blocks in the buffer pool!"
+ " %zu blocks are in use and %zu free."
+ " Consider increasing innodb_buffer_pool_size.",
+ UT_LIST_GET_LEN(buf_pool.LRU),
+ UT_LIST_GET_LEN(buf_pool.free));
+ }
return pages;
}
@@ -2124,6 +2164,8 @@ ATTRIBUTE_COLD void buf_flush_ahead(lsn_t lsn, bool furious)
limit= lsn;
buf_pool.page_cleaner_set_idle(false);
pthread_cond_signal(&buf_pool.do_flush_list);
+ if (furious)
+ log_sys.set_check_for_checkpoint();
}
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
}
@@ -2371,11 +2413,19 @@ func_exit:
goto func_exit;
}
+TPOOL_SUPPRESS_TSAN
+bool buf_pool_t::need_LRU_eviction() const
+{
+ /* try_LRU_scan==false means that buf_LRU_get_free_block() is waiting
+ for buf_flush_page_cleaner() to evict some blocks */
+ return UNIV_UNLIKELY(!try_LRU_scan ||
+ (UT_LIST_GET_LEN(LRU) > BUF_LRU_MIN_LEN &&
+ UT_LIST_GET_LEN(free) < srv_LRU_scan_depth / 2));
+}
+
#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_flush_page_cleaner(),
-but GCC 4.8.5 does not support pop_options. */
-# pragma GCC optimize ("O0")
+/* Avoid GCC 4.8.5 internal compiler error "could not split insn". */
+__attribute__((optimize(0)))
#endif
/** page_cleaner thread tasked with flushing dirty pages from the buffer
pools. As of now we'll have only one coordinator. */
@@ -2409,21 +2459,24 @@ static void buf_flush_page_cleaner()
}
mysql_mutex_lock(&buf_pool.flush_list_mutex);
- if (buf_pool.ran_out())
- goto no_wait;
- else if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED)
- break;
+ if (!buf_pool.need_LRU_eviction())
+ {
+ if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED)
+ break;
- if (buf_pool.page_cleaner_idle() &&
- (!UT_LIST_GET_LEN(buf_pool.flush_list) ||
- srv_max_dirty_pages_pct_lwm == 0.0))
- /* We are idle; wait for buf_pool.page_cleaner_wakeup() */
- my_cond_wait(&buf_pool.do_flush_list,
- &buf_pool.flush_list_mutex.m_mutex);
- else
- my_cond_timedwait(&buf_pool.do_flush_list,
- &buf_pool.flush_list_mutex.m_mutex, &abstime);
- no_wait:
+ if (buf_pool.page_cleaner_idle() &&
+ (!UT_LIST_GET_LEN(buf_pool.flush_list) ||
+ srv_max_dirty_pages_pct_lwm == 0.0))
+ {
+ buf_pool.LRU_warned.clear(std::memory_order_release);
+ /* We are idle; wait for buf_pool.page_cleaner_wakeup() */
+ my_cond_wait(&buf_pool.do_flush_list,
+ &buf_pool.flush_list_mutex.m_mutex);
+ }
+ else
+ my_cond_timedwait(&buf_pool.do_flush_list,
+ &buf_pool.flush_list_mutex.m_mutex, &abstime);
+ }
set_timespec(abstime, 1);
lsn_limit= buf_flush_sync_lsn;
@@ -2445,9 +2498,9 @@ static void buf_flush_page_cleaner()
do
{
- DBUG_EXECUTE_IF("ib_log_checkpoint_avoid", continue;);
- DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", continue;);
-
+ IF_DBUG(if (_db_keyword_(nullptr, "ib_log_checkpoint_avoid", 1) ||
+ _db_keyword_(nullptr, "ib_log_checkpoint_avoid_hard", 1))
+ continue,);
if (!recv_recovery_is_on() &&
!srv_startup_is_before_trx_rollback_phase &&
srv_operation <= SRV_OPERATION_EXPORT_RESTORED)
@@ -2455,7 +2508,7 @@ static void buf_flush_page_cleaner()
}
while (false);
- if (!buf_pool.ran_out())
+ if (!buf_pool.need_LRU_eviction())
continue;
mysql_mutex_lock(&buf_pool.flush_list_mutex);
oldest_lsn= buf_pool.get_oldest_modification(0);
@@ -2484,7 +2537,7 @@ static void buf_flush_page_cleaner()
if (oldest_lsn >= soft_lsn_limit)
buf_flush_async_lsn= soft_lsn_limit= 0;
}
- else if (buf_pool.ran_out())
+ else if (buf_pool.need_LRU_eviction())
{
buf_pool.page_cleaner_set_idle(false);
buf_pool.n_flush_inc();
@@ -2549,10 +2602,11 @@ static void buf_flush_page_cleaner()
else
{
maybe_unemployed:
- const bool below{dirty_pct < pct_lwm};
- pct_lwm= 0.0;
- if (below)
+ if (dirty_pct < pct_lwm)
+ {
+ pct_lwm= 0.0;
goto possibly_unemployed;
+ }
}
}
else if (dirty_pct < srv_max_buf_pool_modified_pct)
@@ -2598,9 +2652,13 @@ static void buf_flush_page_cleaner()
MONITOR_FLUSH_ADAPTIVE_PAGES,
n_flushed);
}
- else if (buf_flush_async_lsn <= oldest_lsn)
+ else if (buf_flush_async_lsn <= oldest_lsn &&
+ !buf_pool.need_LRU_eviction())
goto check_oldest_and_set_idle;
+ else
+ mysql_mutex_lock(&buf_pool.mutex);
+ n= srv_max_io_capacity;
n= n >= n_flushed ? n - n_flushed : 0;
goto LRU_flush;
}