存储与缓存管理实验简介(中科大高级数据库系统)

为便于理解先将实验要求进行翻译,水平有限,有不妥之处请多指教。另外声明在先,本文仅仅是实验要求的中文翻译。
介绍
在本项目中,我们将实现一个简单的存储与缓存管理器。文档着重于磁盘和内存的管理。讨论的内容包括:内存(buffer)和页框(frame)大小,buffer和frame存储结构,页(page)格式,page存储结构,文件(file)结构,缓存技术,哈希技术,文件存储结构,以及硬盘空间的接口函数,缓冲模块。

Buffer与Frames

Buffer与Frames大小

Buffer指主存中的空间。CPU只可以访问驻存在主存中的内容。Buffer包含一个frame数组。当一个page要被访问时,page先被加载到内存的buffer中。大多数的商业数据库管理系统为了避免产生额外的碎片,将frame与page的大小设置成一样的。本项目中也采取类似的策略,buffer的默认值将被设置成1024.

Buffer 和 Frame存储结构

Buffer在逻辑上被划分为frame块。
一个frame被描述为如下全局定义的结构,
#define FRAMESIZE 4096
struct bFrame{
            char field[FRAMESIZE];
};

frame存放待加载的page,而buffer中保存frame数组。
数组的结构如下:

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

上述空间将被分配给buffer,缓冲区管理器和文件将通过访问该buffer来访问所需的页面。

Page格式

在本项目中,我们不需要指明page结构的具体细节。唯一有关的信息是page_id和page_size。

File格式

我们推荐使用目录结构的来组织数据库文件。每个文件有一个基址页保存指向每个页面的指针。页面中的每个指针都于页面中顺序存放。这种类型文件中的数据页面(Data pages)不再设指针,使用记录表示。为了访问文件中的下一页,必须查阅基址页(base page)或目录。
之所以选择基于目录的文件格式,是因为它适合查找特定的记录请求页。目录的基址文件可以实现快速访问正确的页面,而不必搜索一长串的页面找到正确的一个。

Buffering技术

我们采用LRU作为实验中唯一的一种替换技术。LRU总是从一个buffer page的LRU队列中剔除最近最少访问的(least-recently-used)页面,缓冲页面LRU队列按最后一次引用的时间顺序。它总是在LRU位置上寻找替换页(victim page)。LRU的最大优势在于:它拥有常数级别的时间复杂性。进一步说,LRU在时间局部性上表现良好,比如通常最近访问的页面有较高的可能性会再被访问。

Hashing 技术

对buffer中的每个frame而言,buffer control block 必须常驻。每个buffer control block,或者说BCB,包含一个page_id,一个frame_id,page_latch,fix_count,以及dirty_bit。page_ids被用于hash函数的key值映射到BCB上。两个hash表必须常驻内存:一个将page_ids映射到frame_ids以及BCB另一个将frame_ids 映射到page_ids上。
我们建议采用简单的静态hash技术。在静态哈希中,buckets(筐子)的数目固定。如果一个框满,剩余的数据项使用一个溢出链连接。针对key值,hash函数将其映射入一个筐子。并且在一个独立bucket中可以采用线性搜索。bucket的数目不会随时间增长变化。
对hash表而言,静态的hash函数具有如下相似形式:
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

我们的项目中,我们只需要在磁盘上存放一个物理文件。所有的数据库数据将会存放在这个单独文件中。该文件将会驻存在工作目录中并命名为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

这些接口函数将会提供一个对文件与访问管理器的接口。为实现相关功能,我们需要构造如下函数。

FixPage(int page_id, int prot)

函数原型为FixPage(Page_id, protection)。
该函数返回一个frame_id。
文件与访问管理器将会传递一个page_id来调用相关page,此处的page_id与记录中的record_id相对应。该函数查看所需page是否已经在buffer中,若存在返回它对应的frame_id。若该页不在内存,该函数选择一个victim page,并且若有需要加载所需page。

FixNewPage()

该函数原型为 FixNewPage(),它返回一个page_id和frame_id。
当产生插入,目录分割或创建对象等操作时,该函数被调用,用来产生一个新的page。
该函数的返回值是与record_id或元数据相对应的page_id。这个函数将会寻找一个空页面,供给文件与访问管理器存放数据。

UnfixPage(int page_id)

该函数原型为UnfixPage(page_id),它返回一个frame_id。该函数是与FixPage或FixNewPage配合使用。这个函数每次将frame上的fix count减一。 当数量为0时,对page的占用就被解除,若被选中frame可以被移除。page_id可以被转化成frame_id并且它可以被解除占用。当一个页面上的count等于0时,该页面可以被选为victim page。

NumFreeFrames()

NumFreeFrame查看buffer返回空闲可用的buffer page数量。该函数在使用N-路排序中非常有用。该函数的原型是 NumFreeFrames(),返回值为一个整数,范围为 0 -BUFFERSIZE-1(1023).

SelectVictim()

SelectVictim函数选择一个frame进行替换。当一个被选中的页面dirty位被标记,需要将选中页面写回磁盘。

Hash(int page_id)

Hash函数使用page_id作为参数并返回frame id。

RemoveBCB(BCB* ptr, int page_id)

RemoveBCB函数从队列里移除 page_id对应的BCB 。只有在SelectVictim()函数需要替换一个frame时才被调用。

RemoveLRUEle(int frid)

RemoveLRUEle函数从队列里移除LRU 元素。

SetDirty(int frame_id)

SetDirty为 frame_id设置dirty位。dirty位用于指示是否需要写回frame。一个frame若被修改过,则需要被写回。这包括目录页和数据页面。若该位为1需要被写回,若为0不需要写回。

UnsetDirty(int frame_id)

UnsetDirty函数将对应frame_id的dirty_bit设置为0。当调用了setDirty()函数但,实际上该页只是临时改动,不需要被写回,也不想被存储到磁盘,调用UnsetDirty函数。

WriteDirtys()

WriteDirtys 在系统结束前必须被调用。函数的目的是写回buffer中的所有dirty_bit为1的page到磁盘。.

PrintFrame(int frame_id)

PrintFrame函数打印frame内容,这里打印frame_id。

Data Storage Interface Functions

现在的数据文件会保持在 DSManager class中。文件名为data.dbf。

OpenFile(string filename)

任何一个文件需要被读取或写入,OpenFile函数就被调用。函数原型为OpenFile(String filename),若执行错误返回一个错误码。

CloseFile()

当一个文件要被关闭时调用CloseFile函数。函数原型为 CloseFile() 。函数只能在数据库发生变化或一个程序被关闭时被调用。

ReadPage(int page_id)

在buffer管理器中,ReadPage函数被FixPage调用。函数原型为ReadPage(page_id, bytes),返回值为它读取的内容。该函数调用fseek()和fread()从文件中读取数据。

WritePage(int frame_id, bFrame frm)

当一个page从buffer中取出时,调用WritePage函数。函数原型为 WritePage(frame_id, frm)返回值为被写入的字节数目。该函数调用fseek()和 fwrite()向文件中写入数据。

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数组中查找set位。这个数组用于记录page使用情况的变化。如果这个page中所有的记录都被删除,该页面即不再被使用。为了了解一个页面是否被重复使用过,该数组所有的use_bit位都需要被检查是否被置为0。fixNewPage先检查数组的use_bit是否被置为0。如果找到1,说明page已经被重用。否则需要分配一个新的page。

GetUse(int page_id)

GetUse函数返回page_id对应的use_bit

Experiment Setup

我们的项目中,我们需要执行一个trace-driven的实验来测试你的实现结果。我们需要根据Zipf分布确定trace的生成。 trace中共有50000个page记录,每条记录数字从0-49999。每条 trace 记录格式如下 “x, ###”,x表示0(read) or 1(write) 而 ### 指示page number. 你需要扫描trace file,打印出所有的内存与硬盘间的I/Os次数。
buffer初始为空。所有的50000个页面首先需要被保存在磁盘上,对应一个directory-based文件data.dbf。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容