cmu15445 2022fall lab1 Buffer Pool
此project實現一個buffer pool,快取住磁碟查詢的資料。
Task1
這部分需要我們實現一個可擴充套件的雜湊表,這部分的難點在於插入操作時的分裂,由於Remove不需要我們將目錄和桶收縮回去,所以它也很簡單。
先分析清楚目錄和桶的結構。
我們可以先實現簡單的部分,Find,Remove,以及對桶的Find、Remove、Insert,這幾個函式都非常簡單,檢視一下對應類的成員變數就行了,需要注意的是對桶的insert,如果滿了直接返回false即可。
然後就是Insert函式。
- 首先根據索引找目錄項對應的桶,插入成功直接返回,插入失敗進入下一步
- while迴圈判斷應該插入的桶是否滿,因為有可能分裂並重分配節點後還是滿的,需要再次分裂
- 如果桶的深度不等於全域性深度時,可以不需要分裂,而是增加一個目錄項,這個我們後面再說,先說分裂的步驟
- 全域性深度加1
- 目錄翻倍,即複製一份到目錄的後面
- 記錄一下之前插入桶的深度(用於後面尋找兄弟目錄),並將深度加1,再建立一個深度一樣的桶
- 尋找兄弟目錄(它們是指向同一個桶的目錄,他們的低位是一樣的,低位的長度就是之前記錄的深度),因為深度增加之後它們的更高的一位就會不一樣,把高一位為1的那個目錄指標指向新的桶。
- 之後重新分配之前插入桶中的節點,重分配的方法就是把每個值刪掉,重新插入,因為目錄項已被我們修改,所以插入之後就會得到想要的結果。
- 之後再嘗試插入節點,失敗的話就會到第二步,需要再次分裂
-
我們再講一下剛剛第3步說的不需要分裂的情況,上述過程我們發現複製出來的目錄指標,每次只會重新新增一個桶,所以還有很多指標是指向同一個桶的,那門當我們插入那種桶滿時,可以不要分裂,而是隻新增一個桶即可。
-
步驟有點複雜,我們梳理一下,插入桶->分裂/不分裂->建立新桶->重新分配目錄項->重新分配桶內節點->再次嘗試插入,基本就是這樣,處理好細節即可。
Task2
這部分需要我們實現一個LRU-K演算法的替換器,用於buffer滿時替換frame。
面試常見的LRU演算法一般使用雙連結串列+雜湊的寫法,這裡的LRU-K需要維護兩個序列,雖然也可以使用雙連結串列+雜湊,只需要在中建新增一個哨兵節點即可,效率肯定更高,但為了寫程式碼方便,我直接使用一個雜湊表來實現,建立一個FrameInfo
多記錄一些資訊即可,偷個懶。
LRU-K 演算法相比 LRU 演算法的優勢在於它考慮了元素的使用頻率,從而更加精細地選擇淘汰快取中的元素。
這部分實現非常簡單。
Task3
NewPgImp
- 判斷是否有freelist
- 如果有:則拿出freelist中的新的frameid
- 如果沒有:則判斷是否可以將Pages騰出一頁
- 如果可騰出:則判斷騰出的頁是否為髒頁
- 如果是髒頁:則寫回資料至磁碟,置dirty為false,清空頁memory,將頁的<pageid,frameid>從雜湊表中移除,將頁的lru記錄清除
- 如果不是髒頁:則清空頁memory,將頁的<pageid,frameid>從雜湊表中移除,將頁的lru記錄清除
- 如果不能騰出:返回nullptr
- 如果可騰出:則判斷騰出的頁是否為髒頁
- 記錄這個新頁的訪問記錄,置framei的evict位為false
- 分配新的頁id,將對映關係插入雜湊表
- 設定新頁的後設資料(pgid,pin_count,id_dirty,memory)
FetchPgImp
- 先尋找頁,找到了的話,設定一下replacer_的資訊,還有page的pin_count
- 判斷是否還有空閒頁,如果沒有,換出一個頁並刷髒,清除
page_table_
和replacer_
的記錄,進入下一步;有空閒時拿出空閒頁id進入下一步 - 設定新的
replacer_
和page_table_
記錄,同時呼叫disk_manager從磁碟讀出一個所需頁。
FlushPgImp, FlushAllPgsImp,UnpinPgImp
這三個比較簡單,unpin時記得當pin_count為0時設定頁狀態為Evictable。
DeletePgImp
- pin_count >0時不能刪除
- 髒頁記得刷髒
replacer_
和page_table_
記錄刪除- 呼叫
DeallocatePage
Summary
project1在很久之前就做完了,當時忘記寫部落格了,重新回憶並記錄一下。