我正在研究如何对文件系统上的文件进行原子(持久)更新的几种可能性。我这样做是因为我想学习和理解它在数据库系统中的工作方式。一些假设:
到目前为止我学到的东西:
基本上,所有操作系统都有一个后写缓冲区,用于保存文件修改,直到调用fsync()
(或类似命令)将更改内容刷新到磁盘为止。
fsync()
本身不是原子的,尤其是在涉及多个内存页面的情况下。
fsync()
是一个相当昂贵的操作,过于昂贵,无法在每次提交时调用。
数据库保留存储所有传入事务的预写日志(WAL)。每隔一定的时间间隔(WAL文件大小或计时器或...)应用更改并进行fsync()
编辑。
在执行查询时,需要考虑WAL中的所有更改,就像这些更改已经是主文件的一部分一样。由于当WAL变大(未建立索引)时,它可能变慢,因此希望尽早刷新WAL。大型WAL文件的成本与将更改刷新到主文件的成本之间似乎需要权衡。
由于fsync()
可能最终将半页写入磁盘(例如,在断电的情况下),因此WAL中的事务接触的所有内存页面也需要复制到WAL中,以便在重新引导系统时可以还原这些页面。 fsync()
命令成功返回后,我们可以从WAL中删除条目。
我的问题:
我到目前为止正确吗?
使用mmap
版本的文件而不是常规文件时,上述任何改变吗?
在我看来,所有这些并不能真正“解决”问题,而只是减少了腐败的可能性。最后,WAL本身是一个文件,需要进行fsync()
加密,这可能会失败。 WAL上的fsync()
比数据文件中的fsync()
便宜吗?
我们是否在每次提交后立即执行fsync()
?即使是我个人认为非常令人不安的高端数据库系统,例如PostGreSQL seem to do this periodically。如果在fsync()
删除WAL文件之前关闭了计算机的电源,我们是否冒着完全丢失提交的风险?
我们如何保护WAL文件以防止由于页面同步不完整而导致数据损坏? WAL的WAL?
任何与该问题有关的学习资源的链接(除了“读取数据库XY的源代码”之外)也将受到高度赞赏。