@@ -1797,6 +1797,28 @@ ulint buf_flush_LRU(ulint max_n, bool evict)
1797
1797
buf_pool.try_LRU_scan = true ;
1798
1798
pthread_cond_broadcast (&buf_pool.done_free );
1799
1799
}
1800
+ else if (!pages && !buf_pool.try_LRU_scan &&
1801
+ buf_pool.LRU_warned .test_and_set (std::memory_order_acquire))
1802
+ {
1803
+ /* For example, with the minimum innodb_buffer_pool_size=5M and
1804
+ the default innodb_page_size=16k there are only a little over 316
1805
+ pages in the buffer pool. The buffer pool can easily be exhausted
1806
+ by a workload of some dozen concurrent connections. The system could
1807
+ reach a deadlock like the following:
1808
+
1809
+ (1) Many threads are waiting in buf_LRU_get_free_block()
1810
+ for buf_pool.done_free.
1811
+ (2) Some threads are waiting for a page latch which is held by
1812
+ another thread that is waiting in buf_LRU_get_free_block().
1813
+ (3) This thread is the only one that could make progress, but
1814
+ we fail to do so because all the pages that we scanned are
1815
+ buffer-fixed or latched by some thread. */
1816
+ sql_print_warning (" InnoDB: Could not free any blocks in the buffer pool!"
1817
+ " %zu blocks are in use and %zu free."
1818
+ " Consider increasing innodb_buffer_pool_size." ,
1819
+ UT_LIST_GET_LEN (buf_pool.LRU ),
1820
+ UT_LIST_GET_LEN (buf_pool.free ));
1821
+ }
1800
1822
1801
1823
return pages;
1802
1824
}
@@ -2287,6 +2309,16 @@ static ulint page_cleaner_flush_pages_recommendation(ulint last_pages_in,
2287
2309
goto func_exit;
2288
2310
}
2289
2311
2312
+ TPOOL_SUPPRESS_TSAN
2313
+ bool buf_pool_t::need_LRU_eviction () const
2314
+ {
2315
+ /* try_LRU_scan==false means that buf_LRU_get_free_block() is waiting
2316
+ for buf_flush_page_cleaner() to evict some blocks */
2317
+ return UNIV_UNLIKELY (!try_LRU_scan ||
2318
+ (UT_LIST_GET_LEN (LRU) > BUF_LRU_MIN_LEN &&
2319
+ UT_LIST_GET_LEN (free) < srv_LRU_scan_depth / 2 ));
2320
+ }
2321
+
2290
2322
/* * page_cleaner thread tasked with flushing dirty pages from the buffer
2291
2323
pools. As of now we'll have only one coordinator. */
2292
2324
static void buf_flush_page_cleaner ()
@@ -2319,21 +2351,24 @@ static void buf_flush_page_cleaner()
2319
2351
}
2320
2352
2321
2353
mysql_mutex_lock (&buf_pool.flush_list_mutex );
2322
- if (buf_pool.ran_out ())
2323
- goto no_wait;
2324
- else if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED)
2325
- break ;
2354
+ if (! buf_pool.need_LRU_eviction ())
2355
+ {
2356
+ if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED)
2357
+ break ;
2326
2358
2327
- if (buf_pool.page_cleaner_idle () &&
2328
- (!UT_LIST_GET_LEN (buf_pool.flush_list ) ||
2329
- srv_max_dirty_pages_pct_lwm == 0.0 ))
2330
- /* We are idle; wait for buf_pool.page_cleaner_wakeup() */
2331
- my_cond_wait (&buf_pool.do_flush_list ,
2332
- &buf_pool.flush_list_mutex .m_mutex );
2333
- else
2334
- my_cond_timedwait (&buf_pool.do_flush_list ,
2335
- &buf_pool.flush_list_mutex .m_mutex , &abstime);
2336
- no_wait:
2359
+ if (buf_pool.page_cleaner_idle () &&
2360
+ (!UT_LIST_GET_LEN (buf_pool.flush_list ) ||
2361
+ srv_max_dirty_pages_pct_lwm == 0.0 ))
2362
+ {
2363
+ buf_pool.LRU_warned .clear (std::memory_order_release);
2364
+ /* We are idle; wait for buf_pool.page_cleaner_wakeup() */
2365
+ my_cond_wait (&buf_pool.do_flush_list ,
2366
+ &buf_pool.flush_list_mutex .m_mutex );
2367
+ }
2368
+ else
2369
+ my_cond_timedwait (&buf_pool.do_flush_list ,
2370
+ &buf_pool.flush_list_mutex .m_mutex , &abstime);
2371
+ }
2337
2372
set_timespec (abstime, 1 );
2338
2373
2339
2374
lsn_limit= buf_flush_sync_lsn;
@@ -2365,7 +2400,7 @@ static void buf_flush_page_cleaner()
2365
2400
}
2366
2401
while (false );
2367
2402
2368
- if (!buf_pool.ran_out ())
2403
+ if (!buf_pool.need_LRU_eviction ())
2369
2404
continue ;
2370
2405
mysql_mutex_lock (&buf_pool.flush_list_mutex );
2371
2406
oldest_lsn= buf_pool.get_oldest_modification (0 );
@@ -2394,7 +2429,7 @@ static void buf_flush_page_cleaner()
2394
2429
if (oldest_lsn >= soft_lsn_limit)
2395
2430
buf_flush_async_lsn= soft_lsn_limit= 0 ;
2396
2431
}
2397
- else if (buf_pool.ran_out ())
2432
+ else if (buf_pool.need_LRU_eviction ())
2398
2433
{
2399
2434
buf_pool.page_cleaner_set_idle (false );
2400
2435
buf_pool.n_flush_inc ();
@@ -2509,9 +2544,11 @@ static void buf_flush_page_cleaner()
2509
2544
MONITOR_FLUSH_ADAPTIVE_PAGES,
2510
2545
n_flushed);
2511
2546
}
2512
- else if (buf_flush_async_lsn <= oldest_lsn)
2547
+ else if (buf_flush_async_lsn <= oldest_lsn &&
2548
+ !buf_pool.need_LRU_eviction ())
2513
2549
goto check_oldest_and_set_idle;
2514
2550
2551
+ n= srv_max_io_capacity;
2515
2552
n= n >= n_flushed ? n - n_flushed : 0 ;
2516
2553
goto LRU_flush;
2517
2554
}
0 commit comments