本文承接上篇,深入分析 buf0rea.c 中的頁面讀取核心邏輯。原文出處:https://www.cnblogs.com/wingsless/p/5578727.html
該函數負責異步將頁面從磁碟讀入緩衝池,主要工作三階段:
buf_read_ahead_random)buf_read_page_low)buf_flush_free_margin)核心邏輯:給定 (space, offset),計算一個區間 [low, high)(大小由 BUF_READ_AHEAD_RANDOM_AREA 定義),若區間內已被訪問的頁數 ≥ BUF_READ_AHEAD_RANDOM_THRESHOLD,則觸發整個區間的異步預讀。
// 計算區間邊界
low = (offset / BUF_READ_AHEAD_RANDOM_AREA) * BUF_READ_AHEAD_RANDOM_AREA;
high = low + BUF_READ_AHEAD_RANDOM_AREA;
// 統計區間內「近期被訪問」的頁數
for (i = low; i < high; i++) {
block = buf_page_hash_get(space, i);
if (block && block->LRU_position > LRU_recent_limit && block->accessed)
recent_blocks++;
}
// 達閾值則異步預讀區間內所有頁
if (recent_blocks >= BUF_READ_AHEAD_RANDOM_THRESHOLD) {
for (i = low; i < high; i++)
buf_read_page_low(..., OS_AIO_SIMULATED_WAKE_LATER, ...); // 異步模式
}
疑點: 目標頁 (space, offset) 既被異步預讀,後續為何又同步讀一次?
buf_read_page_low 同步模式 (sync=true) 執行實際 I/O,流程:
buf_block_t (buf_block_alloc)buf_page_init)buf_LRU_add_block(block, TRUE))rw_lock_x_lock_gen(&block->lock, BUF_IO_READ))fil_read),完成後 buf_page_io_complete 釋放鎖讀取結束後呼叫 buf_flush_free_margin,若緩衝池髒頁過多或空閒頁不足,觸發刷盤淘汰 LRU 尾部頁面。
這是上層存取頁面的通用介面,流程如下:
buf_page_hash_get(space, offset)buf_read_page() 物理讀入 → goto loop 重新查找accessed = TRUE、判斷是否 make_young(移至 LRU Young 區)buf_read_ahead_linear(space, offset)並非每次訪問都移至 Young 區,需通過 buf_block_peek_if_too_old() 判斷頁面是否在 Old 區停留超過閾值,避免掃描型查詢污染熱點資料。
針對連續訪問模式(如全表掃描),若偵測到連續頁面被順序讀取,預先載入後續頁面。詳細機制留待下篇分析。
源碼閱讀雖枯燥,但能窺見資料庫核心設計的精妙權衡——非同步預讀隱藏延遲、同步讀取保證一致性、LRU 適應性調整平衡命中率與掃描抗污染。下篇將深入線性預讀與自適應哈希索引互動。