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);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,427评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,551评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,747评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,939评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,955评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,737评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,448评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,352评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,834评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,992评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,133评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,815评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,477评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,022评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,147评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,398评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,077评论 2 355