圖解MySQL系列(4)-Buffer Pool中的free鏈表

1 MySQL如何初始化Buffer Pool

Buffer Pool中有N多緩存頁,每個緩存頁還有個描述信息。DB啓動後,按BP大小向os申請一塊內存區域,作爲BP的內存區域。

當內存區域申請完後,DB按默認緩存頁及對應描述信息快,在BP中劃出一塊塊內存,當DB把BP劃分完後:

這時,BP中的一個個緩存頁還都是空的,要等DB運行起來後,當我們要對數據執行CRUD操作時,纔會把數據對應的頁從磁盤文件裏讀取出來,放入BP中的緩存頁。

哪些緩存頁空閒?

DB運行後,肯定執行大量CRUD,就需不停的從磁盤上讀取一個個數據頁放入BP中的對應的緩存頁裏去,把數據緩存起來,後續就能對該數據在內存裏執行CRUD。

但是此時在從磁盤上讀取數據頁放入Buffer Pool中的緩存頁的時候,必然涉及到一個問題,那就是哪些緩存頁是空閒的?

因爲默認情況下磁盤上的數據頁和緩存頁一一對應,都是16K,一個數據頁對應一個緩存頁。所以必須要知道BP中哪些緩存頁是空閒狀態。

所以數據庫會爲BP設計個free鏈表,雙向鏈表,每個節點就是個空閒緩存頁的描述數據塊的地址,即只要一個緩存頁空閒,那他的描述數據塊就會被放入free鏈表。

剛開始DB啓動時,可能所有緩存頁都空閒,因爲此時可能是個空DB,所以此時所有緩存頁的描述數據塊,都放入free鏈表。

上圖中,這free鏈表裏就是各個緩存頁的描述信息塊,只要緩存頁空閒,對應的描述信息塊就會加入free鏈表,每個節點都會雙向鏈接自己的前後節點,組成一個雙向鏈表。free鏈表有個基礎節點引用鏈表的頭節點和尾節點,存儲了鏈表中有多少個描述數據塊的節點,即有多少個空閒緩存頁。

free鏈表佔用內存大小

這free鏈表本就由BP裏的描述信息塊組成,可認爲是每個描述信息塊裏都有兩個指針:

  • free_pre

    指向自己的上一個free鏈表節點

  • free_next

    指向下一個free鏈表的節點

通過BP中的描述數據塊的free_pre和free_next兩個指針,就能將所有描述數據塊串成一個free鏈表,上面只是爲了方便畫圖,所以將描述信息塊單獨畫出來。

對free鏈表,只有一個基礎節點(40K)不屬於BP,存放了free鏈表的頭節點地址,尾節點地址,還有free鏈表當前節點個數。

如何將磁盤上的頁讀取到BP的緩存頁?

先從free鏈表獲取一個描述信息塊,就能獲取到對應空閒緩存頁。

就能將磁盤上的數據頁讀到對應緩存頁,同時將相關的描述信息寫入緩存頁的描述信息塊,比如該數據頁所屬的表空間之類的信息,最後把那描述信息塊從free鏈表中移除:

怎知數據頁是否被緩存?

執行CRUD時,先看該數據頁是否被緩存,若沒被緩存就走上面邏輯,從free找個空閒緩存頁,從磁盤上讀取數據頁寫入緩存頁,寫入描述信息,最後從free中移除該描述信息塊。

但若數據頁已被緩存,就能直接使用。

所以DB還有個數據頁緩存哈希表:

  • key:表空間號+數據頁號
  • value:緩存頁的地址

當要使用一個數據頁時,通過“表空間號+數據頁號”作爲K查這個哈希表:

  • 若無,讀取數據頁
  • 若有,說明數據頁已被緩存

每次讀取一個數據頁到緩存後,都會在這哈希表寫入一個數據,下次若再使用這數據頁,就能從哈希表直接讀出來,畢竟他經被放入一個緩存頁了:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章