参数
状态
image.png
made young表示old页移动到LRU头部,not young表示的是访问的old区的页,但是访问这页的时间与上次访问这个页的时间小于innodb_old_blocks_time,不需要移动到LRU的头部。
LRU的插入,删除,以及make young。
buf_page_get_gen
----buf_read_page /* 页如果需要从硬盘中读取的话,需要加入到LRU队列中。 */
--------buf_read_page_low
------------buf_page_init_for_read
----------------buf_LRU_add_block(bpage, TRUE/* to old blocks */);
--------------------buf_LRU_add_block_low
----buf_page_make_young_if_needed
--------if (buf_page_peek_if_too_old(bpage)) {
buf_page_make_young(bpage);
}
buf_LRU_add_block_low的具体逻辑,如果当前LRU的长度小于BUF_LRU_OLD_MIN_LEN,直接插入到LRU的头部,否则插入到old的头部,同时buf_LRU_old_adjust_len调整LRU。
/******************************************************************//**
Adds a block to the LRU list. Please make sure that the page_size is
already set when invoking the function, so that we can get correct
page_size from the buffer page when adding a block into LRU */
UNIV_INLINE
void
buf_LRU_add_block_low(
/*==================*/
buf_page_t* bpage, /*!< in: control block */
ibool old) /*!< in: TRUE if should be put to the old blocks
in the LRU list, else put to the start; if the
LRU list is very short, the block is added to
the start, regardless of this parameter */
{
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
if (!old || (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN)) {
UT_LIST_ADD_FIRST(buf_pool->LRU, bpage);
bpage->freed_page_clock = buf_pool->freed_page_clock;
} else {
UT_LIST_INSERT_AFTER(buf_pool->LRU, buf_pool->LRU_old,
bpage);
buf_pool->LRU_old_len++;
}
incr_LRU_size_in_bytes(bpage, buf_pool);
if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
/* Adjust the length of the old block list if necessary */
buf_page_set_old(bpage, old);
buf_LRU_old_adjust_len(buf_pool);
} else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
/* The LRU list is now long enough for LRU_old to become
defined: init it */
buf_LRU_old_init(buf_pool);
} else {
buf_page_set_old(bpage, buf_pool->LRU_old != NULL);
}
/* If this is a zipped block with decompressed frame as well
then put it on the unzip_LRU list */
if (buf_page_belongs_to_unzip_LRU(bpage)) {
buf_unzip_LRU_add_block((buf_block_t*) bpage, old);
}
}
buf_page_make_young_if_needed用来判断是否page是否需要移动到LRU列表的头部。如果page在old区,并且本次时间减去上次访问时间大于innodb_old_blocks_time,不移动,否则移动到LRU列表的头部,移动后还需要调整下列表
/********************************************************************//**
Recommends a move of a block to the start of the LRU list if there is danger
of dropping from the buffer pool. NOTE: does not reserve the buffer pool
mutex.
@return TRUE if should be made younger */
UNIV_INLINE
ibool
buf_page_peek_if_too_old(
/*=====================*/
const buf_page_t* bpage) /*!< in: block to make younger */
{
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
if (buf_pool->freed_page_clock == 0) {
/* If eviction has not started yet, do not update the
statistics or move blocks in the LRU list. This is
either the warm-up phase or an in-memory workload. */
return(FALSE);
} else if (buf_LRU_old_threshold_ms && bpage->old) {
unsigned access_time = buf_page_is_accessed(bpage);
/* It is possible that the below comparison returns an
unexpected result. 2^32 milliseconds pass in about 50 days,
so if the difference between ut_time_monotonic_ms() and
access_time is e.g. 50 days + 15 ms, then the below will behave
as if it is 15 ms. This is known and fixing it would require to
increase buf_page_t::access_time from 32 to 64 bits. */
if (access_time > 0
&& ((ib_uint32_t) (ut_time_monotonic_ms() - access_time))
>= buf_LRU_old_threshold_ms) {
return(TRUE);
}
buf_pool->stat.n_pages_not_made_young++;
return(FALSE);
} else {
return(!buf_page_peek_if_young(bpage));
}
}
buf_page_get_gen简化版
/** This is the general function used to get access to a database page.
@return pointer to the block or NULL */
buf_block_t*
buf_page_get_gen(
const page_id_t& page_id,
const page_size_t& page_size,
ulint rw_latch,
buf_block_t* guess,
ulint mode,
const char* file,
ulint line,
mtr_t* mtr,
bool dirty_with_no_latch)
{
buf_block_t* block;
unsigned access_time;
rw_lock_t* hash_lock;
buf_block_t* fix_block;
ulint retries = 0;
buf_pool_t* buf_pool = buf_pool_get(page_id);
buf_pool->stat.n_page_gets++;
hash_lock = buf_page_hash_lock_get(buf_pool, page_id);
loop:
block = guess;
if (block == NULL) {
block = (buf_block_t*) buf_page_hash_get_low(buf_pool, page_id);
}
if (!block || buf_pool_watch_is_sentinel(buf_pool, &block->page)) {
rw_lock_s_unlock(hash_lock);
block = NULL;
}
if (block == NULL) {
/* Page not in buf_pool: needs to be read from file */
if (buf_read_page(page_id, page_size)) {
buf_read_ahead_random(page_id, page_size,
ibuf_inside(mtr));
retries = 0;
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
++retries;
} else {
/* 打印错误日志*/
}
goto loop;
} else {
fix_block = block;
}
got_block:
/* Check if this is the first access to the page */
access_time = buf_page_is_accessed(&fix_block->page);
/* This is a heuristic and we don't care about ordering issues. */
if (access_time == 0) {
buf_page_set_accessed(&fix_block->page);
}
if (mode != BUF_PEEK_IF_IN_POOL) {
buf_page_make_young_if_needed(&fix_block->page);
}
if (mode != BUF_PEEK_IF_IN_POOL && !access_time) {
/* In the case of a first access, try to apply linear
read-ahead */
buf_read_ahead_linear(page_id, page_size, ibuf_inside(mtr));
}
return(fix_block);
}
网友评论