是否在所有文件系统上按顺序写入没有查找刷新字节的文件?
Does writing to a file with no seeks flush bytes sequentially on all file systems?
我正在编写 JSON 个文件。这意味着对于每个 '{'
个字符,都有一个对应的 '}'
并且文件中的最后一个字节是 '}'
。写入顺序发生。没有 fseeks。因此,如果写入文件以某种方式中断,我预计会有一个无效的 JSON 文件。
现在一个假设的文件系统可能决定乱序刷新我的字节。这意味着如果在写入期间发生断电,在刷新所有内容之前,我可以获得一个有效的 JSON,其中不包含我想要的数据。我可以使用字符串 "xxx"
,而不是 "yyy"
,或者数字末尾缺少数字。
有这样的文件系统吗?我可以相信如果一个文件是有效的,那么它就一定是完整的吗?
编辑:这个问题是针对如果数据丢失最后一个字节则数据无效的情况。 JSON 在这里是说明性的。技术上 42342
是有效的 JSON,如果不完整则无法验证。
文件系统可能会乱序刷新页面的原因有多种:
- 该页面有来自 2 个文件的数据,另一个文件正在刷新到磁盘。
- 该页面在进程的工作集之外(因此不值得缓存)并且 OS 需要内存用于其他目的。
- 文件系统是分布式的,例如OrangeFS 或 Andrew 文件系统,并按照非常不同的实现规则进行播放。
- 文件系统 NFS 面向更复杂的分布式异构设备集,其中一些写入是完全同步的,应用程序 none 更明智。
不仅是文件系统,还有底层设备。
- 块设备可能会进行缓冲,直到文件系统实际需要完全刷新,并以它认为合适的顺序刷新它(因为它不知道文件的概念)。
- 块设备可以条带化 (RAID 0),这样一个设备可以先于另一个设备刷新。
也就是说,崩溃后像 xxx
这样丢失 3 个字节的情况极不可能发生。它更有可能经历块丢失,例如4096 字节的倍数。
事实是,大多数文件系统对崩溃期间写入的数据(与元数据相反)的完整性几乎没有保证。
当需要原子性时,应用程序通常做的是利用 rename(2)
或其等价物:
- 写入临时文件,例如POSIX
write(2)
.
- 刷新文件,例如使用 POSIX
fsync(2)
并关闭它。
- 将文件重命名为目标名称,例如POSIX
rename(2)
.
我知道所有正在使用的 POSIX 文件系统都以崩溃安全的方式实现 POSIX 重命名,我假设 NTFS 也是如此。
但这显然不是 POSIX 严格要求的。由于您正在编写新文件,所以这不是什么大问题,但如果您想更加偏执,您可以添加另一个步骤:
- 删除临时文件(不存在则忽略错误)
我正在编写 JSON 个文件。这意味着对于每个 '{'
个字符,都有一个对应的 '}'
并且文件中的最后一个字节是 '}'
。写入顺序发生。没有 fseeks。因此,如果写入文件以某种方式中断,我预计会有一个无效的 JSON 文件。
现在一个假设的文件系统可能决定乱序刷新我的字节。这意味着如果在写入期间发生断电,在刷新所有内容之前,我可以获得一个有效的 JSON,其中不包含我想要的数据。我可以使用字符串 "xxx"
,而不是 "yyy"
,或者数字末尾缺少数字。
有这样的文件系统吗?我可以相信如果一个文件是有效的,那么它就一定是完整的吗?
编辑:这个问题是针对如果数据丢失最后一个字节则数据无效的情况。 JSON 在这里是说明性的。技术上 42342
是有效的 JSON,如果不完整则无法验证。
文件系统可能会乱序刷新页面的原因有多种:
- 该页面有来自 2 个文件的数据,另一个文件正在刷新到磁盘。
- 该页面在进程的工作集之外(因此不值得缓存)并且 OS 需要内存用于其他目的。
- 文件系统是分布式的,例如OrangeFS 或 Andrew 文件系统,并按照非常不同的实现规则进行播放。
- 文件系统 NFS 面向更复杂的分布式异构设备集,其中一些写入是完全同步的,应用程序 none 更明智。
不仅是文件系统,还有底层设备。
- 块设备可能会进行缓冲,直到文件系统实际需要完全刷新,并以它认为合适的顺序刷新它(因为它不知道文件的概念)。
- 块设备可以条带化 (RAID 0),这样一个设备可以先于另一个设备刷新。
也就是说,崩溃后像 xxx
这样丢失 3 个字节的情况极不可能发生。它更有可能经历块丢失,例如4096 字节的倍数。
事实是,大多数文件系统对崩溃期间写入的数据(与元数据相反)的完整性几乎没有保证。
当需要原子性时,应用程序通常做的是利用 rename(2)
或其等价物:
- 写入临时文件,例如POSIX
write(2)
. - 刷新文件,例如使用 POSIX
fsync(2)
并关闭它。 - 将文件重命名为目标名称,例如POSIX
rename(2)
.
我知道所有正在使用的 POSIX 文件系统都以崩溃安全的方式实现 POSIX 重命名,我假设 NTFS 也是如此。
但这显然不是 POSIX 严格要求的。由于您正在编写新文件,所以这不是什么大问题,但如果您想更加偏执,您可以添加另一个步骤:
- 删除临时文件(不存在则忽略错误)