国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

CMU15445 數據庫系統實驗一:Buffer Pool Manager

運維 數據庫運維
本篇是實驗一,管理文件系統的頁在內存中的緩存 —— buffer pool manager。實驗的目標系統 BusTub 是一個面向磁盤的 DBMS,但磁盤上的數據不支持字節粒度的訪問。

[[382283]]

本文轉載自微信公眾號「分布式點滴」,作者穆尼奧。轉載本文請聯系分布式點滴公眾號。  

本篇是實驗一,管理文件系統的頁在內存中的緩存 —— buffer pool manager。

概覽

實驗的目標系統 BusTub 是一個面向磁盤的 DBMS,但磁盤上的數據不支持字節粒度的訪問。這就需要一個管理頁的中間層,但 Andy Pavlo 教授堅持不使用 mmap 將頁管理權力讓渡給操作系統,因此實驗一 的目標便在于主動管理磁盤中的頁(page)在內存中的緩存,從而,最小化磁盤訪問次數(時間上)、最大化相關數據連續(空間上)。

該實驗可以分解為相對獨立的兩個子任務:

  • 維護替換策略的:LRU replacement policy
  • 管理緩沖池的:buffer pool manager

兩個組件都要求線程安全。

本文首先從基本概念、核心數據流總體分析下實驗內容,然后分別對兩個子任務進行梳理。

作者:青藤木鳥 https://www.qtmuniao.com/2021/02/10/cmu15445-project1-buffer-pool/, 轉載請注明出處

實驗分析

剛開始寫實驗代碼的時候,感覺細節很多,實現時很容易丟三落四。但隨著實現和思考的深入,漸漸摸清了全貌,發現只要明確幾個基本概念和核心數據流,便能夠提綱挈領。

基本概念

buffer pool 的操作的基本單位為一段邏輯連續的字節數組,在磁盤上表現為頁(page),有唯一的標識 page_id;在內存中表現為幀(frame),有唯一的標識 frame_id。為了記下哪些 frame 存的哪些 page,需要使用一個頁表(page table)。

下邊行文可能會混用 page 和 frame,因為這兩個概念都是 buffer pool 管理數據的基本單位,一般為 4k,其區別如下:

page id 是這一段單位數據的全局標識,而 frame id 只是在內存池(frame 數組)中索引某個 page 下標

page 在文件系統中是一段邏輯連續的字節數組;在內存中,我們會給其附加一些元信息:pin_count_,is_dirty_


 

 

基本概念

而管理幀的內存池大小一般來說是遠小于磁盤的,因此在內存池滿了后,再從磁盤加載新的頁到內存池,需要 某種替換策略(replacer)將一些不再使用的頁踢出內存池以騰出空間。

核心數據流

先說結論,buffer pool manager 的實現核心,在于對內存池中所有 frame 的狀態的管理。因此,如果我們能梳理出 frame 的狀態機,便可以把握好核心數據流。

buffer pool 維護了一個 frame 數組,每個 frame 有三種狀態:

  1. free:初始狀態,沒有存放任何 page
  2. pinned:存放了 thread 正在使用的 page
  3. unpinned:存放了 page,但 page 已經不再為任何 thread 所使用

而待實現函數:

  1. FetchPageImpl(page_id) 
  2. NewPageImpl(page_id) 
  3. UnpinPageImpl(page_id, is_dirty) 
  4. DeletePageImpl(page_id) 

便是驅動狀態機中上述狀態發生改變的動作(action),狀態機如下:


 

 

frame 狀態機

對應到實現時數據結構上:

  1. 保存 page 數據的 frame 數組為 pages_
  2. 所有 free frame 的索引(frame_id)保存在 free_list_ 中
  3. 所有 unpinned frame 的索引保存在 replacer_ 中
  4. 所有 pinned frame 索引和 unpinned frame 的索引保存在 page_table_ 中,并通過 page 中 pin_count_ 字段來區分兩個狀態。

上圖中,NewPage1 和 NewPage2 表示在 NewPage 函數中,每次獲取空閑 frame 時,會先去空閑列表(freelist_)中取一個 free frame,如果取不到,才會去 replacer_ 中驅逐一個 unpinned 的 frame 后使用。這體現了 buffer pool manager 實現的一個目標:最小化磁盤訪問,原因后面分析。

實驗組件

把握了本實驗的基本概念和核心數據流后,再來分析兩個子任務。

TASK #1 - LRU REPLACEMENT POLICY

以前在 LeetCode 上寫過相關實現,因此很自然的帶入之前經驗,但隨后發現這兩個接口有一些不同。

LeetCode 上提供的是 kv store 接口,在 get/set 的時候完成新老順序的維護,并在內存池滿后自動替換最老的 KV。

但本實驗提供的是 replacer 接口,維護一個 unpinned 的 frame_id 列表 ,在調用 Unpin 時將 frame_id 加入列表并維護新老順序、在調用 Pin 時將 frame_id 從列表中摘除、在調用Victim 的時候將最老的 frame_id 返回。

當然,本質上還是一樣,因此本實驗我也是采用 unordered_map 和 doubly linked list 的數據結構,實現細節不再贅述。需要注意的是,如果 Unpin 時發現 frame_id 已經在 replacer 中,則直接返回,并不改變列表的新老順序。因為邏輯上來說,同一個 frame_id,并不能被 Unpin多次,因此我們只需要考慮 frame_id 第一次 Unpin。

放到更大的語境中,本質上,replacer 就是一個維護了回收順序的回收站,即我們將所有 pin_count_ = 0 的 page 不直接從內存中刪除,而是放入回收站中。根據數據訪問的時間局部性原理,剛剛被訪問的 page 很可能再次被訪問,因此當我們不得不從回收站中真刪(Victim)一個 frame 時,需要刪最老的 frame。當之后我們想訪問一個剛加入回收站的數據時, 只需要將 page 從這個回收站中撈出來,從而省去一次磁盤訪問,這也就達到了最小化磁盤訪問的目標。

TASK #2 - BUFFER POOL MANAGER

在實驗分析部分已經把核心邏輯說的差不多了,這里簡單羅列一下我實現中遇到的問題。

page_table_ 的范圍。在最初實現時,畫出 frame 的狀態機之后,感覺 page_table_ 中只放 pinned frame id 很完美:可以使 frame id 按狀態互斥的分布在 free_list_ 、 replacer_ 和 page_table_ 中。但后來發現,如果不將 unpinned frame id 保存在 page_table_ 中,就不能很好地復用 pin_count_ = 0 的 page 了,replacer 也就沒有了意義。

dirty page 的刷盤時機。有兩種策略,一種是每次 Unpin 的時候都刷,這樣會刷比較頻繁,但能保證異常掉電重啟后內容不丟;一種是在 replacer victimized 的時候 lazily 的刷,這樣能保證刷的次數最少。這是性能和可靠性取舍,僅考慮本實驗,兩者肯定都能過。

NewPage 不要讀盤。這個就是我寫的 bug 了,畢竟 NewPage 的時候,磁盤上根本沒有對應 page 的內容,因此會報如下錯誤:

  1. 2021-02-18 16:53:47 [autograder/bustub/src/storage/disk/disk_manager.cpp:121:ReadPage] DEBUG - Read less than a page 
  2. 2021-02-18 16:53:47 [autograder/bustub/src/storage/disk/disk_manager.cpp:108:ReadPage] DEBUG - I/O error reading past end of file 

復用 frame 時清空元信息。在復用一個從 replacer 中驅逐的 frame 時尤其要注意,使用前一定要將 pin_count_\is_dirty_ 這些字段清空。當然,在 DeletePage 的時候,也需要注意將 page_id_ 置為 INVALID_PAGE_ID 、清空上述字段。否則,再次使用時, 如果 pin_count_ 在 Unpin 后,數值不為 0,會導致 DeletePage 時刪不掉該 page。

鎖的粒度。最粗暴的就是每個函數范圍粒度加鎖即可,后期如果需要優化,再將鎖的粒度變細。

實驗代碼

以 FetchPageImpl 為例強調下一些實現的細節,注意到,實驗已經通過注釋給出了實現框架。

我使用中文注釋注出了一些我認為需要注意的點。

  1. Page *BufferPoolManager::FetchPageImpl(page_id_t page_id) { 
  2.   // a. 使用自動獲取和釋放鎖 
  3.   std::scoped_lock<std::mutex> lock(latch_); 
  4.    
  5.   // 1.     Search the page table for the requested page (P). 
  6.   // 1.1    If P exists, pin it and return it immediately. 
  7.   auto target = page_table_.find(page_id); // b. 判斷存在與訪問數據只用一次查找 
  8.   if (target != page_table_.end()) { 
  9.     frame_id_t frame_id = target->second
  10.     // c. 通過指針運算獲取 frame_id 處存放的 Page 結構體 
  11.     Page *p = pages_ + frame_id;  
  12.     p->pin_count_++; 
  13.     replacer_->Pin(frame_id); // d. 將對應 page 從“回收站”中撈出 
  14.     return p; 
  15.   } 
  16.  
  17.   // 1.2    If P does not exist, find a replacement page (R) from either the free list or the replacer. 
  18.   //        Note that pages are always found from the free list first
  19.   frame_id_t frame_id = -1;  
  20.   Page *p = nullptr; 
  21.   if (!free_list_.empty()) { 
  22.     frame_id = free_list_.back(); // e. 在結尾處操作效率高一點 
  23.     free_list_.pop_back(); 
  24.     assert(frame_id >= 0 && frame_id < static_cast<int>(pool_size_)); 
  25.     p = pages_ + frame_id; 
  26.      
  27.     // f. 從 freelist 中獲取的 dirty page 已經在 delete 時寫回了 
  28.   } else { 
  29.     bool victimized = replacer_->Victim(&frame_id); 
  30.     if (!victimized) { 
  31.       return nullptr; 
  32.     } 
  33.     assert(frame_id >= 0 && frame_id < static_cast<int>(pool_size_)); 
  34.     p = pages_ + frame_id; 
  35.  
  36.     // 2.     If R is dirty, write it back to the disk. 
  37.     if (p->IsDirty()) { 
  38.       disk_manager_->WritePage(p->GetPageId(), p->GetData()); 
  39.       p->is_dirty_ = false
  40.     } 
  41.     p->pin_count_ = 0; // g. 將元信息 pin_count_ 清空 
  42.   } 
  43.  
  44.   // 3.     Delete R from the page table and insert P. 
  45.   page_table_.erase(p->GetPageId()); // h. 時刻注意區分 p->GetPageId() 與 page_id 是否相等,別混用 
  46.   page_table_[page_id] = frame_id; 
  47.  
  48.   // 4.     Update P's metadata, read in the page content from disk, and then return a pointer to P. 
  49.   p->page_id_ = page_id; 
  50.   p->ResetMemory(); 
  51.   disk_manager_->ReadPage(page_id, p->GetData()); 
  52.   p->pin_count_++; 
  53.   return p; 

實驗相關 autograder 可以在 FAQ 中找到注冊地址和邀請碼,提交代碼的時候最好不要提交 github 倉庫地址,會有很多格式問題??梢悦看伟凑諏嶒烅撁娴闹甘?,將相關文件按目錄結構達成 zip 包提交即可。

 

提交事項

仔細閱讀實驗描述,提交前需要注意的事項:

  1. 在 build 目錄運行 make format ,自動格式化。
  2. 在 build 目錄運行 make check-lint,檢查一些語法問題。
  3. 自己針對每個函數在本地設計一些測試,寫到相關文件(本實驗 buffer_pool_manager_test.cpp )中,并且打開測試開關,在 build 文件夾下,編譯 make buffer_pool_manager_test,運行 ./test/buffer_pool_manager_test

貼一個 project1 autograder 的實驗結果:

 

autograder 結果

小結

這是 cmu15445 第一個實驗,實現了在磁盤和內存間按需搬運頁(page)的 buffer pool manager。本實驗的關鍵之處在于把握基本概念,梳理出核心數據流,在此基礎上注意一些實現的細節即可。

責任編輯:武曉燕 來源: 分布式點滴
相關推薦

2022-10-12 08:52:00

內存緩沖管理

2022-10-09 08:53:06

存儲容量SSD

2025-08-11 02:00:00

2022-10-08 00:00:00

SQLDDL數據

2025-08-04 06:00:00

2022-10-17 08:49:47

2022-10-30 10:03:20

B+數據庫數據

2022-09-30 11:08:44

MySQLPostgreSQLOracle

2025-08-12 07:31:11

2025-08-11 02:25:00

數據庫數據模型

2025-08-08 07:37:07

2025-08-06 00:00:00

2025-08-11 07:31:40

2011-04-13 15:07:30

數據庫系統設計

2011-04-13 15:25:12

數據庫系統設計

2025-08-18 07:32:23

2025-08-21 06:39:13

2022-04-05 13:46:21

日志數據庫系統

2025-08-06 01:22:00

2025-08-04 07:31:30

點贊
收藏

51CTO技術棧公眾號

欧美日本乱大交xxxxx| 三上悠亚国产精品一区二区三区| 日皮视频在线观看| 国产精品原创视频| 在线观看亚洲精品| 在线播放国产区| 欧美性猛交xxxxxxxx| 国产国语**毛片高清视频| 综合毛片免费视频| 日韩一区二区电影| 欧美aaa免费| 一本大道久久精品懂色aⅴ| 成人黄色短视频在线观看| av在线app| 欧美电影影音先锋| 日本国产在线| 精品一区二区国语对白| 欧美日韩视频专区在线播放| 国产一区 在线播放| 久久电影院7| 成人无号精品一区二区三区| 在线成人动漫av| 亚洲第一精品久久忘忧草社区| 中文久久久久久| 黄色成人精品网站| 国产精品中文欧美| 久久久亚洲综合网站| 在线xxxx| 久久免费美女视频| 欧美一区免费视频| 香蕉久久精品日日躁夜夜躁| 国产一区二区三区高清在线观看| 香蕉视频在线免费看| 色综合导航网站| 欧美寡妇性猛交xxx免费| 亚洲最新av网址| 导航福利在线| 亚洲一区二区电影| 中文日韩欧美| 国产日韩亚洲欧美综合| 国产一区二区三区在线播放免费观看| 久久成人精品视频| 欧美日韩国产综合视频在线| 高清免费电影在线观看| 亚洲乱码视频| 欧美香蕉大胸在线视频观看| 国产精品亚洲自拍| av超碰在线观看| 精品产国自在拍| 亚洲色图视频网站| 国产成人精品免高潮费视频| 91国在线高清视频| 日韩精品av| 久久久久国产精品人| 欧美成人在线直播| 97欧美精品一区二区三区| 老司机aⅴ毛片免费观看| 亚洲熟妇av日韩熟妇在线 | 亚洲www在线| av在线1区2区| 国产精品18久久久久久久网站| 日韩av在线高清| 成人性做爰片免费视频| 欧美极品免费| 五月天激情小说综合| 国产欧美精品一区二区三区-老狼| 狠狠v欧美ⅴ日韩v亚洲v大胸| 欧美激情综合色综合啪啪| 欧美日韩亚洲激情| 日本一区高清不卡| 免费观看羞羞视频网站| 性色av一区| 中文字幕中文字幕一区二区| 午夜精品福利一区二区| 国产女主播一区| 超碰porn在线| 久久人人爽人人爽人人片av高清| 欧美黄色aaaa| 欧美aⅴ在线观看| 欧美日韩一区小说| 久久97精品| 欧美另类videos| 色欧美片视频在线观看在线视频| 九色porny自拍视频在线播放| 国产欧美欧洲在线观看| 成人手机在线视频| 国产在线观看a| 成人h猎奇视频网站| 成人精品一区二区三区中文字幕| 成年人在线看| 91精品国产乱码久久久久久蜜臀| 奇米综合一区二区三区精品视频| 自拍偷拍电影| 欧美巨猛xxxx猛交黑人97人| 久久性天堂网| 一级毛片在线视频| 欧美国产亚洲视频| 国产精品夜夜嗨| 操你啦视频在线| 成人久久精品视频| 亚洲天堂a在线| 日本午夜免费一区二区| 欧美日韩亚洲免费| 午夜伦欧美伦电影理论片| jizz性欧美2| 亚洲人精品午夜射精日韩| 欧美成人aa大片| 婷婷亚洲图片| 色琪琪免费视频网站| 久久久爽爽爽美女图片| caoporm超碰国产精品| sm久久捆绑调教精品一区| 激情一区二区三区| 富二代精品短视频| 欧美亚洲国产精品久久| 超碰色偷偷男人的天堂| 欧美极品少妇xxxxx| 2020国产精品自拍| 久久天天久久| 日韩欧美国产免费| www.国产精品一二区| 国产+成+人+亚洲欧洲自线| av漫画网站在线观看| 欧美一区二区综合| 日韩欧美自拍偷拍| 日本不卡视频在线| 高清在线视频不卡| 最近中文字幕免费mv| 精品国产免费一区二区三区四区 | 日韩欧美在线电影| 欧美日韩国产小视频| 欧美精品99| a视频网址在线观看| 国产精品乱码视频| 欧美日韩一区二区三区免费看 | 精品国产丝袜高跟鞋| 亚洲在线观看视频| 欧美在线色视频| 99精品久久| av不卡高清| 一区二区国产日产| 亚洲男人天堂视频| 播五月开心婷婷综合| 国产精品亚洲四区在线观看| 国产xxxxx在线观看| 国内精品久久久久久久久| 一区二区三区不卡视频| 在线中文字幕第一区| yiren22综合网成人| 奇米影视首页 狠狠色丁香婷婷久久综合 | 每日更新成人在线视频| 国产在线电影| 狠狠综合久久av| 日韩精品福利在线| 不卡视频一二三四| 国产主播性色av福利精品一区| 国产真实伦在线观看| 999热视频| 亚洲激情视频在线| 久久先锋影音av鲁色资源| 尤物tv在线精品| 一级毛片视频在线| 欧美少妇一区二区三区| 久久久久久欧美| 在线一区二区观看| 国产真实乱子伦精品视频| 涩涩屋成人免费视频软件| 一二三四在线视频观看社区| 久久精品美女| 欧美xxxx18国产| 色系网站成人免费| 国内一区二区在线| 夜夜春成人影院| 欧美黑人猛交| 97视频免费| 久久视频在线观看中文字幕| 中文字幕亚洲激情| 婷婷久久综合九色综合绿巨人 | 高清电影在线免费观看| 国产真人做爰毛片视频直播| 国产精品99久久久久久人 | 男人天堂免费视频| 亚洲精品在线观看免费| 午夜剧场成人观在线视频免费观看| 色欧美日韩亚洲| a在线欧美一区| 91久久夜色精品国产按摩| 成人影院入口| 在线观看免费av网| 阿v天堂2018| 成人黄动漫网站免费| www国产精品com| 欧美日韩国产a| 中文字幕av一区二区三区高 | 不卡视频免费播放| 国内自拍一区| 欧美三级一区| 色呦呦在线免费观看| 一二三四中文在线| 欧美一区二区中文字幕|