Skip to content

Commit 7b1252c

Browse files
committed
MDEV-24278 InnoDB page cleaner keeps waking up on idle server
The purpose of the InnoDB page cleaner subsystem is to write out modified pages from the buffer pool to data files. When the innodb_max_dirty_pages_pct_lwm is not exceeded or innodb_adaptive_flushing=ON decides not to write out anything, the page cleaner should keep sleeping indefinitely until the state of the system changes: a dirty page is added to the buffer pool such that the page cleaner would no longer be idle. buf_flush_page_cleaner(): Explicitly note when the page cleaner is idle. When that happens, use mysql_cond_wait() instead of mysql_cond_timedwait(). buf_flush_insert_into_flush_list(): Wake up the page cleaner if needed. innodb_max_dirty_pages_pct_update(), innodb_max_dirty_pages_pct_lwm_update(): Wake up the page cleaner just in case. Note: buf_flush_ahead(), buf_flush_wait_flushed() and shutdown are already waking up the page cleaner thread.
1 parent f693b72 commit 7b1252c

File tree

3 files changed

+52
-4
lines changed

3 files changed

+52
-4
lines changed

storage/innobase/buf/buf0flu.cc

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,20 @@ static void buf_flush_validate_skip()
126126
}
127127
#endif /* UNIV_DEBUG */
128128

129+
/** Wake up the page cleaner if needed */
130+
inline void buf_pool_t::page_cleaner_wakeup()
131+
{
132+
if (page_cleaner_idle() &&
133+
(srv_max_dirty_pages_pct_lwm == 0.0 ||
134+
srv_max_dirty_pages_pct_lwm <=
135+
double(UT_LIST_GET_LEN(buf_pool.flush_list)) * 100.0 /
136+
double(UT_LIST_GET_LEN(buf_pool.LRU) + UT_LIST_GET_LEN(buf_pool.free))))
137+
{
138+
page_cleaner_is_idle= false;
139+
mysql_cond_signal(&do_flush_list);
140+
}
141+
}
142+
129143
/** Insert a modified block into the flush list.
130144
@param[in,out] block modified block
131145
@param[in] lsn oldest modification */
@@ -145,6 +159,7 @@ void buf_flush_insert_into_flush_list(buf_block_t* block, lsn_t lsn)
145159

146160
UT_LIST_ADD_FIRST(buf_pool.flush_list, &block->page);
147161
ut_d(buf_flush_validate_skip());
162+
buf_pool.page_cleaner_wakeup();
148163
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
149164
}
150165

@@ -2067,8 +2082,12 @@ static os_thread_ret_t DECLARE_THREAD(buf_flush_page_cleaner)(void*)
20672082
else if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED)
20682083
break;
20692084

2070-
mysql_cond_timedwait(&buf_pool.do_flush_list, &buf_pool.flush_list_mutex,
2071-
&abstime);
2085+
if (buf_pool.page_cleaner_idle())
2086+
mysql_cond_wait(&buf_pool.do_flush_list, &buf_pool.flush_list_mutex);
2087+
else
2088+
mysql_cond_timedwait(&buf_pool.do_flush_list, &buf_pool.flush_list_mutex,
2089+
&abstime);
2090+
20722091
set_timespec(abstime, 1);
20732092

20742093
lsn_limit= buf_flush_sync_lsn;
@@ -2091,6 +2110,8 @@ static os_thread_ret_t DECLARE_THREAD(buf_flush_page_cleaner)(void*)
20912110
/* wake up buf_flush_wait_flushed() */
20922111
mysql_cond_broadcast(&buf_pool.done_flush_list);
20932112
}
2113+
unemployed:
2114+
buf_pool.page_cleaner_set_idle(true);
20942115
continue;
20952116
}
20962117

@@ -2101,13 +2122,14 @@ static os_thread_ret_t DECLARE_THREAD(buf_flush_page_cleaner)(void*)
21012122
double(UT_LIST_GET_LEN(buf_pool.LRU) + UT_LIST_GET_LEN(buf_pool.free));
21022123

21032124
if (dirty_pct < srv_max_dirty_pages_pct_lwm && !lsn_limit)
2104-
continue;
2125+
goto unemployed;
21052126

21062127
const lsn_t oldest_lsn= buf_pool.get_oldest_modification(0);
21072128

21082129
if (UNIV_UNLIKELY(lsn_limit != 0) && oldest_lsn >= lsn_limit)
21092130
buf_flush_sync_lsn= 0;
21102131

2132+
buf_pool.page_cleaner_set_idle(false);
21112133
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
21122134

21132135
ulint n_flushed;
@@ -2159,6 +2181,11 @@ static os_thread_ret_t DECLARE_THREAD(buf_flush_page_cleaner)(void*)
21592181
goto do_checkpoint;
21602182
}
21612183
}
2184+
else
2185+
{
2186+
mysql_mutex_lock(&buf_pool.flush_list_mutex);
2187+
goto unemployed;
2188+
}
21622189

21632190
#ifdef UNIV_DEBUG
21642191
while (innodb_page_cleaner_disabled_debug && !buf_flush_sync_lsn &&

storage/innobase/handler/ha_innodb.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17207,6 +17207,7 @@ innodb_max_dirty_pages_pct_update(
1720717207
in_val);
1720817208

1720917209
srv_max_dirty_pages_pct_lwm = in_val;
17210+
mysql_cond_signal(&buf_pool.do_flush_list);
1721017211
}
1721117212

1721217213
srv_max_buf_pool_modified_pct = in_val;
@@ -17240,6 +17241,7 @@ innodb_max_dirty_pages_pct_lwm_update(
1724017241
}
1724117242

1724217243
srv_max_dirty_pages_pct_lwm = in_val;
17244+
mysql_cond_signal(&buf_pool.do_flush_list);
1724317245
}
1724417246

1724517247
/*************************************************************//**

storage/innobase/include/buf0buf.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1937,10 +1937,29 @@ class buf_pool_t
19371937
FlushHp flush_hp;
19381938
/** modified blocks (a subset of LRU) */
19391939
UT_LIST_BASE_NODE_T(buf_page_t) flush_list;
1940-
1940+
private:
1941+
/** whether the page cleaner needs wakeup from indefinite sleep */
1942+
bool page_cleaner_is_idle;
1943+
public:
19411944
/** signalled to wake up the page_cleaner; protected by flush_list_mutex */
19421945
mysql_cond_t do_flush_list;
19431946

1947+
/** @return whether the page cleaner must sleep due to being idle */
1948+
bool page_cleaner_idle() const
1949+
{
1950+
mysql_mutex_assert_owner(&flush_list_mutex);
1951+
return page_cleaner_is_idle;
1952+
}
1953+
/** Wake up the page cleaner if needed */
1954+
inline void page_cleaner_wakeup();
1955+
1956+
/** Register whether an explicit wakeup of the page cleaner is needed */
1957+
void page_cleaner_set_idle(bool deep_sleep)
1958+
{
1959+
mysql_mutex_assert_owner(&flush_list_mutex);
1960+
page_cleaner_is_idle= deep_sleep;
1961+
}
1962+
19441963
// n_flush_LRU + n_flush_list is approximately COUNT(io_fix()==BUF_IO_WRITE)
19451964
// in flush_list
19461965

0 commit comments

Comments
 (0)