eud*_*xos 18 kernel open-files
我依稀记得曾经在某个地方读过,在某些 Unices 中,一种打开现有文件进行写入的方法,带有一个标志,要求内核使用旧版本(供其他进程访问它以进行读取),直到“新的" 版本已完全写入(fd 关闭),从那时起该文件显示为新版本。
换句话说,其他进程要么看到旧版本,要么看到新版本,从来没有一个不完整的版本。
有知识的人可以给我指点参考吗?
phe*_*mer 14
您所描述的听起来与覆盖文件的基本重命名完全一样。
当您将一个文件重命名/移动到另一个文件之上时,旧文件将被取消链接。这意味着该文件仍然存在,但它不再在文件系统树中。因此,只要旧应用程序保持打开状态,它们就可以继续访问该文件。一旦所有应用程序都关闭了旧文件,那么它实际上未分配到磁盘上。
该rename系统调用是一个原子操作。为此,您需要使用不同的名称创建一个新文件,然后调用rename将临时文件重命名为要替换的文件。由于操作是原子的,因此绝对没有丢失文件的时间段。它立即从旧文件转到新文件。
请注意,临时文件和被替换的文件必须驻留在同一个挂载点上。
正如帕特里克所写,通常的做法是将新版本写入一个单独的文件,完成后将新版本重命名为旧文件名,以原子方式覆盖它。第二个操作称为overwrite-by-rename。
ISO C 要求rename是原子的。从开放组基本规范:
如果new参数命名的链接存在,则应将其删除并将旧的重命名为 new。在这种情况下,在整个重命名操作期间,名为new的链接应该对其他进程保持可见,并在操作开始之前引用new或old引用的文件。
出于性能原因,Btrfs 显然故意违反了标准,不保证原子重命名。但是,通过重命名覆盖仍然是原子的,这就是您为此目的所需要的。
这让我想起Allocate On Flush。当文件系统使用此功能时,它不是直接将数据写入磁盘,而是从磁盘的可用空间计数器中减去要写入的数据的大小,并将数据保存在内存中,直到执行同步系统调用或内核决定刷新脏缓冲区。
在这种情况下,如果文件正在被一个进程修改,并被另一个进程打开,则后一个进程将“看到”文件的未修改(或“旧” )版本。
当然,以上是理论上的,取决于各种因素,我想说有点不可预测 - 因为你不知道内核何时会刷新脏页。例如,在 Linux 中(您也可以阅读《理解 Linux 内核》的 15.3 节),脏页在以下条件下被写入磁盘:
页面缓存太满,需要更多页面,或者脏页面数量变得太大。
自从页面保持脏状态以来已经过去了太多时间。
进程请求刷新块设备或特定文件的所有挂起更改;它通过调用sync()、fsync()或fdatasync()系统调用来实现这一点。
已知此功能已在 HFS+、XFS、Reiser4、ZFS、Btrfs 和 ext4 文件系统中实现。
| 归档时间: |
|
| 查看次数: |
9871 次 |
| 最近记录: |