BusTub


PROJECT #0 - C++ PRIMER

這個Warm-Up主要是要熟悉C++ 17的一些Features,只需要實現p0_starter.h即可;
提交gradescope,要上傳zip文件,但是路徑總是不對,文檔里也說得不明不白,一定要加上路徑名:zip solution.zip src/include/primer/p0_starter.h
unique_ptr擁有對象的獨占權,可以用move將對象的所有權轉移到另一個unique_ptr

第一次提交時有內存安全隱患:
在這里插入圖片描述
網上說可能是valgrind版本過低,用高版本測試后發現沒問題:
在這里插入圖片描述
其實代碼是有bug的,經過測試,發現問題在於實現矩陣乘法時定義了臨時變量double tmp = 0.0

double tmp = 0.0;
for (int k = 0; k < mat1->GetColumns(); ++k) {
  tmp += mat1->GetElem(i, k) * mat2->GetElem(k, j);
}
ans->SetElem(i, j, tmp);

改為:

for (int k = 0; k < mat1->GetColumns(); ++k) {
  ans->SetElem(i, j, ans->GetElem(i, j) + mat1->GetElem(i, k) * mat2->GetElem(k, j));
}

我個人理解是這樣:因為原本代碼中是模板參數T,如果定義double作為臨時變量,測試時用int測試,最終SetElem時要存入double,但是預先分配的內存只有int大小,所以內存溢出報錯。
在這里插入圖片描述

PROJECT #1 - BUFFER POOL MANAGER

整體要為Bustub做一個面向磁盤的存儲管理系統:
在這里插入圖片描述
第一次作業是要實現一個內存緩沖池:負責將物理頁面在磁盤和主存之間移動,這樣DBMS就可以支持比內存更大的數據庫。緩沖池的操作對其它系統部件是透明的,比如系統通過唯一的頁面標識符page_id_t向緩沖池要求訪問頁面,而不管頁面是在內存中還是在磁盤上。

緩沖池的實現必須是線程安全的,多個線程同時訪問時需要用latches保護(OS中叫locks)。
關於DBMS中的🔒:

  • locks:高層次的邏輯原語,在事務的整個執行過程中保護數據庫的內容(元組/表/數據庫),可以rollback
  • latches:低層次的保護原語,DBMS用來保護內部數據結構的安全訪問(hash table, regions of memory),只在某個具體操作時使用,不可以rollback

具體來說:有2部分:LRU替換策略+緩沖池管理

  • LRU
    LRU的實現有多種方式:
    1、數組+時間戳:每次插入新數據項的時候,先把數組中存在的數據項的時間戳自增,並將新數據項的時間戳置為0並插入到數組中。每次訪問數組中的數據項的時候,將被訪問的數據項的時間戳置為0。當數組空間已滿時,將時間戳最大的數據項淘汰。
    2、雙向鏈表:每次新插入數據的時候將新數據插到鏈表的頭部;每次緩存命中(即數據被訪問),則將數據移到鏈表頭部;那么當鏈表滿的時候,就將鏈表尾部的數據丟棄。
    上面兩種復雜度均是O(n)
    3、雙向鏈表+Hash Map:當需要插入新的數據項的時候,如果新數據項在鏈表中存在(一般稱為命中),則把該節點移到鏈表頭部,如果不存在,則新建一個節點,放到鏈表頭部,若緩存滿了,則把鏈表最后一個節點刪除即可。在訪問數據的時候,如果數據項在鏈表中存在,則把該節點移到鏈表頭部,否則返回-1。這樣一來在鏈表尾部的節點就是最近最久未訪問的數據項。本質上是list看作時間戳,hash table記錄元素值到鏈表位置的映射關系,get和put均是O(1)。
  • 緩沖池管理
    緩沖池的組織形式是frame數目固定的數組,訪問時將page從磁盤拷貝到frame。
    與OS內存管理相似,也需要有page table記錄哪些page在buffer pool中,page id -> frame id;page directory記錄了磁盤上的位置,page id -> page locations in disk。
    還需要有dirty位以及pin/ref counter記錄當前正在訪問的線程數目,只有flush或者置換臟頁時才寫回磁盤。
    在這里插入圖片描述
    緩沖池和Replacer的大小是相同的,如果page的ref counter變為0時就可以加入到Replacer中作為替補犧牲頁面。

從緩沖池中根據ID fetch的時候有3種情況:

  1. 如果page在緩沖池,直接返回;
  2. 如果不在,但緩沖池有空閑frame,從磁盤讀取page放入該frame;
  3. 如果不在且緩沖池沒有空閑frame,從buffer中犧牲一頁,從磁盤讀取page放入對應的frame。

第一次提交忘了處理並發問題,只得了65分:
在這里插入圖片描述
加了一些🔒后,還有2個test掛了:
在這里插入圖片描述
isdirty一直過不去,后來在群里看到:只有page當前的臟位是false且傳入is_dirty==true時才需要修改當前的臟位。這里我是這么理解的:如果頁面應該標記為dirty那么傳入的參數就是true:

  • 當前為true && is_dirty==true:頁面修改過,也做了正確標記,不用管;
  • 當前為false && is_dirty==true:頁面其實修改過,但沒有標記,改正;
  • 當前為false && is_dirty==false:頁面沒修改,標記正確,不用管;
  • 當前為true && is_dirty==false:頁面沒修改,標記為修改過,這種也不用管,大不了置換時寫回磁盤耗費些時間。
    在這里插入圖片描述
    數據庫真的太難了,尤其是涉及到並發控制的部分,我真的沒有足夠時間去debug這些,以后有空再繼續做吧。。

PROJECT #2 - B+ TREE

PROJECT #3 - QUERY EXECUTION

PROJECT #4 - CONCURRENCY CONTROL


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



猜您在找
 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM