侧边栏壁纸
博主头像
ProSayJ 博主等级

Talk is cheap. Show me the code.

  • 累计撰写 35 篇文章
  • 累计创建 16 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

08-Flush链表

YangJian
2025-06-28 / 0 评论 / 0 点赞 / 3 阅读 / 0 字

1. 脏数据页到底为什么会脏?

接下来,我们来探讨一个关键问题。当你在执行增、删、改操作时,如果发现数据页尚未缓存,系统就会通过 free 链表找到一个空闲的缓存页,并将数据页从磁盘读取到该缓存页中。而如果数据页已经存在于缓存中,那么下一次访问时就会直接使用缓存页,无需再从磁盘读取。

无论是哪种情况,你需要更新的数据页都会驻留在 Buffer Pool 的缓存页中,使你能够在内存中直接执行增删改操作。

然而,当你对缓存页中的数据进行修改后,会导致缓存页中的数据与磁盘上的数据页内容出现不一致的情况。此时,我们称该缓存页为“脏页”,即缓存中的数据已被修改,但尚未同步回磁盘。

2. 哪些缓存页属于脏页呢?

在之前的学习中,我们已经了解到,所有在内存中被修改过的脏页最终都会被刷新回磁盘文件。但这里就涉及到一个问题——并不是所有的缓存页都会被刷回磁盘。因为有些缓存页只是单纯地被查询时读取到 Buffer Pool,并没有发生任何修改,自然也就不需要写回磁盘。

为了解决这个问题,数据库引入了一个与 free 链表类似的 flush 链表。它的本质同样是利用缓存页的描述数据块中的两个指针,将所有被修改过的缓存页的描述数据块串联成一个双向链表。

凡是发生过修改的缓存页,其对应的描述数据块都会被加入到 flush 链表中。flush 的含义即表示这些缓存页都是脏页,后续需要被刷新(flush)到磁盘上。

因此,flush 链表的结构与 free 链表非常相似,只不过它专门用于追踪需要写回磁盘的脏页。

3. flush 链表构造的伪代码演示

下面我们用伪代码演示 flush 链表的构造过程。例如,当缓存页 01 的数据被修改后,它就变成了脏页,因此需要将其加入到 flush 链表中。

假设此时缓存页 01 的描述数据块如下所示:

// 描述数据块
DeccriptionDataBlock {
    //这个是缓存页01的数据块
    block_id = block01
    int count;
    free_pre = null
    free_next = null
    flash_pre = null
    flash_next = null  
}
FlashLinkListBaseNode {
    start = block01
    end = block01
    // flush链表中有几个节点
    count = 1
}

我们可以看到,现在flush链表的基础节点就指向了一个block01的节点,接着比如缓存页02被更新了,他也是脏页了,此时他的描述数据块也要被加入到flush链表中去:

// 描述数据块
DeccriptionDataBlock {
    //这个是缓存页01的数据块
    block_id = block01
    free_pre = null
    free_next = null
    flash_pre = null
    flash_next = block02  
}
DeccriptionDataBlock {
    //这个是缓存页01的数据块
    block_id = block02
    free_pre = null
    free_next = null
    flash_pre = block01
    flash_next = null
}

FlashLinkListBaseNode {
    start = block01
    end = block02
    // flush链表中有几个节点
    count = 2
}

当更新缓存页时,可以通过调整缓存页描述数据块中的 flush 链表指针,将所有脏页的描述数据块串联成一个双向链表,即 flush 链表。此外,flush 链表的基础节点会维护头节点和尾节点的指针,以便快速定位整个链表的起始和末尾位置。

借助 flush 链表,数据库能够清晰地记录哪些缓存页已经被修改,标记为脏页,并在适当的时候将这些脏页的数据刷新回磁盘,确保数据持久化和一致性。

0

评论区