InnoDBソース分析--バッファ(三)

8876 ワード

転載は原文のリンクを添付してください.http://www.cnblogs.com/wingsless/p/5582063.html
     昨日はInnoDBバッファの予読について書きました.
     線形予読はこの関数によって実現される:buf_read_.アホードlinearは、ランダム予読と同様に、まず領域境界を決めます.この境界内に訪問されたpageがしきい値に達すると、予読動作をトリガします.境界のアルゴリズムはBUF_によって実行される.READ_AHEAD_LINEAR_AREA決定:
    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がハイテンション位置にあれば、順に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_ゲットするprevとfil_page_ゲットする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
" "InnoDB: tablespace %lu page %lu,
" "InnoDB: but the tablespace does not" " exist or is just being dropped.
", (ulong) space, (ulong) i); } } }
    リニア予読はやはりbuf_を利用しました.read_.page_low関数は、この点はランダム予読と同じで、非同期方式です.
    これでリニア予読が完了しました.
    ランダムで予読しても、線形で予読しても、システムの圧力が大きい時に予読しないような条件があります.
    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の半分の時は予読しません.似たような条件はまだたくさんあります.コードの中にあります.ここでは書きません.