From 28e166d6435741c46e0ea789657b739f78eb0425 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Thu, 20 Jan 2022 16:30:18 +0530 Subject: [PATCH] MDEV-26784 [Warning] InnoDB: Difficult to find free blocks in the buffer pool Problem: ======= InnoDB ran out of memory during recovery and it fails to flush the dirty LRU blocks. The reason is that buffer pool can ran out before the LRU list length reaches BUF_LRU_OLD_MIN_LEN(256) threshold. Fix: ==== During recovery, InnoDB should write out and evict all dirty blocks. --- .../suite/innodb/r/recovery_memory.result | 12 +++++++++++ mysql-test/suite/innodb/t/recovery_memory.opt | 1 + .../suite/innodb/t/recovery_memory.test | 21 +++++++++++++++++++ storage/innobase/buf/buf0flu.cc | 8 ++++--- 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 mysql-test/suite/innodb/r/recovery_memory.result create mode 100644 mysql-test/suite/innodb/t/recovery_memory.opt create mode 100644 mysql-test/suite/innodb/t/recovery_memory.test diff --git a/mysql-test/suite/innodb/r/recovery_memory.result b/mysql-test/suite/innodb/r/recovery_memory.result new file mode 100644 index 00000000000..4fa31009130 --- /dev/null +++ b/mysql-test/suite/innodb/r/recovery_memory.result @@ -0,0 +1,12 @@ +CREATE TABLE t1(c TEXT, KEY(c(3072)))ENGINE=InnoDB; +CREATE PROCEDURE dorepeat() +LOOP +INSERT INTO t1 VALUES ('abc'); +UPDATE t1 SET c='cba'; +END LOOP +| +connect con1,localhost,root,,,; +CALL dorepeat(); +connection default; +# restart: --innodb_buffer_pool_size=5242880 +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/recovery_memory.opt b/mysql-test/suite/innodb/t/recovery_memory.opt new file mode 100644 index 00000000000..7207fd27a42 --- /dev/null +++ b/mysql-test/suite/innodb/t/recovery_memory.opt @@ -0,0 +1 @@ +--innodb_buffer_pool_size=1073741824 diff --git a/mysql-test/suite/innodb/t/recovery_memory.test b/mysql-test/suite/innodb/t/recovery_memory.test new file mode 100644 index 00000000000..d9afd52c499 --- /dev/null +++ b/mysql-test/suite/innodb/t/recovery_memory.test @@ -0,0 +1,21 @@ +--source include/have_innodb.inc +--source include/big_test.inc +CREATE TABLE t1(c TEXT, KEY(c(3072)))ENGINE=InnoDB; +DELIMITER |; + +CREATE PROCEDURE dorepeat() + LOOP + INSERT INTO t1 VALUES ('abc'); + UPDATE t1 SET c='cba'; + END LOOP +| + +DELIMITER ;| +connect(con1,localhost,root,,,); +send CALL dorepeat(); +connection default; +sleep 10; +let $shutdown_timeout=0; +let $restart_parameters=--innodb_buffer_pool_size=5242880; +--source include/restart_mysqld.inc +DROP TABLE t1; diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index c14b274645d..ce8f8dc34c4 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -1288,9 +1288,11 @@ static void buf_flush_LRU_list_batch(ulint max, flush_counters_t *n) static_assert(FIL_NULL > SRV_SPACE_ID_UPPER_BOUND, "consistency"); for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.LRU); - bpage && n->flushed + n->evicted < max && - UT_LIST_GET_LEN(buf_pool.LRU) > BUF_LRU_MIN_LEN && - UT_LIST_GET_LEN(buf_pool.free) < free_limit; ++scanned) + bpage && + ((UT_LIST_GET_LEN(buf_pool.LRU) > BUF_LRU_MIN_LEN && + UT_LIST_GET_LEN(buf_pool.free) < free_limit && + n->flushed + n->evicted < max) || + recv_recovery_is_on()); ++scanned) { buf_page_t *prev= UT_LIST_GET_PREV(LRU, bpage); const lsn_t oldest_modification= bpage->oldest_modification();