InnoDB源碼分析--緩衝池(三)

     轉載請附原文連接:http://www.cnblogs.com/wingsless/p/5582063.htmlhtml

     昨天寫到了InnoDB緩衝池的預讀:《InnoDB源碼分析--緩衝池(二)》,最後由於着急看歐洲盃,沒有把線性預讀寫完,今天接着寫。算法

     線性預讀是由這個函數實現的:buf_read_ahead_linear,和隨機預讀同樣,首先是要肯定區域邊界,這個邊界內被訪問過的page若是達到一個閾值(BUF_READ_AHEAD_LINEAR_THRESHOLD),就會觸發預讀操做。邊界的算法由BUF_READ_AHEAD_LINEAR_AREA決定:less

    low  = (offset / BUF_READ_AHEAD_LINEAR_AREA)
        * BUF_READ_AHEAD_LINEAR_AREA;
    high = (offset / BUF_READ_AHEAD_LINEAR_AREA + 1)
        * BUF_READ_AHEAD_LINEAR_AREA;

    if ((offset != low) && (offset != high - 1)) {
        /* This is not a border page of the area: return */

        return(0);
    }

    注意,若是offset不在邊界上,就不會進行預讀了,這一點和隨機預讀是不同的。線性預讀實際上是順序性讀取的,若是offset在low位置,逆序讀取page,若是offset在high位置,正序讀取page。讀取的每一個頁,都要進行判斷,若是被訪問過的頁的數量到達上面提到的閾值,就知足了線性預讀的條件,達不到閾值,就不進行預讀,代碼以下:異步

    asc_or_desc = 1; //默認正序

    if (offset == low) {
        asc_or_desc = -1; //若是offset在low位置,變成逆序
    }

    fail_count = 0;

    for (i = low; i < high; i++) {
        block = buf_page_hash_get(space, i); //遍歷邊界範圍內的頁

        if ((block == NULL) || !block->accessed) {
            /* Not accessed */
            fail_count++; //未讀取的頁計數

        } else if (pred_block
               && (ut_ulint_cmp(block->LRU_position,
                        pred_block->LRU_position)
                   != asc_or_desc)) {
            /* Accesses not in the right order */

            fail_count++;
            pred_block = block;
        }
    }

    if (fail_count > BUF_READ_AHEAD_LINEAR_AREA
        - BUF_READ_AHEAD_LINEAR_THRESHOLD) { //不知足預讀條件,退出
        /* Too many failures: return */

        mutex_exit(&(buf_pool->mutex));

        return(0);
    }

     我以前在一本書上看到過一句話,大概意思是內存裏的頁能夠不是物理上連續的,邏輯上倒是連續的。這裏的線性預讀要求這些頁在物理上也是必須連續的:函數

    pred_offset = fil_page_get_prev(frame);
    succ_offset = fil_page_get_next(frame);

    mutex_exit(&(buf_pool->mutex));

    if ((offset == low) && (succ_offset == offset + 1)) {

        /* This is ok, we can continue */
new_offset = pred_offset; //知足了條件,繼續 } else if ((offset == high - 1) && (pred_offset == offset - 1)) { /* This is ok, we can continue */ new_offset = succ_offset; //這是正序狀況下,知足條件 } else { /* Successor or predecessor not in the right order */ return(0); }

     這個地方是這樣的,首先利用fil_page_get_prev和fil_page_get_next函數讀取offset->frame以後或者以前的4個bytes,若是結果知足順序條件,能夠繼續進行線性預讀。源碼分析

    for (i = low; i < high; i++) {
        /* It is only sensible to do read-ahead in the non-sync
        aio mode: hence FALSE as the first parameter */

        if (!ibuf_bitmap_page(i)) {
            count += buf_read_page_low(
                &err, FALSE,
                ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
                space, tablespace_version, i);
            if (err == DB_TABLESPACE_DELETED) {
                ut_print_timestamp(stderr);
                fprintf(stderr,
                    "  InnoDB: Warning: in"
                    " linear readahead trying to access\n"
                    "InnoDB: tablespace %lu page %lu,\n"
                    "InnoDB: but the tablespace does not"
                    " exist or is just being dropped.\n",
                    (ulong) space, (ulong) i);
            }
        }
    }

    線性預讀仍是利用了buf_read_page_low函數,這一點和隨機預讀同樣,並且是異步方式。spa

    至此便完成了線性預讀。code

    無論是隨機預讀仍是線性預讀,都會有一些條件不進行預讀,好比系統壓力大的時候不預讀,這個的實現:htm

    if (buf_pool->n_pend_reads
        > buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
        mutex_exit(&(buf_pool->mutex));

        return(0);
    }

    這裏規定了pend讀取數大於buf_pool->curr_size一半的時候,就不預讀了,類似的還有不少條件,都在代碼裏,這裏就不寫了。blog

相關文章
相關標籤/搜索