MySQL-Innodb-LRU

参数
状态


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);
}

你可能感兴趣的:(MySQL-Innodb-LRU)