BufDesc

frame 们的 descriptor(见BufHashTbl注释),包括

  • pageNo: 这个 frame 在文件里的id,page number
  • prevframe: -1 表示此 frame 为空,如果是hash slot的第一个则为 slot number,否则就是前一个 frame的frame number
  • 注意 frame number 是在 buffer pool 里的 id,page number 是在文件里的 id
  • nextframe: 下一个 frame 的 number,-1表示没有下一个 frame
  • dirty: 1 是 dirty
  • int: 1 表示这个 frame 正在被一个新的读取覆盖,可以用1+oldpageno表示原来的frame的page number

方法只有 constructor 和 destructor,constructor设各种 number 为 -1,不 dirty,没人 reading

BufHashTbl

用来登记 buffer pool 里的 page 们

  • ht[HTSIZE]:用来登记frame的数组,-1表示对应的hash value 还没有 page 登记过,否则保存对应的链表头的 frame no
  • numBuffers:buffer的大小
  • bufTable[numBuffers]:保存 frame 们的 descriptor

方法

  • hash: 接收 pageNo,返回 hash value,用来做 ht 下标(这里用的是最傻的取模+开放寻址)
  • insert: 算好哪个 page 放进 哪个 frame 后,将 page number 和frame number 传给它来放
    1. 首先会将bufTable的对应指针保存进tmp,如果发现对应所指的frame不为空,报错,提醒先调用remove
    2. 将page no设成新的
    3. 设dirty为false,因为刚插进来肯定没改
    4. 将它插到slot的顶部,设prevframe为index+numBuffers(index是hash过的page id)即slot number
    5. 通过ht找到index对应的frame number,要么是-1表示这个slot还是空的,要么就是当前slot顶部的frame number,赋给tmp的nextframe,也就是把tmp插到了链表头部
    6. 如果ht[index]>-1,这个slot不是空的,那么将被挤到后面去的frame的prevframe设成这个新插进去的frame
    7. 最后将ht[index]设成当前frame 的 frame number,插入头部完成
  • lookup: 接收 page number,然后去 hash table 里查找,有的话就返回对应的 frame number,不然返回 -1
    • 就是开放寻址,hash之然后不断向后找,直到碰到空的frame就返回-1
  • remove: 删掉
    1. 将frame number对应的descriptor存进tmp先
    2. 检查是不是在链表头(看tmp->prevframe是否是slot number,即大于numBuffers)
      1. 如果是,把ht里对应的frame number改成下一个frame
      2. 如果不是,让自己的prevframe的nextframe指向自己的nextframe
    3. 如果自己的nextframe不为空(>1),将自己的nextframe的prevframe设成自己的prevframe
    4. 前后的连接都设置好了,把自己的descriptor的各种值改成跟空的一样,等待caller回收或者覆盖掉里面的东西

Replacer

abstract class,给各种换页算法的class用的

  • mgr:跟这个replacer一起的buffer manager
  • pin_count[numBuffers]:对应每个frame的pin count
  • state_bit[numBuffers]:每个frame的state,包括 {Available, Referenced, Pinned}
  • head:clock的head

方法

  • pin:接收frame number,加一个 pin

    • 设这个frame的state为pinned,然后加pin_count
  • unpin:
    • 注意如果它的pin_count已经是0,说明有问题,要报错
    • 减掉pin_count,如果是0,将state转换到referenced给clock用
  • free:给buffer manager的freePage用的,接收 frame number,pin_count和state_bit都初始化掉
  • pick_victim:挑选要 free 掉的 frame,不同的算法有不同的选法,所以是 abstract function
  • name:?
  • info:?
  • getNumUnpinnedBuffers:目前还有多少 frame 还是有人用的
  • setBufferManager:设置对应的 buffer manager
    1. 删掉原来的私有变量,然后各种初始化

BufMgr

buffer manager啦~

  • hashTable:用来管理 buffer pool里的 frame 的 hash table,一个buffer manager只有一个
  • bufPool[numBuffers]:实际放每个frame对应page的的数组
  • numBuffers:buffer pool的大小
  • replacer:这个buffer manager用的replacer
  • _victim_list:里面都是已经从 buffer pool里删除的 page,但都是 dirty 的,而且还没有写回硬盘,每个元素里有对应的 frame number 和 page id
  • _valid_victim_entries:当前victim的数量

方法

  • _exist_victim_list: 查找 victim list 里是否有符合 pgid 的page,如果有将对应的 frame number 写进参数,返回OK,否则写-1到参数里
  • _remove_victim_list: 在 victim list 里查找并删除对应的 page,删除之后把后面的所有entries向前移……(= =)
  • _add_victim_list:把新的page id 和frame number 对加到尾部

  • BufMgr: 初始化buffer pool和_victim_list(malloc),将hash table里每个descriptor们的next frame按顺序连起来,_victim_list的所有元素的page id 和 frame number 设置为 -1,给buffer pool里每个元素都设成空的页,这里有个略看不懂的东西:

    (void) new(bufPool+i) Page;

    貌似是给bufPool+i所指向的空间调用Page的constructor

    然后设置好 replacer,如果没有传参进来就分配空间设一个新的,给replacer的buffer manager设成自己

  • ~BufMgr:检查hash table里所有的frame,有dirty的就写回去,然后删除每个malloc过的指针

  • pinPage:

    1. 在 buffer pool里查找 page id 对应的 page

      hashTable.lookup(pin_pgid);
    2. 如果找不到,用replacer的pick_victim()挑一页来换

      1. 如果挑不到(全都有人在用),报错
      2. 如果挑到了但是是 dirty 的
        1. 暂存这frame里目前的 page number,然后将这frame放进 _victim_list,处理好前后frame的连接(用hash table的remove()),设置好这frame的 reading,然后用hash table的insert()将新的page登记进去
        2. 以上一路都OK的话就用write_page()将 dirty 的原来的 page 写进去(到这步frameNo还是指向原来的 page 所在的frame,而且这个 frame 里的内容也还没改)
        3. 如果写好了也没其他错误,就可以将这个old page从_victim_list里拿走了
      3. 挑完了也写回去了,就可以读进新的 page 了(read_page())
        1. 如果读取过程中出现错误,需要将这hash table里的这一frame清掉,假装这一frame空了
      4. 设回 hash table里的reading=0,将读好的frame的地址写进参数传回去
      5. pin好这个frame
    3. 如果有就写进 page 指针,没有就换页再读进来,如果换页的时候发现是 dirty 的,它也负责把原来的 frame 写回去,然后给对应的pin_count + 1

    4. 如果设了 BM_TRACE,会接收 filename 方便 trace

    5. 如果 emptyPage == TRUE,提示要读的 page 是空的,就不会真的去读,返回一个空的 page 就好了
  • unpinPage:接收 page id,unpin 掉这个 page(pin_count -1)
    • 如果在hash table里找page id的时候发现找不到 or 找到的是空 frame or 没法让 replacer unpin,返回错误
    • 如果告知是 dirty 的,设好这个 frame descriptor 的 dirty
    • replacer会搞定pin_count的减,如果 pin_count 减完变0了,说明没人在用了,可以拿去做换页的候选
  • newPage:让 DB 给一堆(howmany)新的 page 分配硬盘空间,在 buffer pool里找个可以放 page 的 frame 给其中的第一个 page,pin 之(覆写参数 firstPageId 和 firstpage 做返回)。如果 buffer 已满,让 DB 悲催地把已经新建的 page deallocate掉,然后返回 error
  • freePage:删掉硬盘上的 page 的时候需要调用这个函数
    1. 先在hash table里查找page id,如果找不到说明不在buffer pool里,直接deallocate即可
    2. 如果找得到,要让replacer free掉它,然后从hash table里remove(即从pool里移走),然后再让 DB deallocate 掉这个 page
  • flushPage:flush 掉_指定的_ page,把它从 buffer pool 里销掉,需要写回硬盘就写回去
  • flushAllPages:顾名思义
  • PageInFrame:接收 frame number,把保存在内存里的 page 的指针返回来

MINIBASE源代码阅读笔记之buffer manager的更多相关文章

  1. MINIBASE源代码阅读笔记之DB

    DB 管理数据库的类 file_entry:dir page的元素,保存不同文件对应的page directory_page:dir page的专用结构体,里面有个初始长度为0的variable si ...

  2. MINIBASE源代码阅读笔记之heapfile

    Heapfile 用来管理heap file里的dir page们 成员 _firstDirPageId:这个文件的第一个dir page _ftype:文件类型 _file_deleted:删除的时 ...

  3. MINIBASE源代码阅读笔记之HFPage

    HFPage heap file的page的类 成员 slot_t:用来表示页里的slot,包括offset和length slot[]:倒着生长的slot array slotCnt:有多少已用sl ...

  4. Spark源代码阅读笔记之DiskStore

    Spark源代码阅读笔记之DiskStore BlockManager底层通过BlockStore来对数据进行实际的存储.BlockStore是一个抽象类,有三种实现:DiskStore(磁盘级别的持 ...

  5. Mongodb源代码阅读笔记:Journal机制

    Mongodb源代码阅读笔记:Journal机制 Mongodb源代码阅读笔记:Journal机制 涉及的文件 一些说明 PREPLOGBUFFER WRITETOJOURNAL WRITETODAT ...

  6. CI框架源代码阅读笔记5 基准測试 BenchMark.php

    上一篇博客(CI框架源代码阅读笔记4 引导文件CodeIgniter.php)中.我们已经看到:CI中核心流程的核心功能都是由不同的组件来完毕的.这些组件类似于一个一个单独的模块,不同的模块完毕不同的 ...

  7. CI框架源代码阅读笔记3 全局函数Common.php

    从本篇開始.将深入CI框架的内部.一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说.全局函数具有最高的载入优先权.因此大多数的框架中BootStrap ...

  8. CI框架源代码阅读笔记2 一切的入口 index.php

    上一节(CI框架源代码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程.这里再次贴出流程图.以备參考: 作为CI框架的入口文件.源代码阅读,自然由此開始. 在源代码阅读的 ...

  9. Java Jdk1.8 HashMap源代码阅读笔记二

    三.源代码阅读 3.元素包括containsKey(Object key) /** * Returns <tt>true</tt> if this map contains a ...

随机推荐

  1. [模板]2-SAT 问题&和平委员会

    tarjan的运用 this is a problem:link 2-SAT处理的是什么 首先,把「2」和「SAT」拆开.SAT 是 Satisfiability 的缩写,意为可满足性.即一串布尔变量 ...

  2. Howto run google-chrome as root

    Just want to add a permanent solution to the problem: 1. Open google-chrome located in /usr/bin with ...

  3. intellij 插件结构(文件结构以及概念层面上的结构)

    1.插件内的文件 2.插件类加载器 3.插件组件(component) 4.插件的扩展以及扩展点(Extensions.Extension Points) 5.插件的Action 6.插件的Servi ...

  4. python安装包下载

    加入python官网一次按照下图点击: 这个exe文件就下好了,然后再安装一下即可.

  5. SpringBoot (六) :如何优雅的使用 mybatis

    原文出处: 纯洁的微笑 这两天启动了一个新项目因为项目组成员一直都使用的是mybatis,虽然个人比较喜欢jpa这种极简的模式,但是为了项目保持统一性技术选型还是定了 mybatis.到网上找了一下关 ...

  6. 隐藏超出父元素的子元素的部分:overflow

    overflow : 针对超出父级的内容如何显示 值: visible 默认值,超出的内容会显示出来 auto 如果内容超出了父级,那就出现滚动条.如果内容没有超出,就没有滚动条 hidden 超出的 ...

  7. (转)C++常见问题: 字符串分割函数 split

    http://www.cnblogs.com/dfcao/p/cpp-FAQ-split.html C++标准库里面没有字符分割函数split ,这可太不方便了,我已经遇到>3次如何对字符串快速 ...

  8. JVM调优总结(3):垃圾回收面临的问题

    如何区分垃圾 上面说到的“引用计数”法,通过统计控制生成对象和删除对象时的引用数来判断.垃圾回收程序收集计数为0的对象即可.但是这种方法无法解决循环引用.所以,后来实现的垃圾判断算法中,都是从程序运行 ...

  9. JQuery和Servlet来实现跨域请求

    在网上看到很多的JQuery跨域请求的文章,比较有意思.这里我发表一个Servlet与JQuery配置实现跨域的代码,供大家参考.不足之处请指教 原理:JavaScript的Ajax不可以跨域,但是可 ...

  10. 【BZOJ】2125: 最短路 圆方树(静态仙人掌)

    [题意]给定带边权仙人掌图,Q次询问两点间最短距离.n,m,Q<=10000 [算法]圆方树处理仙人掌问题 [题解]树上的两点间最短路问题,常用倍增求LCA解决,考虑扩展到仙人掌图. 先对仙人掌 ...