06 缓存管理

缓冲区结构

  • 缓冲区由一个个 frame 构成,每个 frame 刚好可以容纳一个页
  • 为计算机程序隐藏了“并非所有数据都存在内存”这一事实

frame 参数

  • dirty:frame 中的块是否已经被修改
  • pin-count:frame 的块的已经被请求且还未释放的计数,即当前的用户数
  • *others
    • latch: 是否加锁

缓冲区管理过程

  1. 当请求块且块不在缓冲区时:
    1. 选择一个用于替换的 frame(空或非空)
    2. 如果 frame 是 dirty 的(部分块被修改过),frame 的内容写回磁盘
    3. 将请求块写入被选择的frame
    4. pin the block(将该 frame 的 pin-count 自增1),并返回其地址
  2. 当释放块时
    1. 请求者 unpin the block (将该 frame 的 pin-count 自减 1)
    2. 请求者必须声明该块是否被修改过(用frame->dirty)

缓冲区置换算法

opt

在实验中作为算法性能上界加以对比

LRU

  • 维护一个链表,并按照最近访问时间排序
  • 基于时间局部性 (temporal locality) 假设:越是最近访问的在未来被访问的概率越高
  • 总是替换 lru 端的 frame
  • 优点
    • 适用于满足时间局部性的场景(多次重复请求同一页)
    • 选取被替换 frame 的时间复杂度是 o (1)
  • 缺点
    • 缓存污染 (sequential flooding): lru + repeated sequential scans
      • 缓存污染问题主要关注数据的访问频次
    • lru链表维护代价昂贵:修改链表耗时
    • 如果访问不满足时间局部性,则性能较差
    • 只考虑最近一次访问,忽略了访问频率

lru-k

  • 需要维护两个 lru 链表
    • 一个存储访问小于 k 次的
    • 一个存储访问大于 k 次的
  • 需要替换 frame 时,按照 lru 策略优先置换小于 k 次的链表
  • 实验表明,k并非越大越好,lru-2性能较好
  • 缺点:需要额外记录访问次数

2q

和 lru-2 类似,但是访问 1 次的队列采用 fifo,而不是 lru

second-chance fifo

  • 所有 frame 组成 fifo 链表,每个 frame 附加一个 bit 位,初始为0
    • fi, fo 分别为队尾和队头
    • 每 frame 被使用时,将 bit 设置为 0
    • 当 fo 页第一次被选中置换时置为 1,并移到 fi 端。只有 bit 位为 1 的 fo 端的页才被选中置换
  • 相当于每个 frame 给了两次置换机会,避免高频访问但最近一轮没有被访问的 frame 被置换出 buffer

clock

  • 把 second-chance fifo 组织成环形
    • current 指针指向当前 frame
    • 每个 frame 有一个 referenced 位,初始为1
  • 当需要置换页时
    • 若 pin-count>0,current 增加1
    • 若 referenced=1 ,则关闭它(=0)并增加 current
    • 若 pin-count=0 并且 referenced 关闭(=0),则替换该 frame,同时 current 加1

置换过程才会更新 current 指针,访问命中过程不改变 current 指针

ssd 上的置换算法

为什么不使用 os 的缓冲管理

  • dbms 能预测访问模式 (access pattern)
    • 可以使用更专门的缓冲区替换策略
    • 有利于 pre-fetch 策略的有效使用
  • dbms 需要强制写回磁盘能力
    • os 的缓冲写回一般通过记录写请求来实现(来自不同应用),实际的磁盘修改推迟,因此不能保证写顺序

缓冲区管理的实现

block vs. disk file

  • 文件存储在磁盘上的物理形式是 bits/bytes
  • block 是由 os 或 dbms 软件对文件所做的抽象,这一抽象是通过控制数据在文件中的起止 offset 来实现的

buffer vs. disk file

  • frame 是 buffer 中的单位;page/block 是内存/磁盘的单位
  • 通常 frame 和 page 大小相同

buffer 存储结构

#define framesize 4096
struct bframe
{
	char field[framesize];
}
#define bufsize 1024 // frame数目
bframe buf[bufsize]; //也可以是用户配置的值
  • buffer 是一个存放 frame 的数组

在 buffer 中查找 frame

  • block 时,根据 page_id 确定 buffer 中是否已经存在 frame
  • block 时,根据 frame_id 找到文件对应的 page_id

维护 buffer 中所有 frame 的维护信息(buffer control blocks):

struct bcb
{
	bcb();
	int page_id;
	int frame_id;
	int count;
	int time;
	/* int latch; */
	int dirty;
	bcb * next;
};

用哈希表建立 frame-page 之间的索引:

bcb htable[buffersize] //page 2 frame
int htable[buffersize] //frame 2 page

buffer manager 的基本功能

  • fixpage(int page_id):将对应 page_id 的 page 读入到 buffer 中
    • 如果 buffer 已满,则需要执行替换算法
  • fixnewpage()
    • 在插入数据时申请一个新 page 并将其放在 buffer 中
  • selectvictim()
    • 选择换出的 frame_id
  • findframe(int page_id):查找给定的 page 是否已经在某个 frame 中了
  • setdirty(int frame_id)

数据库文件组成

  • 数据文件
    • insert_record --> fixnewpage 创建首块
  • 系统目录文件
    • create_table --> fixnewpage 创建首块

存储管理器

从磁盘中存取物理数据,为 buffer manager 提供 page 抽象

posted @ 2024-01-20 11:20  ConnorLan  阅读(36)  评论(0)    收藏  举报