Commit a46adb0f authored by Inaam Rana's avatar Inaam Rana

Bug#15859402 INNODB_BUFFER_POOL_READ_AHEAD_EVICTED IS INACCURATE

rb://1546
approved by: Sunny Bains and Marko Makela

Our dealing of buf_page_t::access_time flag is inaccurate.
* If LRU eviction has not started we don't set the access_time
* If LRU eviction is started we set it only if the block is not
'too old'.
* Not a correctness issue but we hold buf_pool::mutex when
setting the flag

This patch fixes this by:
* Setting flag unconditionally whenever the first page access happens
* Use buf_page_t mutex to protect write to the flag
parent b5ff983a
...@@ -1108,32 +1108,21 @@ buf_page_make_young( ...@@ -1108,32 +1108,21 @@ buf_page_make_young(
} }
/********************************************************************//** /********************************************************************//**
Sets the time of the first access of a page and moves a page to the Moves a page to the start of the buffer pool LRU list if it is too old.
start of the buffer pool LRU list if it is too old. This high-level This high-level function can be used to prevent an important page from
function can be used to prevent an important page from slipping slipping out of the buffer pool. */
out of the buffer pool. */
static static
void void
buf_page_set_accessed_make_young( buf_page_make_young_if_needed(
/*=============================*/ /*==========================*/
buf_page_t* bpage, /*!< in/out: buffer block of a buf_page_t* bpage) /*!< in/out: buffer block of a
file page */ file page */
unsigned access_time) /*!< in: bpage->access_time
read under mutex protection,
or 0 if unknown */
{ {
ut_ad(!buf_pool_mutex_own()); ut_ad(!buf_pool_mutex_own());
ut_a(buf_page_in_file(bpage)); ut_a(buf_page_in_file(bpage));
if (buf_page_peek_if_too_old(bpage)) { if (buf_page_peek_if_too_old(bpage)) {
buf_pool_mutex_enter(); buf_page_make_young(bpage);
buf_LRU_make_block_young(bpage);
buf_pool_mutex_exit();
} else if (!access_time) {
ulint time_ms = ut_time_ms();
buf_pool_mutex_enter();
buf_page_set_accessed(bpage, time_ms);
buf_pool_mutex_exit();
} }
} }
...@@ -1217,7 +1206,6 @@ buf_page_get_zip( ...@@ -1217,7 +1206,6 @@ buf_page_get_zip(
buf_page_t* bpage; buf_page_t* bpage;
mutex_t* block_mutex; mutex_t* block_mutex;
ibool must_read; ibool must_read;
unsigned access_time;
#ifndef UNIV_LOG_DEBUG #ifndef UNIV_LOG_DEBUG
ut_ad(!ibuf_inside()); ut_ad(!ibuf_inside());
...@@ -1284,13 +1272,14 @@ err_exit: ...@@ -1284,13 +1272,14 @@ err_exit:
got_block: got_block:
must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ; must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ;
access_time = buf_page_is_accessed(bpage);
buf_pool_mutex_exit(); buf_pool_mutex_exit();
buf_page_set_accessed(bpage);
mutex_exit(block_mutex); mutex_exit(block_mutex);
buf_page_set_accessed_make_young(bpage, access_time); buf_page_make_young_if_needed(bpage);
#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
ut_a(!bpage->file_page_was_freed); ut_a(!bpage->file_page_was_freed);
...@@ -1861,16 +1850,16 @@ wait_until_unfixed: ...@@ -1861,16 +1850,16 @@ wait_until_unfixed:
buf_block_buf_fix_inc(block, file, line); buf_block_buf_fix_inc(block, file, line);
mutex_exit(&block->mutex); buf_pool_mutex_exit();
/* Check if this is the first access to the page */
access_time = buf_page_is_accessed(&block->page); access_time = buf_page_is_accessed(&block->page);
buf_pool_mutex_exit(); buf_page_set_accessed(&block->page);
mutex_exit(&block->mutex);
if (UNIV_LIKELY(mode != BUF_PEEK_IF_IN_POOL)) { if (UNIV_LIKELY(mode != BUF_PEEK_IF_IN_POOL)) {
buf_page_set_accessed_make_young(&block->page, access_time); buf_page_make_young_if_needed(&block->page);
} }
#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
...@@ -1925,7 +1914,7 @@ wait_until_unfixed: ...@@ -1925,7 +1914,7 @@ wait_until_unfixed:
mtr_memo_push(mtr, block, fix_type); mtr_memo_push(mtr, block, fix_type);
if (UNIV_LIKELY(mode != BUF_PEEK_IF_IN_POOL) && !access_time) { if (mode != BUF_PEEK_IF_IN_POOL && !access_time) {
/* In the case of a first access, try to apply linear /* In the case of a first access, try to apply linear
read-ahead */ read-ahead */
...@@ -1975,15 +1964,13 @@ buf_page_optimistic_get( ...@@ -1975,15 +1964,13 @@ buf_page_optimistic_get(
buf_block_buf_fix_inc(block, file, line); buf_block_buf_fix_inc(block, file, line);
mutex_exit(&block->mutex); access_time = buf_page_is_accessed(&block->page);
/* Check if this is the first access to the page. buf_page_set_accessed(&block->page);
We do a dirty read on purpose, to avoid mutex contention.
This field is only used for heuristic purposes; it does not
affect correctness. */
access_time = buf_page_is_accessed(&block->page); mutex_exit(&block->mutex);
buf_page_set_accessed_make_young(&block->page, access_time);
buf_page_make_young_if_needed(&block->page);
ut_ad(!ibuf_inside() ut_ad(!ibuf_inside()
|| ibuf_page(buf_block_get_space(block), || ibuf_page(buf_block_get_space(block),
...@@ -2035,7 +2022,7 @@ buf_page_optimistic_get( ...@@ -2035,7 +2022,7 @@ buf_page_optimistic_get(
#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
ut_a(block->page.file_page_was_freed == FALSE); ut_a(block->page.file_page_was_freed == FALSE);
#endif #endif
if (UNIV_UNLIKELY(!access_time)) { if (!access_time) {
/* In the case of a first access, try to apply linear /* In the case of a first access, try to apply linear
read-ahead */ read-ahead */
...@@ -2095,22 +2082,12 @@ buf_page_get_known_nowait( ...@@ -2095,22 +2082,12 @@ buf_page_get_known_nowait(
buf_block_buf_fix_inc(block, file, line); buf_block_buf_fix_inc(block, file, line);
mutex_exit(&block->mutex); buf_page_set_accessed(&block->page);
if (mode == BUF_MAKE_YOUNG && buf_page_peek_if_too_old(&block->page)) { mutex_exit(&block->mutex);
buf_pool_mutex_enter();
buf_LRU_make_block_young(&block->page);
buf_pool_mutex_exit();
} else if (!buf_page_is_accessed(&block->page)) {
/* Above, we do a dirty read on purpose, to avoid
mutex contention. The field buf_page_t::access_time
is only used for heuristic purposes. Writes to the
field must be protected by mutex, however. */
ulint time_ms = ut_time_ms();
buf_pool_mutex_enter(); if (mode == BUF_MAKE_YOUNG) {
buf_page_set_accessed(&block->page, time_ms); buf_page_make_young_if_needed(&block->page);
buf_pool_mutex_exit();
} }
ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD));
...@@ -2542,7 +2519,6 @@ buf_page_create( ...@@ -2542,7 +2519,6 @@ buf_page_create(
buf_frame_t* frame; buf_frame_t* frame;
buf_block_t* block; buf_block_t* block;
buf_block_t* free_block = NULL; buf_block_t* free_block = NULL;
ulint time_ms = ut_time_ms();
ut_ad(mtr); ut_ad(mtr);
ut_ad(mtr->state == MTR_ACTIVE); ut_ad(mtr->state == MTR_ACTIVE);
...@@ -2627,12 +2603,12 @@ buf_page_create( ...@@ -2627,12 +2603,12 @@ buf_page_create(
rw_lock_x_unlock(&block->lock); rw_lock_x_unlock(&block->lock);
} }
buf_page_set_accessed(&block->page, time_ms);
buf_pool_mutex_exit(); buf_pool_mutex_exit();
mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX); mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX);
buf_page_set_accessed(&block->page);
mutex_exit(&block->mutex); mutex_exit(&block->mutex);
/* Delete possible entries for the page from the insert buffer: /* Delete possible entries for the page from the insert buffer:
......
...@@ -927,8 +927,7 @@ UNIV_INLINE ...@@ -927,8 +927,7 @@ UNIV_INLINE
void void
buf_page_set_accessed( buf_page_set_accessed(
/*==================*/ /*==================*/
buf_page_t* bpage, /*!< in/out: control block */ buf_page_t* bpage) /*!< in/out: control block */
ulint time_ms) /*!< in: ut_time_ms() */
__attribute__((nonnull)); __attribute__((nonnull));
/*********************************************************************//** /*********************************************************************//**
Gets the buf_block_t handle of a buffered file block if an uncompressed Gets the buf_block_t handle of a buffered file block if an uncompressed
...@@ -1260,10 +1259,11 @@ struct buf_page_struct{ ...@@ -1260,10 +1259,11 @@ struct buf_page_struct{
to read this for heuristic to read this for heuristic
purposes without holding any purposes without holding any
mutex or latch */ mutex or latch */
unsigned access_time:32; /*!< time of first access, or
0 if the block was never accessed
in the buffer pool */
/* @} */ /* @} */
unsigned access_time; /*!< time of first access, or
0 if the block was never accessed
in the buffer pool. Protected by
block mutex */
# if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG # if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
ibool file_page_was_freed; ibool file_page_was_freed;
/*!< this is set to TRUE when fsp /*!< this is set to TRUE when fsp
......
...@@ -531,15 +531,15 @@ UNIV_INLINE ...@@ -531,15 +531,15 @@ UNIV_INLINE
void void
buf_page_set_accessed( buf_page_set_accessed(
/*==================*/ /*==================*/
buf_page_t* bpage, /*!< in/out: control block */ buf_page_t* bpage) /*!< in/out: control block */
ulint time_ms) /*!< in: ut_time_ms() */
{ {
ut_a(buf_page_in_file(bpage)); ut_a(buf_page_in_file(bpage));
ut_ad(buf_pool_mutex_own()); ut_ad(!buf_pool_mutex_own());
ut_ad(mutex_own(buf_page_get_mutex(bpage)));
if (!bpage->access_time) { if (!bpage->access_time) {
/* Make this the time of the first access. */ /* Make this the time of the first access. */
bpage->access_time = time_ms; bpage->access_time = ut_time_ms();
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment