【问题标题】:File durability settings文件持久性设置
【发布时间】:2025-12-15 10:10:02
【问题描述】:

我正在开发 ACID 数据库软件产品,我对 WinOS 上的文件持久性有一些疑问。

CreateFile 有两个属性,FILE_FLAG_WRITE_THROUGHFILE_FLAG_NO_BUFFERING - 我是否需要这两个属性来实现文件持久性(即覆盖各种磁盘或操作系统文件缓存) ?我问,因为他们似乎做同样的事情,并设置 FILE_FLAG_NO_BUFFERING 导致WriteFile 抛出一个 ERROR_INVALID_PARAMETER 错误。

【问题讨论】:

  • 您在使用 FILE_FLAG_NO_BUFFERING 时收到的错误是因为您使用的缓冲区的内存地址(用于读取或写入)未正确对齐。请参阅this article,了解为什么会出现这种情况,以及放弃缓冲 IO 系统的好处和潜在缺陷。

标签: c++ windows file


【解决方案1】:

FILE_FLAG_NO_BUFFERING 指定不缓存。没有读写缓存,所有数据都直接进出您的应用程序到磁盘。如果您读取如此大的块以致缓存无用,或者您自己进行缓存,这将非常有用。 注意 WhozCraig 关于在使用此标志时正确对齐数据的评论。

FILE_FLAG_WRITE_THROUGH 仅表示在函数返回之前写入应直接写入磁盘。这足以实现 ACID,同时它仍然为操作系统提供了从文件中缓存数据的选项。

使用FlushFileBuffers() 可以提供一种更有效的方法来实现 ACID,因为您可以对文件进行多次写入,然后一次性刷新它们。在一次刷新中组合写入非常重要,因为非缓存写入会限制您的硬盘驱动器的主轴速度。对于 7200 rpm 磁盘,每秒最多 120 次非缓存写入或刷新。

【讨论】:

  • 您对 FILE_FLAG_NO_BUFFERING 的描述并不完全准确。它确实告诉 IO 系统不要为读取或写入设置缓冲区。但是,您缺少的关键数据是ReadFileWriteFile 调用期间提供的任何缓冲区的对齐要求。您提供的缓冲区必须位于与文件所在卷的扇区大小的偶数倍对齐的内存上。有关这方面的更多信息,请参阅this article
  • 我们有自己的缓冲区管理器来处理磁盘扇区到内部内存缓存,您是否仍然推荐 FILE_FLA_WRITE_THROUGH 而不是 FILE_FLAG_NO_BUFFERING?两者之间有性能差异吗?对于 FlushFileBuffers,我认为我们不应该这样做,因为我们需要刷新单个磁盘扇区 - 我们的磁盘管理器处理所有多线程文件访问逻辑,包括正确的磁盘扇区刷新。
  • 很难说。操作系统缓冲的开销很小,所以我怀疑通过关闭它你会获得很多收益,并且在某些情况下通过保持开启它可能会有所收获......我认为最好对其进行测试。