如果我们修改了Buffer Pool中某个缓冲页的数据,那么它就与磁盘上的页不一致了,这样的缓冲页也被称之为脏页(dirty page)。
为了性能问题,我们每次修改缓冲页后,并不着急立刻把修改刷新到磁盘上,而是在未来的某个时间点进行刷新操作。
如果有了修复发生,不是立刻刷新,那之后再刷新的时,我们怎么知道Buffer Pool中哪些页是脏页,哪些页从来没有被修改过呢?
创建一个存储脏页的链表,凡是被修改过的缓冲页对应的控制块都会作为节点加入到这个链表中。该链表也被称为flush链表。
flush链表的结构与free链表差不多,flush链表的结构如下图所示:
是否会存在一个控制块既是free链表的节点,也是flush链表的节点吗?
不会的。因为如果一个缓冲页是空闲的,那它肯定不可能是脏页。反之亦然。
后台有专门的线程负责每隔一段时间就把脏页刷新到磁盘。这样就不影响用户线程处理正常的请求了。
刷新方式有哪几种?
(1)、从flush链表中刷新一部分页面到磁盘
1、后台线程会根据当时系统的繁忙程度确定刷新速率,定时从flush链表中刷新一部分页面到磁盘。即:BUF_FLUSH_LIST
2、有时后台线程刷新脏页的进度比较慢,导致用户准备加载一个磁盘页到Buffer Pool中时没有可用的缓冲页。此时,就会尝试查看LRU链表尾部,看是否存在可以直接释放掉的未修改缓冲页。如果没有,则不得不将LRU链表尾部的一个脏页同步刷新到磁盘(与磁盘交互是很慢的,这会降低处理用户请求的速度)。即:BUF_FLUSH_SINGLE_PAGE
(2)、从LRU链表的冷数据中刷新一部分页面到磁盘,即:BUF_FLUSH_LRU
1、后台线程会定时从LRU链表的尾部开始扫描一些页面,扫描的页面数量可以通过系统变量innodb_lru_scan_depth来指定,如果在LRU链表中发现脏页,则把它们刷新到磁盘。
2、控制块里会存储该缓冲页是否被修改的信息,所以在扫描LRU链表时,可以很轻松地获取到某个缓冲页是否是脏页的信息。