CMU15445-2024fall-project1踩坑經歷

p1目錄:

  • lRU\_K替換策略
    • LRU
    • LRU\_K
    • 大體思路
      • SetEvictable
      • RecordAccess
      • Size
      • Evict
      • Remove
  • Disk Scheduler
  • BufferPool
    • NewPage
    • DeletePage
    • FlashPage/FlashAllPage
    • CheckReadPage/CheckWritePage
      • PageGuard
      • 并發設計
      • 主邏輯

感謝CMU的教授們給我們分享了如此精彩的一門課程, 希望您能尊重教授們和TAs的勞動成果!

本篇文章記錄本人對實驗中各個板塊的理解以及踩坑, 如果您發現我過多的涉及到了實驗的內容, 有違學術誠信, 請告訴我!

正文:

Project1要實現的是一個Buffer pool Manager。 Buffer pool Manager的作用是能夠對磁盤中的數據進行預緩存。 數據庫的數據是保存在磁盤中的, 要對其中的數據進行處理, 就要將磁盤的數據加載到內存中, 但是如果當每次要用這個數據的時候再從磁盤中取出, 那么就會消耗大量的時間。 Buffer Pool Manager的作用就是預先從磁盤中將數據取出來, 當需要使用到時候再把數據從內存中直接提取使用。

在本project中, 我們要實現三個組件:

  • lru_k替換策略

  • Disk Scheduler 磁盤管理器

  • Buffer pool Manager 緩沖池管理器。

lRU_K替換策略

Buffer pool manager通過lru_k的替換策略來替換掉緩沖池中的不常用頁面。 這個lru_k的替換策略類似于操作系統中的三大調度算法 —— 進程替換、頁面置換、 磁盤調度算法。

為了解釋lru_k, 這里用lru進行輔助理解。 下面是兩者的執行策略和思想:

LRU

  • 執行策略:選擇最長時間沒有被使用過的頁面進行替換。
  • 思想:過去訪問頻繁的頁面, 未來也會頻繁訪問;過去訪問最少的頁面, 未來也會很少訪問。

如果兩個數據的訪問次數相同, 那么刪除訪問時間最早的那一個。 或者說是訪問時間距離現在最遠的那一個。

LRU_K

  • 執行策略: 設置一個k, 然后規定一個后向距離k, 刪除后向距離k最大的節點。

    • 在這里插入圖片描述

    • 后向距離k的計算方式為(除紅框框外的論述):
      
    • 當節點被訪問的次數大于等于k:k = 當前時間戳 - 第前k次訪問該節點時的時間;

      • 比如當前時間戳為1000, k為3。有節點1、節點2。其中節點1的訪問次數為4, 訪問時間戳依次為:100, 200, 300, 400; 節點2的訪問次數為5, 訪問時間戳依次為:10, 20, 50, 800, 900。那么對于節點1的后向k為: 1000 - 200 = 800。 節點2的后向k為: 1000 - 50 = 950。 所以刪除節點2。
    • 當節點被訪問的次數小于k:k = +inf, 如果兩個節點的訪問次數均小于k, 那么會刪除第一次時間戳距離當前時間戳最久的節點。

        • 對于當訪問次數小于k的時候我之前也有過疑問, 文檔中寫的意思按照我的理解是:刪除節點中最近訪問的時間戳最小的節點, 但是我這么寫線上測試沒過。 所以這里的節點訪問次數小于k應該是對于最早的一次訪問的時間戳與當前時間戳的比較。
    • 綜上lru_k的策略其實很簡單: 就是如果有訪問次數小于k的節點,優先刪除訪問節點小于k的, 如果存在多個這樣的節點, 那么就刪除第一次訪問的時間戳最早的節點。 如果沒有訪問次數小于k的節點, 那么計算后向k距離, 刪除后向k距離最大的節點。

大體思路

LRU_K的代碼集中在了lru_k_replacer.h和cpp文件中。您可以閱讀lru_k_replacer.h中的注釋和類的定義來獲取實現所需要的各種信息。

在這里插入圖片描述

(上圖為官方倉庫)LRUKNode是lru_k中的節點。根據注釋的描述, histroy_用來存儲訪問的timestamps(時間戳)、k_為規定的k、 fid_為與當前節點綁定的緩沖池中的頁面id、is_evicatable_為當前頁面是否可以被刪除。

另外, 在該項目中, 我們的變量如果定義后沒有使用, 編譯是會報錯的, 所以請將不使用的變量刪掉或者不確定使用可以加[[maybe_unused]]修飾。

在這里插入圖片描述

(上圖為官方倉庫)LRUKReplacer是lru_k數據結構, 作為移除器使用。 這里面可能有一些我們可能需要的屬性以及要實現的方法。

SetEvictable

修改指定的lru_k節點是否可以刪除。 可以為true, 否則為false。需要注意同時修改lru_k移除器中的可移除節點的數量。

RecordAccess

頁面被訪問時調用, 更新頁面對應節點的使用情況。先查找lru_k移除器有沒有維護該頁面。 如果沒有, 則添加維護信息; 如果已經維護, 添加時間戳, 同時全局時間戳要增加。

Size

返回移除器中可移除節點的數量。

Evict

lru_k板塊的核心。 找出要移除的節點。 大體思路就是設置一個指向刪除節點的標記位。遍歷所有可移除節點, 計算后向k距離, 與被標記的節點對比。 如果兩個后向k都為inf, 標記兩者中最小時間戳更小的那一個; 如果其中一個inf, 標記該節點。 如果兩個都不為inf, 標記后向k更大的。

Remove

Remove也是移除某個節點。 不同的是, 它是指定某個可移除幀, 確定該幀要被刪除。而Evict是從可以出幀中選出一個不常用的刪除。 Remove面向外部的 “我要刪除特定的幀”; Evict面向外部的"我需要一個幀”。

Disk Scheduler

這部分記不太清了, 印象中實現起來很簡單。 難點是要使用C++17的語法promise 和 future, 學習一下新語法就可以通過了。

BufferPool

實現BufferPool, 其實就是實現PageGuard的創建和刪除, 在該組件中, 核心的功能就是 創建新頁面、從磁盤讀取頁面、刪除頁面, 將頁面刷新到磁盤。

NewPage

NewPage, 即創建新頁面。 就是在磁盤中創建新的頁面。 注意!不是將頁面放到緩沖池的frames中, 而是直接在磁盤上創建一個頁面, 無需讀取到frames。利用DiskScheduler的函數。

DeletePage

刪除頁面的操作,這個刪除是在磁盤中刪除, 而不是只從緩沖池中刪除。如果目標頁面在緩沖池的幀中, 那么刷新到磁盤, 再從磁盤中刪除。 注意:只從緩沖池刪除p1不會測試出現問題, 但是在p3的外排序任務中需要檢測磁盤的刷新和加載。

FlashPage/FlashAllPage

將頁面刷新到磁盤。(刷新磁盤的操作都是使用Disk Scheduler中的刷新函數)

CheckReadPage/CheckWritePage

p1的核心, 最難的地方。 需要理解pin_count的增加和減少的時機、SetEvict的時機;以及大鎖(整個BufferPool的鎖)和小鎖(單個頁面的讀寫鎖) 的獲取與釋放的時機。

我們下面就先討論并發設計:

PageGuard

對于CheckReadPage和CheckWritePage, 他們兩個獲取的是指定page_id的PageGuard。 這個PageGuard, 可以理解為BufferPool內frame幀的RAII管理器。 創建ReadPageGuard的時候, 會增加幀的引用計數, 修改幀的lru_k屬性, 同時也會獲取幀的讀鎖, 此時如果獲取了讀鎖, 那么別的線程再獲取寫鎖,即WritePageGuard, 就會阻塞;創建WritePageGuard的時候, 同樣也會增加幀的引用計數, 修改幀的lru_k屬性, 同時也會獲取幀的寫鎖, 此時如果獲取了寫鎖, 那么別的線程再獲取ReadPageGuard或者WritePageGuard, 就會阻塞。

當ReadPageGuard釋放的時候, 會減少幀的引用計數, 修改幀的lru_k屬性, 同時會釋放讀鎖,銷毀資源; 當WritePageGuard釋放的時候, 同樣會減少幀的引用計數, 修改幀的lru_k屬性, 同時會釋放寫鎖。

以上就是PageGuard的理解。

并發設計

并發設計要保證三個順序:

  • 當獲取和釋放PageGuard的時候, 對于讀寫鎖和pin_count,我們要保證一個順序:pin->lock->unlock->unpin。

    • 大概的主要原因是因為如果lock->pin, 那么在線程獲取小鎖被鎖住后,該頁面的pin_count只有1, 如果持有頁面的線程釋放該頁面, 在lock -> pin + SetEvict()中間的空擋, 該頁面可能會被設置為可移除,進而被刷新回磁盤。那么線程再lock, lock的是什么? 我們要知道, lock是frame幀里面的成員, 作用是鎖住該幀。 而如果原本的頁面被替換成別的頁面, 那么此時lock,鎖住的就不是原本的頁面, 而是新替換來的頁面了, 與預期結果不符, 程序出錯。(TODO。這里不太懂,可能就是先 lock再pin會導致頁面被刷新替換, 導致lock了自己不想要的頁面,導致邏輯錯誤。)
  • 保證獲取小鎖之前要將大鎖釋放掉。在本地測試的DeadLockTest有下面這種情況:

    • 線程TA想要獲取頁面A, 所以進入CheckPage函數, 獲取了大鎖, 然后創建頁面A的PageGuard獲取頁面A的小鎖。退出CheckPage函數釋放大鎖。
    • 此時線程TB也想要獲取頁面A, 所以進入CheckPage函數, 獲取了大鎖, 然后創建頁面A的PageGuard時因為A的鎖被占用, 所以阻塞。 此時TB占據著大鎖阻塞。
    • 如果此時TA想要再獲取任何一個頁面, 都要進入CheckPage函數獲取大鎖, 但是大鎖被TB占用, 就形成了一種情況:TA占據著頁面A的小鎖, 想要獲取TB占用的的大鎖; TB占據著大鎖, 想要獲取TA占用的小鎖。 形成死鎖。
    • 所以我們要確保TB在阻塞之前把大鎖釋放掉。 但是這樣我們必須說服自己一件事, 就是這樣做可能導致插隊,此時執行會不會不符合預期?
    • 如果TA和TB兩個獲取不同的頁面PageGuard那么不會造成插隊情況, TA獲取頁面A的PageGuard之前釋放大鎖, TB進入獲取TB的PageGuard。兩個線程針對不同的frame,即BufferPool中不同的內存塊。互相不干預, 而且因為減少了鎖粒度,可以讓并發更快。
    • 如果TA和TB獲取相同的頁面, TA獲取頁面A的PageGuard,在獲取小鎖之前釋放大鎖;TA剛剛釋放大鎖, 此時一個TB速度極快, 迅速獲取大鎖, 然后搶在TA之前獲取小鎖。
    • 如果TA和TB獲取的都是讀鎖, 那么不沖突, 兩者都可以獲取到頁面A的小鎖。
    • 如果TA獲取讀鎖, TB獲取寫鎖。或者TA獲取寫鎖, TB獲取讀鎖。 那么TA會被插隊, TB會成功獲取到頁面A。 此時的結果相當于TB獲取到頁面A后,TA才執行。頁面A此時pin_count為二,TBpin了一次, TApin了一次,并且頁面A的可移除狀態為false。 結果在可接受范圍之內。
  • 保證pin/unpin和SetEvictable()被綁定為原子。 即兩個操作一定是在一起,原子的。所以要保證pin和SetEvictable()以及unpin 和SetEvictable()是在大鎖的保護下。 因為如果pin和SetEvictable不被綁定為原子操作,就會出現以下這種情況:

    • 對于頁面A,線程A本來持有該頁面。然后 線程Aunlock->unpin->pin_count == 0。 線程A想要進入SetEvictable。
    • 此時另一個線程B在正在獲取頁面A, 并且執行速度非常快。 很快就pin->pin_count == 1了。然后比線程A更快進入SetEvictable, 修改了頁面的狀態變成”不可移除“。
    • 最后線程A才進入SetEvictable修改頁面變成”可移除“。程序出錯。

所以要保證pin和unpin都是在鎖保護下的,我們就可以在這里使用大鎖進行保護。 即 獲取大鎖->pin->釋放大鎖->lock->unlock->獲取大鎖->unpin->釋放大鎖。

主邏輯

注釋中給出的解釋非常清楚,為了節省看文章的時間, 這里直接說這段注釋的意思:

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

意思概括起來大概就是說:

  • 其中一種情況是無需IO, 也就是說此時頁面就在內存中。(即幀中)
  • 第二種情況是內存夠用。(即幀有空閑位)
  • 第三種情況是頁面既沒在內存中, 內存也不夠用了, 此時需要使用頁面置換算法, 替換不常用頁面。

情況一直接查找,如果在頁面中, 更新lru_k時間戳獲取頁面就行了。

情況二查找不在頁面,但是有空閑, 那么直接從磁盤拿頁面,設置 幀的頁面id , 維護緩沖池內部 頁面管理表(page_table_) ,添加頁面到lru_k替換器。

情況三查找不在頁面, 并且沒有空閑。 要先使用Evict查找最少使用頁面并從lru_k替換器中移除,從幀中移除之前先將頁面數據刷新到磁盤, 然后再替換新的頁面進入該幀, 設置 幀的頁面id , 維護緩沖池內部 頁面管理表(page_table_) , 添加新頁面到lru_K替換器。

以上。暫時先寫成這樣。
參考文章:

https://zhuanlan.zhihu.com/p/828933572

https://blog.csdn.net/John_Snowww/article/details/145908700

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88570.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88570.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88570.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【C語言進階】帶你由淺入深了解指針【第四期】:數組指針的應用、介紹函數指針

前言上一期講了數組指針的原理,這一期接著上一期講述數組指針的應用以及數組參數、函數參數。首先看下面的代碼進行上一期內容的復習,pc應該是什么類型?char* arr[5] {0}; xxx pc &arr;分析:①首先判斷arr是一個數組&#x…

在HTML中CSS三種使用方式

一、行內樣式在標簽<>中輸入style "屬性&#xff1a;屬性值;"。(中等使用頻率)不利于CSS樣式的復用&#xff1b;違背了CSS內容和樣式分離的設計理念&#xff0c;后期難以維護。<p style"color: red">這是div中的p元素</p>二、內部樣式在…

汽車功能安全-軟件單元驗證 (Software Unit Verification)【用例導出方法、輸出物】8

文章目錄1 軟件單元驗證用例導出方法2 測試用例完整性度量標準3 驗證環境要求4 軟件單元驗證的工作產品1 軟件單元驗證用例導出方法 為確保軟件單元測試的測試案例規范符合9.4.2要求&#xff0c;應通過表8所列方法開發測試用例。 表8 軟件單元測試用例的得出方法&#xff1a; …

MySQL內置函數(8)

文章目錄前言一、日期函數二、字符串函數三、數學函數四、其它函數總結前言 其實在之前的幾篇中我們也用到了內置函數&#xff0c;現在我們再來系統學習一下它&#xff01; 一、日期函數 函數名稱描述current_date()獲取當前日期current_time()獲取當前時間current_timestamp(…

蒼穹外賣項目日記(day04)

蒼穹外賣|項目日記(day04) 前言: 今天主要是接口開發, 涉及的新東西不多, 需要注意的只有多表聯查和修改的邏輯,今日難點: 1.菜品的停起售狀態設置 2.套餐的停起售狀態設置 3.動態sql中的 useGeneratedKeys 與 keyProperty 兩個參數 一. 菜品的停起售狀態設置 ? 在菜品的停售中…

React之旅-05 List Key

每個React的初學者&#xff0c;在調試程序時&#xff0c;都會遇到這樣的警告&#xff1a;Warning: Each child in a list should have a unique "key" prop. 如下面的代碼&#xff1a; const list [Learn React, Learn GraphQL];const ListWithoutKey () > (&l…

[特殊字符] 人工智能技術全景:從基礎理論到前沿應用的深度解析

&#x1f680; 人工智能技術全景&#xff1a;從基礎理論到前沿應用的深度解析 在這個AI驅動的時代&#xff0c;理解人工智能的核心技術和應用場景已成為技術人員的必備技能。本文將帶你深入探索AI的發展脈絡、核心技術差異以及在各行業的創新應用。 文章目錄&#x1f680; 人工…

Go語言教程-環境搭建

前言 Go&#xff08;又稱 Golang&#xff09;是由 Google 開發的一種 開源、靜態類型、編譯型 編程語言&#xff0c;于 2009 年正式發布。它旨在解決現代軟件開發中的高并發、高性能和可維護性問題&#xff0c;尤其適合 云計算、微服務、分布式系統 等領域。 Go 語言國際官網…

windows指定某node及npm版本下載

下載并安裝 nvm-windowshttps://github.com/coreybutler/nvm-windows/releases&#xff08;選擇 nvm-setup.zip&#xff09;。打開命令提示符&#xff08;管理員權限&#xff09;&#xff0c;安裝 Node.js v16.15.0&#xff1a; nvm install 16.15.0 nvm use 16.15.0 驗證node版…

每天一個前端小知識 Day 28 - Web Workers / 多線程模型在前端中的應用實踐

Web Workers / 多線程模型在前端中的應用實踐&#x1f9e0; 一、為什么前端需要多線程&#xff1f; 單線程 JS 的瓶頸&#xff1a;瀏覽器主線程不僅負責執行 JS&#xff0c;還要負責&#xff1a; UI 渲染&#xff08;DOM/CSS&#xff09;用戶事件處理&#xff08;點擊、輸入&am…

python:ImportError: cannot import name ‘ParameterSource‘ from ‘click.core‘

瀏覽器訪問網站拋錯&#xff1a;ImportError: cannot import name ParameterSource from click.core (E:\environment\python\Lib\site-packages\click\core.py)問題分析&#xff1a;1. click 版本問題ParameterSource 可能是在某個特定版本的 click 庫中引入的&#xff0c;而你…

flink 去重

LOCALTIMESTAMP as time_stamp ts as case when time is null then CURRENT_TIMESTAMP else TO_TIMESTAMP_LTZ(time, 0) end , watermark for ts as ts - interval ‘60’ second PARTITION BY 的都有回撤流 group by 的沒有回撤流 因為算的是指標 開窗又慢 SELECT * FROM (…

【音視頻】TS協議解析

參考博客&#xff1a;https://blog.csdn.net/rell336/article/details/38109621?utm_mediumdistribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_sourcedistribute.pc_relevant_t0.none-task-blog-BlogCommendFromMac…

uniapp 日期組件可選擇年月

month-picker 月份選擇器組件 組件介紹 month-picker 是一個用于選擇年月的自定義組件&#xff0c;基于 uni-app 開發&#xff0c;提供了簡潔的月份選擇功能。 解決彈框底部出現底部頁面區域 safe-area屬性設為true時&#xff0c;即可解決這個問題效果如圖功能特點 支持選擇年份…

從真人到數字分身:3D人臉掃描設備在高校數字人建模教學中的應用

在影視、動漫、游戲等數字創意產業蓬勃發展的當下&#xff0c;超寫實虛擬數字人憑借其高度逼真的形象&#xff0c;成為行業關注的焦點。無論是影視特效中栩栩如生的角色&#xff0c;還是游戲里精致的NPC&#xff0c;超寫實虛擬數字人的制作都離不開先進的技術支撐。而3D人臉掃描…

你以為大數據只是存?其實真正的“寶藏”藏在這招里——數據挖掘!

你以為大數據只是存&#xff1f;其實真正的“寶藏”藏在這招里——數據挖掘&#xff01; 曾經我也天真地以為&#xff0c;搞大數據就是會寫幾個SQL、部署個Hadoop集群&#xff0c;結果真到項目現場&#xff0c;甲方爸爸一句&#xff1a;“給我挖掘一下用戶的購買意圖”&#xf…

LeetCode經典題解:128、最長連續序列

“最長連續序列”是一道極具代表性的數組處理問題&#xff0c; 本文將帶你從直觀思路出發&#xff0c;逐步推導出最優解法&#xff0c;并通過場景化記憶技巧掌握核心邏輯。 一、題目描述 題目&#xff1a;給定一個未排序的整數數組 nums&#xff0c;找出數字連續的最長序列&…

電力分析儀的“雙語對話”:CCLinkIE與Modbus TCP的無縫連接

在工業自動化領域&#xff0c;協議兼容性問題如同“方言壁壘”&#xff0c;讓不同品牌、不同系統的設備難以高效協同。對于電力分析儀這類關鍵設備而言&#xff0c;如何打破CCLinkIE與Modbus TCP協議的“語言障礙”&#xff0c;已成為工程師優化系統集成的核心課題。 為何需要協…

暑假復習篇之文本編譯器

一、知識點補充【在此次示例代碼上顯示的關鍵用法】知識點1、JMenuBar&#xff1a;菜單欄的容器&#xff0c;通常添加到JFrame的頂部。關鍵用法&#xff1a;add&#xff1a; 添加菜單到菜單欄2、JMenu&#xff1a;菜單條目&#xff08;“文件” “編輯” 等&#xff09;&#x…

Linux自動化構建工具(一)

&#x1f381;個人主頁&#xff1a;工藤新一 &#x1f50d;系列專欄&#xff1a;C面向對象&#xff08;類和對象篇&#xff09; &#x1f31f;心中的天空之城&#xff0c;終會照亮我前方的路 &#x1f389;歡迎大家點贊&#x1f44d;評論&#x1f4dd;收藏?文章 文章目錄Li…