15445第一階段筆記+Buffer Pool(2019)
概念
page與frame
? 塊,頁,是對同一概念的不同叫法,取決于場景不同,其表述的都是磁盤上某一柱面上的連續扇區(固定數目),資料在磁盤和緩沖區(記憶體)之間傳輸,傳輸的單位就是塊(頁),
? 記憶體區是以定長的頁陣列的形式組織的,其中每一個陣列條目,被稱為一個幀(frame),當DBMS請求一個頁時,被請求頁的一份拷貝就被讀取進其中一個幀中,
? 所以,page和frame實際是指的是同一個概念,buffer pool中的叫做幀,磁盤與記憶體之間的傳輸單位的叫做page或者block,
page table
? 是一個Page ID到Frame ID的映射,Page ID是磁盤頁的屬性,不同的磁盤頁的Page ID不同,當磁盤頁被讀取進緩沖區時,該磁盤頁會在緩沖區中有一個位置,即Frame ID,緩沖區是Frame的定長陣列,一共只有buffer_pool_size大小的frame,所以,當磁盤頁讀進寫出,會存在不同的磁盤頁先后出現在同一個幀位置的情況,那么這個Page Table,就是保存當前頁ID到幀ID的映射,

page directory
? Page Directory中的每?個小格中包含有對應page所在位置,也包含它剩余空間資訊,通過Page Directory可以將page映射到記憶體或者磁盤上的某個位置
存盤結構
? 總的來說,資料庫內部的存盤結構可以總結為,Page Directory負責映射記憶體或者磁盤中的page,Page Table負責將page映射到buffer pool中的frame中,
? 而page內部的header和slot array來組織tuple存放,以下是page中的結構
? tuple內部的結構也是header+data,
專案
一些注意的地方
clock_replacer
-
replacer是一個定長陣列,但是clock_size不是定長,而是可以被victim的frame的總數,所以replacer實際上存放的是可以被替換的幀,clock_size初始為0,
-
clock_hand是遍歷replacer的指標,只有Victim()函式可以修改clock_hand指標,
buffer_pool_manager
pages_是buffer pool的幀陣列,
函式
clock_replacer
bool Victim(frame_id_t *frame_id)
1.進行回圈遍歷,掃描所有實際存在replacer中的幀,如果沒有可替換幀,則回傳false,
2.只查看實際在replacer中的幀,如果ref為1,則將ref修改為0,clock_hand++,如果ref為0,則將其標記為不在replacer中,clock_size--,并令*frame_id = clock_hand++,將該幀的frame_id傳出去,回傳true,
void Pin(frame_id_t frame_id)
將目標幀標記為不在replacer中,clock_size--,
void Unpin(frame_id_t frame_id)
將目標幀標記為在replacer中,clock_size++,同時將ref標記為true(clock_replacer中新添加幀的ref需標記為true),
buffer_pool_manager
FetchPageImpl(page_id_t page_id)
0.首先用latch上鎖
1.page_table_中是否存在page_id所對應的幀,如果存在,則直接回傳所對應的幀,并需要進行pin操作;若沒有則需要將磁盤中的page讀取到buffer pool中,即讀取到pages_中的一個幀的位置,
2.首先從free_list中尋找空閑幀,如果可以找到空閑幀,則go to 4;如果free_list為空,則呼叫replacer.Victim()獲得可替換幀的victim_frame_id,若沒有可替換幀,則回傳nullptr,
3.檢查victim_frame的臟讀位,如果臟讀位有效,則需要呼叫disk_manager_->WritePage()寫回到磁盤中,
4.進行victim_frame資料的讀取以及元資料的更新操作:
(1)清除victim_frame的頁表中的記錄,
(2)添加victim_frame的page_id到victim_frame_id的新映射,
(3)更新victim_frame(在pages_陣列中)的page_id,
(4)進行victim_frame的pin操作,pin_count++,呼叫者加1,并呼叫replacer_->pin()方法,
(5)victim_frame的臟讀位記為false,
(6)呼叫disk_manager_->ReadPage(page_id, pages_[victim_frame_id].data_),將page的資料讀取到victim_frame中,
5.回傳pages_中victim_frame的地址,
Page* NewPageImpl(page_id_t *page_id)
0.首先用latch上鎖
1.首先從free_list中尋找空閑幀,如果可以找到空閑幀,則go to 3;如果free_list為空,則呼叫replacer.Victim()獲得可用幀的victim_frame_id,若沒有可用幀,則回傳nullptr,
2.檢查victim_frame的臟讀位,如果臟讀位有效,則需要呼叫disk_manager_->WritePage()寫回到磁盤中,
3.呼叫disk_manager_->AllocatePage()分配一個新的頁,記頁ID為page_id,然后進行victim_frame資料的清除以及元資料的更新操作:
(1)清除victim_frame的頁表中的記錄,
(2)添加victim_frame的page_id到victim_frame_id的新映射,
(3)更新pages_陣列中的victim_frame的page_id.
(4)記victim_frame的臟讀位為false
(5)清空victim_frame中的資料
(6)設定victim_frame的pin_count=1
4.回傳pages_中victim_frame的地址
bool DeletePageImpl(page_id_t page_id)
0.首先用latch上鎖
1.在page_table_中查找page_id是否存在對應的frame_id,如果不存在,則直接go to 4,
2.若page_table_[frame_id].pin_count不為0,則回傳false,
3.若目標幀的臟讀位為true,則呼叫disk_manager_->WritePage()將其寫回磁盤,
4.進行目標幀的重置操作:
(1)該目標幀不再進行replacer_->Victim()操作,所以呼叫replacer_->Pin(frame_id),
(2)從page_table_中洗掉page_id的映射
(3)設定目標幀的pin_count=0,is_dirty_=false,data_清空,page_id=INVALID_PAGE_ID,
(4)加入free_list_中,
4.呼叫disk_manager_->DeallocatePage(page_id),回傳true,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/505555.html
標籤:其他
