Skip to content

模型Model

页缓存、脏页与回写代际

Page cache and writeback · Dirty page redirty · Buffered file I/O

分离应用缓冲、内核页缓存和设备缓存,追踪同一页回写期间再次变脏,并解释write返回为何不足以证明持久化。

形式陈述 ​

页缓存以(文件对象,文件页号)为键保存文件内容的内存副本。OS-16普通read与write以及shared文件映射使用同一个页缓存对象。buffered write将实际接受的字节复制到缓存,更新必要的文件内存元数据;返回表示该次调用已接受这些字节,不要求设备块此刻稳定。

页缓存中的dirty表示内容相对于已经完成的下层写回尚有更新。writeback表示某一内容版本正由设备请求发送;两者可同时成立。为精确说明再变脏窗口,本页使用单页教学状态(g,c,w):g是当前内容代际,c是已成功完成下层写回的代际,w是当前在途代际或空。每次缓存写递增g,dirty定义为g>c;提交时冻结该代内容快照并置w=g,完成时推进c到该在途代际并清w。

这是OS-16的版本化解释模型,不宣称Linux直接用三个同名计数器。真实实现可使用dirty/writeback位、页锁及重新标脏协议。这里每页至多一个在途回写,设备保持该页版本顺序,失败完成不推进c。

另外记录稳定设备版本s。c推进只表示普通设备命令完成;若设备有易失写缓存,s仍可小于c。页缓存干净不等于数据跨过掉电边界。

直觉

一层缓存完成自己的责任,只说明更新已交给下一层按合同处理。应用的stdio缓冲交给内核、内核页缓存交给设备、设备缓存交给稳定介质,是三个不同的交接点。每个“成功”都应问清它在回答哪一层的问题。

回写也不是暂停世界后拍一张永久照片。设备正在写昨天的版本,应用可以已经改出今天的版本;旧请求完成只能证明昨天那份已送到下层。

例子与边界

一次write和两次回写 ​

inode42稳定内容为abcdefgh,初始g=c=s=0。P在共享offset2处write XY返回2,页缓存为abXYefgh,g=1、c=0、dirty=true;稳定内容仍旧。

事件 当前缓存 (g,c,w) dirty 设备稳定版本s
write XY返回 abXYefgh (1,0,空) 是 0
提交代1快照 abXYefgh (1,0,1) 是 0
应用又把第0B写Z ZbXYefgh (2,0,1) 是 0
代1设备完成 ZbXYefgh (2,1,空) 是 0
提交并完成代2 ZbXYefgh (2,2,空) 否 0
相应flush成功 ZbXYefgh (2,2,空) 否 2

在第四行无条件清dirty会丢掉代2的回写责任;在第五行把干净当持久,会忽略设备易失缓存。若第五行后掉电且设备尚未自行稳定,最终仍可能恢复abcdefgh;第六行后则必须恢复代2。

返回前后可见性与错误不同步 ​

在表第一行write返回后、尚未写Z之前,另一个进程按顺序read同一inode相同区域,OS-16从缓存可读到abXYefgh,即使设备还完全没处理它。这验证了可见性,不验证持久性。反之,设备后来写回失败,错误可能直到fsync才由应用获知;write早先成功不能排除延迟错误。

fwrite还可能仅写到用户态库缓冲,尚无系统调用。调用fsync之前,若所需字节仍在该缓冲中,内核根本无从同步它们;必须先按库接口成功flush,且仍检查后续持久化错误。fflush本身只完成这一层交接。

推论与应用

回写快照要么独立复制,要么通过锁/所有权保证设备看到提交的那一代。若设备DMA读取期间应用直接改同一内存,没有合适同步,就可能发送不同代际混合的字节,不能仅用一个版本号宣称整页一致。

OS-16分别保持0≤s≤g和0≤c≤g,在途w来自提交时g且完成只推进c到w。s和c没有固定大小关系:设备可以在通知完成之前先稳定代1,使s=1而c=0;也可以先通知接收完成而仍未稳定,使c=1而s=0。应用写增加g,回写完成推进c,设备稳定写推进s;成功flush保证所覆盖的写都已稳定,在无新写且最新代已提交的场景得到s=g。这个证明依赖同页写顺序及完整快照;若允许多代在途乱序稳定,就需要阻止旧代覆盖新代的协议。

CPU的缓存dirty块和文件页dirty不处在同一层:CPU回写到DRAM可以让内核看到新字节,却仍没有启动文件I/O。数据库缓冲池也可在用户态再加一层,自己的脏页、pin和事务LSN须与OS页缓存分别记账。

参考资料
关系图谱6 个相邻概念 · 1 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组