经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
C++实现页面的缓冲区管理器
来源:jb51  时间:2022/8/1 19:09:58  对本文有异议

1. 实验目标

本次实验要实现一个页面的缓冲区管理器。

具体要实现以下的函数:

~BufMgr():

清除所有脏页并释放缓冲池和 BufDesc 表

void advanceClock():

用来找到下一个时钟的位置

void allocBuf(FrameId& frame):

使用时钟算法分配自由帧;如有必要,将脏页写回磁盘。

void readPage(File* file, const PageId PageNo, Page*& page)

通过调用 lookup()方法检查页是否已经在缓冲池中。当页不在缓冲池中可以在哈希表上抛出 HashNotFoundException 以获取帧编号。

void unPinPage(File* file, const PageId PageNo, const bool dirty)

减少一个页面的占用次数

void allocPage(File* file, PageId& PageNo, Page*& page)

通过调用 file->allocatePage()方法在指定的文件中分配一个空页。此方法将返回新分配的页。然后调用 allocBuf()以获取缓冲池帧。接下来,将一个条目插入到哈希表中,并在帧上调用 Set(),以正确设置它。

void disposePage(File* file, const PageId pageNo)

功能是释放一个页面

void flushFile(File* file)

功能是找到含有对应文件的页面,并释放

2. 代码实现

  1. BufMgr::~BufMgr() {
  2. delete hashTable;
  3. delete[] bufPool;
  4. delete[] bufDescTable;
  5. }

直接调用 delete 删除哈希表、缓冲池、缓冲池表

  1. void BufMgr::advanceClock() {
  2. clockHand++;
  3. if (clockHand >= numBufs) {
  4. clockHand %= numBufs;
  5. }
  6. }

将时钟提前到缓冲池的下一帧。

如果指针超过了最大值,进行取模操作。

  1. void BufMgr::allocBuf(FrameId &frame) {
  2. unsigned pinned = 0;
  3. while (true) {
  4. advanceClock();
  5. if (!bufDescTable[clockHand].valid) {
  6. frame = clockHand;
  7. return;
  8. }
  9. if (bufDescTable[clockHand].refbit) {
  10. bufDescTable[clockHand].refbit = false;
  11. continue;
  12. }
  13. if (bufDescTable[clockHand].pinCnt) {
  14. pinned++;
  15. if (pinned == numBufs) {
  16. throw BufferExceededException();
  17. } else {
  18. continue;
  19. }
  20. }
  21. if (bufDescTable[clockHand].dirty) {
  22. bufDescTable[clockHand].file->writePage(bufPool[clockHand]);
  23. bufDescTable[clockHand].dirty = false;
  24. }
  25. frame = clockHand;
  26. if (bufDescTable[clockHand].valid) {
  27. try {
  28. hashTable->remove(bufDescTable[clockHand].file, bufDescTable[clockHand].pageNo);
  29. }
  30. catch (HashNotFoundException &) {
  31. }
  32. }
  33. break;
  34. }
  35. }

遍历栈区寻找可用的页面。如果是没有被使用过的页面,直接进行分配。如果缓冲区所有的页面都被占用,那么会进行报错 BufferExceededException()。如果找到脏页,会将它写回磁盘,并将脏页标记给清除。如果不是脏页,那么就进行分配操作。如果它在哈希表中要将它移除。

  1. void BufMgr::readPage(File *file, const PageId pageNo, Page *&page) {
  2. FrameId frame;
  3. try {
  4. hashTable->lookup(file, pageNo, frame);
  5. bufDescTable[frame].refbit = true;
  6. bufDescTable[frame].pinCnt++;
  7. page = (bufPool + frame);
  8. } catch (HashNotFoundException &) {
  9. allocBuf(frame);
  10. bufPool[frame] = file->readPage(pageNo);
  11. hashTable->insert(file, pageNo, frame);
  12. bufDescTable[frame].Set(file, pageNo);
  13. page = (bufPool + frame);
  14. }
  15. }

如果页面在缓冲池中,增加它的占用次数,调用 page 返回指向该页面的指针。

如果页面不在缓冲池中,那么将页面读取到缓冲池,插入哈希表中,调用 set 正确设置该界面,调用 page 返回指向该页面的指针。

  1. void BufMgr::unPinPage(File *file, const PageId pageNo, const bool dirty) {
  2. FrameId frame;
  3. try {
  4. hashTable->lookup(file, pageNo, frame);
  5. } catch (HashNotFoundException &) {
  6. //没有该页面
  7. cerr << "Warning: unpinning a nonexistent page" << endl;
  8. return;
  9. }
  10. //找到页面
  11. if (bufDescTable[frame].pinCnt > 0) {
  12. bufDescTable[frame].pinCnt--;
  13. if (dirty) {
  14. bufDescTable[frame].dirty = true;
  15. }
  16. } else {
  17. //pin = 0,抛出异常
  18. throw PageNotPinnedException(bufDescTable[frame].file->filename(), bufDescTable[frame].pageNo, frame);
  19. }
  20. }

如果缓冲池中没有该页面,进行异常提示。

如果在缓冲池中,那么将它的占用次数减少。如果占用次数为 0,进行报错。

  1. void BufMgr::flushFile(const File *file) {
  2. for (FrameId fi = 0; fi < numBufs; fi++) {
  3. if (bufDescTable[fi].file == file) {
  4. if (!bufDescTable[fi].valid) {
  5. throw BadBufferException(fi, bufDescTable[fi].dirty, bufDescTable[fi].valid, bufDescTable[fi].refbit);
  6. }
  7. if (bufDescTable[fi].pinCnt > 0) {
  8. throw PagePinnedException(file->filename(), bufDescTable[fi].pageNo, fi);
  9. }
  10. if (bufDescTable[fi].dirty) {
  11. bufDescTable[fi].file->writePage(bufPool[fi]);
  12. bufDescTable[fi].dirty = false;
  13. }
  14. hashTable->remove(file, bufDescTable[fi].pageNo);
  15. bufDescTable[fi].Clear();
  16. }
  17. }
  18. }

遍历整个表,找到含有对应页面的缓冲页,移除并清空该页面。如果页面是脏页,则将其写回磁盘,初始化脏页标记。如果页面被占用或者页面不可用,则进行报错。

  1. void BufMgr::allocPage(File *file, PageId &pageNo, Page *&page) {
  2. FrameId frame;
  3. Page p = file->allocatePage();
  4. allocBuf(frame);
  5. bufPool[frame] = p;
  6. pageNo = p.page_number();
  7. hashTable->insert(file, pageNo, frame);
  8. bufDescTable[frame].Set(file, pageNo);
  9. page = bufPool + frame;
  10. }

掉用 allocatePage()分配一个新页面,加入哈希表,调用 set(),返回该页面指针。

  1. void BufMgr::disposePage(File *file, const PageId PageNo) {
  2. FrameId frame;
  3. try {
  4. hashTable->lookup(file, PageNo, frame);
  5. hashTable->remove(file, PageNo);
  6. bufDescTable[frame].Clear();
  7. } catch (HashNotFoundException &) {
  8. }
  9. file->deletePage(PageNo);
  10. }

删除一个页面。如果它在缓冲池中,要将缓冲内容一并删除。

3.实验结果

12个样例均能通过,实验结果如下:

  1. me].Clear();
  2. } catch (HashNotFoundException &) {
  3. }
  4. file->deletePage(PageNo);
  5. }

删除一个页面。如果它在缓冲池中,要将缓冲内容一并删除

到此这篇关于C++实现页面的缓冲区管理器的文章就介绍到这了,更多相关C++缓冲区管理器内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号