存儲與緩存管理實驗簡介(中科大高級數(shù)據(jù)庫系統(tǒng))

為便于理解先將實驗要求進行翻譯,水平有限,有不妥之處請多指教。另外聲明在先,本文僅僅是實驗要求的中文翻譯。
介紹
在本項目中,我們將實現(xiàn)一個簡單的存儲與緩存管理器。文檔著重于磁盤和內(nèi)存的管理。討論的內(nèi)容包括:內(nèi)存(buffer)和頁框(frame)大小,buffer和frame存儲結構,頁(page)格式,page存儲結構,文件(file)結構,緩存技術,哈希技術,文件存儲結構,以及硬盤空間的接口函數(shù),緩沖模塊。

Buffer與Frames

Buffer與Frames大小

Buffer指主存中的空間。CPU只可以訪問駐存在主存中的內(nèi)容。Buffer包含一個frame數(shù)組。當一個page要被訪問時,page先被加載到內(nèi)存的buffer中。大多數(shù)的商業(yè)數(shù)據(jù)庫管理系統(tǒng)為了避免產(chǎn)生額外的碎片,將frame與page的大小設置成一樣的。本項目中也采取類似的策略,buffer的默認值將被設置成1024.

Buffer 和 Frame存儲結構

Buffer在邏輯上被劃分為frame塊。
一個frame被描述為如下全局定義的結構,
#define FRAMESIZE 4096
struct bFrame{
            char field[FRAMESIZE];
};

frame存放待加載的page,而buffer中保存frame數(shù)組。
數(shù)組的結構如下:

#define   DEFBUFSIZE 1024
bFrame buf[DEFBUFSIZE]; //or the size that the user defined by the input parameter

上述空間將被分配給buffer,緩沖區(qū)管理器和文件將通過訪問該buffer來訪問所需的頁面。

Page格式

在本項目中,我們不需要指明page結構的具體細節(jié)。唯一有關的信息是page_id和page_size。

File格式

我們推薦使用目錄結構的來組織數(shù)據(jù)庫文件。每個文件有一個基址頁保存指向每個頁面的指針。頁面中的每個指針都于頁面中順序存放。這種類型文件中的數(shù)據(jù)頁面(Data pages)不再設指針,使用記錄表示。為了訪問文件中的下一頁,必須查閱基址頁(base page)或目錄。
之所以選擇基于目錄的文件格式,是因為它適合查找特定的記錄請求頁。目錄的基址文件可以實現(xiàn)快速訪問正確的頁面,而不必搜索一長串的頁面找到正確的一個。

Buffering技術

我們采用LRU作為實驗中唯一的一種替換技術。LRU總是從一個buffer page的LRU隊列中剔除最近最少訪問的(least-recently-used)頁面,緩沖頁面LRU隊列按最后一次引用的時間順序。它總是在LRU位置上尋找替換頁(victim page)。LRU的最大優(yōu)勢在于:它擁有常數(shù)級別的時間復雜性。進一步說,LRU在時間局部性上表現(xiàn)良好,比如通常最近訪問的頁面有較高的可能性會再被訪問。

Hashing 技術

對buffer中的每個frame而言,buffer control block 必須常駐。每個buffer control block,或者說BCB,包含一個page_id,一個frame_id,page_latch,fix_count,以及dirty_bit。page_ids被用于hash函數(shù)的key值映射到BCB上。兩個hash表必須常駐內(nèi)存:一個將page_ids映射到frame_ids以及BCB另一個將frame_ids 映射到page_ids上。
我們建議采用簡單的靜態(tài)hash技術。在靜態(tài)哈希中,buckets(筐子)的數(shù)目固定。如果一個框滿,剩余的數(shù)據(jù)項使用一個溢出鏈連接。針對key值,hash函數(shù)將其映射入一個筐子。并且在一個獨立bucket中可以采用線性搜索。bucket的數(shù)目不會隨時間增長變化。
對hash表而言,靜態(tài)的hash函數(shù)具有如下相似形式:
H(k) = (page_id)%buffer_size
BCB(Buffer Control Blocks)通常包含page_id, frame_id, latch, count, dirty_bit。
BCB中page_id的hash表具有如下類似形式:BCB hTable[BufferSize]。
page_id中的frame_id 的hash表具有如下類似形式: int hTable[BufferSize]。

struct BCB
{ BCB();
int page_id;
int frame_id;
int latch;
int count;
int dirty;
BCB * next;
};

File Storage

我們的項目中,我們只需要在磁盤上存放一個物理文件。所有的數(shù)據(jù)庫數(shù)據(jù)將會存放在這個單獨文件中。該文件將會駐存在工作目錄中并命名為data.dbf。該文件必須始終能被找到,即使是空文件。

Class Design

Data Storage Manager

class DSMgr
{
public:
        DSMgr();
        int OpenFile(string filename);
        int CloseFile();
        bFrame ReadPage(int page_id);
        int WritePage(int frame_id, bFrame frm);
        int Seek(int offset, int pos);
        FILE * GetFile();
        void IncNumPages();
        int GetNumPages();
        void SetUse(int index, int use_bit);
        int GetUse(int index);
private:
        FILE *currFile;
        int numPages;
        int pages[MAXPAGES];
};

Buffer Manager

class BMgr
{ 
 public:
        BMgr();
        // Interface functions
        int FixPage(int page_id, int prot);
        void NewPage FixNewPage();
        int UnfixPage(int page_id);
        int NumFreeFrames();
        // Internal Functions
       int SelectVictim();
        int Hash(int page_id);
        void RemoveBCB(BCB * ptr, int page_id);
        void RemoveLRUEle(int frid);
        void SetDirty(int frame_id);
         void UnsetDirty(int frame_id);
         void WriteDirtys();
        PrintFrame(int frame_id);
private:
        // Hash Table
        int ftop[DEFBUFSIZE];
        BCB* ptof[DEFBUFSIZE];
};

Buffer Interface Functions

這些接口函數(shù)將會提供一個對文件與訪問管理器的接口。為實現(xiàn)相關功能,我們需要構造如下函數(shù)。

FixPage(int page_id, int prot)

函數(shù)原型為FixPage(Page_id, protection)。
該函數(shù)返回一個frame_id。
文件與訪問管理器將會傳遞一個page_id來調(diào)用相關page,此處的page_id與記錄中的record_id相對應。該函數(shù)查看所需page是否已經(jīng)在buffer中,若存在返回它對應的frame_id。若該頁不在內(nèi)存,該函數(shù)選擇一個victim page,并且若有需要加載所需page。

FixNewPage()

該函數(shù)原型為 FixNewPage(),它返回一個page_id和frame_id。
當產(chǎn)生插入,目錄分割或創(chuàng)建對象等操作時,該函數(shù)被調(diào)用,用來產(chǎn)生一個新的page。
該函數(shù)的返回值是與record_id或元數(shù)據(jù)相對應的page_id。這個函數(shù)將會尋找一個空頁面,供給文件與訪問管理器存放數(shù)據(jù)。

UnfixPage(int page_id)

該函數(shù)原型為UnfixPage(page_id),它返回一個frame_id。該函數(shù)是與FixPage或FixNewPage配合使用。這個函數(shù)每次將frame上的fix count減一。 當數(shù)量為0時,對page的占用就被解除,若被選中frame可以被移除。page_id可以被轉(zhuǎn)化成frame_id并且它可以被解除占用。當一個頁面上的count等于0時,該頁面可以被選為victim page。

NumFreeFrames()

NumFreeFrame查看buffer返回空閑可用的buffer page數(shù)量。該函數(shù)在使用N-路排序中非常有用。該函數(shù)的原型是 NumFreeFrames(),返回值為一個整數(shù),范圍為 0 -BUFFERSIZE-1(1023).

SelectVictim()

SelectVictim函數(shù)選擇一個frame進行替換。當一個被選中的頁面dirty位被標記,需要將選中頁面寫回磁盤。

Hash(int page_id)

Hash函數(shù)使用page_id作為參數(shù)并返回frame id。

RemoveBCB(BCB* ptr, int page_id)

RemoveBCB函數(shù)從隊列里移除 page_id對應的BCB 。只有在SelectVictim()函數(shù)需要替換一個frame時才被調(diào)用。

RemoveLRUEle(int frid)

RemoveLRUEle函數(shù)從隊列里移除LRU 元素。

SetDirty(int frame_id)

SetDirty為 frame_id設置dirty位。dirty位用于指示是否需要寫回frame。一個frame若被修改過,則需要被寫回。這包括目錄頁和數(shù)據(jù)頁面。若該位為1需要被寫回,若為0不需要寫回。

UnsetDirty(int frame_id)

UnsetDirty函數(shù)將對應frame_id的dirty_bit設置為0。當調(diào)用了setDirty()函數(shù)但,實際上該頁只是臨時改動,不需要被寫回,也不想被存儲到磁盤,調(diào)用UnsetDirty函數(shù)。

WriteDirtys()

WriteDirtys 在系統(tǒng)結束前必須被調(diào)用。函數(shù)的目的是寫回buffer中的所有dirty_bit為1的page到磁盤。.

PrintFrame(int frame_id)

PrintFrame函數(shù)打印frame內(nèi)容,這里打印frame_id。

Data Storage Interface Functions

現(xiàn)在的數(shù)據(jù)文件會保持在 DSManager class中。文件名為data.dbf。

OpenFile(string filename)

任何一個文件需要被讀取或?qū)懭耄琌penFile函數(shù)就被調(diào)用。函數(shù)原型為OpenFile(String filename),若執(zhí)行錯誤返回一個錯誤碼。

CloseFile()

當一個文件要被關閉時調(diào)用CloseFile函數(shù)。函數(shù)原型為 CloseFile() 。函數(shù)只能在數(shù)據(jù)庫發(fā)生變化或一個程序被關閉時被調(diào)用。

ReadPage(int page_id)

在buffer管理器中,ReadPage函數(shù)被FixPage調(diào)用。函數(shù)原型為ReadPage(page_id, bytes),返回值為它讀取的內(nèi)容。該函數(shù)調(diào)用fseek()和fread()從文件中讀取數(shù)據(jù)。

WritePage(int frame_id, bFrame frm)

當一個page從buffer中取出時,調(diào)用WritePage函數(shù)。函數(shù)原型為 WritePage(frame_id, frm)返回值為被寫入的字節(jié)數(shù)目。該函數(shù)調(diào)用fseek()和 fwrite()向文件中寫入數(shù)據(jù)。

Seek(int offset, int pos)

Seek function moves the file pointer.

GetFile()

GetFile function returns the current file.

IncNumPages()

IncNumPages function increments the page counter.

GetNumPages()

GetNumPages function returns the page counter.

SetUse(int page_id, int use_bit)

SetUse在page數(shù)組中查找set位。這個數(shù)組用于記錄page使用情況的變化。如果這個page中所有的記錄都被刪除,該頁面即不再被使用。為了了解一個頁面是否被重復使用過,該數(shù)組所有的use_bit位都需要被檢查是否被置為0。fixNewPage先檢查數(shù)組的use_bit是否被置為0。如果找到1,說明page已經(jīng)被重用。否則需要分配一個新的page。

GetUse(int page_id)

GetUse函數(shù)返回page_id對應的use_bit

Experiment Setup

我們的項目中,我們需要執(zhí)行一個trace-driven的實驗來測試你的實現(xiàn)結果。我們需要根據(jù)Zipf分布確定trace的生成。 trace中共有50000個page記錄,每條記錄數(shù)字從0-49999。每條 trace 記錄格式如下 “x, ###”,x表示0(read) or 1(write) 而 ### 指示page number. 你需要掃描trace file,打印出所有的內(nèi)存與硬盤間的I/Os次數(shù)。
buffer初始為空。所有的50000個頁面首先需要被保存在磁盤上,對應一個directory-based文件data.dbf。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容