首页 文章

如何在POSIX中持久重命名文件?

提问于
浏览
16

在POSIX文件系统中持久重命名文件的正确方法是什么?特别想知道目录上的fsyncs . (如果这取决于OS / FS,我问的是Linux和ext3 / ext4) .

Note :StackOverflow还有其他关于持久重命名的问题,但AFAICT他们甚至没有修改文件数据 .

我目前有(在Python中):

dstdirfd = open(dstdirpath, O_DIRECTORY|O_RDONLY)
rename(srcdirpath + '/' + filename, dstdirpath + '/' + filename)
fsync(dstdirfd)

Specific questions

  • 这是否也暗含fsync源目录?或者我可能会在电源循环后最终显示两个目录中显示的文件(这意味着我无法保证持久的原子移动操作?

  • 如果我fsync源目录而不是目标目录,那还会隐式fsync目标目录吗?

  • 是否有任何有用的相关测试/调试/学习工具(故障注入器,内省工具,模拟文件系统等)?

提前致谢 .

4 回答

  • -4

    Unfortunately Dave’s answer is wrong.

    并非所有POSIX系统都可能具有持久存储 . 如果他们这样做,它仍然被“允许”在系统崩溃后被冲洗 . 对于那些系统,no-op fsync()是有意义的,并且在POSIX下明确允许这样的fsync() . 在旧目录,新目录,两者或任何其他位置可以恢复文件也是合法的 . POSIX不保证系统崩溃或文件系统恢复 .

    真正的问题应该是:

    How to do a durable rename on systems which support that through the POSIX API?

    您需要在源目录和目标目录上执行fsync(),因为fsync()s应该执行的最小值是持久化源目标或目标目录应该是什么样子 .

    Does a fsync(destdirfd) also implicitly fsync the source directory?

    • POSIX一般:不,没有任何暗示

    • ext3 / 4:我不确定源和目标dir的更改是否都会在日志中的同一事务中结束 . 如果他们这样做,他们两个都会在一起 .

    Or might I end up with the file showing up in both directories after a power cycle (“crash”), i.e. it's impossible to guarantee a durably atomic move operation?

    • POSIX一般:没有保证,但你应该fsync()两个目录,这可能不是原子耐用的

    • ext3 / 4:您最低需要多少fsync()取决于挂载选项 . 例如 . 如果使用“dirsync”安装,则不需要任何这两个fsync() . 最多你需要两个fsync(),但我几乎可以肯定一个就足够了(原子耐用) .

    If I fsync the source directory instead of the destination directory, will that also implicitly fsync the destination directory?

    • POSIX:没有

    • ext3 / 4:我真的相信两者都会在同一个事务中结束,所以你fsync中的哪一个并不重要()

    • 较旧的内核ext3 :(如果它们不在同一个事务中)一些不那么优化的实现在fsync()上实现了太多的同步,我敢打赌它确实提交了之前的每个事务 . 是的,正常的实现首先将它链接到目标,然后从源中删除它 . 所以fsync(srcdirfd)也会触发目标的fsync() .

    • ext4 / latest ext3:如果它们不在同一个事务中,您可以独立完全同步它们(两者都是如此)

    Are there any useful related testing/debugging/learning tools (fault injectors, introspection tools, mock filesystems, etc.)?

    对于真正的崩溃,没有 . 顺便说一句,真正的崩溃超出了内核的观点 . 硬件可能会重新排序写入(并且无法写入所有内容),从而破坏文件系统 . Ext4对此做了更好的准备,因为它默认启用写入barries(挂载选项)(ext3没有)并且可以使用日志校验和(也是挂载选项)检测损坏 .

    并且为了学习:找出两个变化是否在期刊中以某种方式相关联! :-P

  • -1

    POSIX定义重命名函数必须是原子的:

    http://pubs.opengroup.org/onlinepubs/009695399/functions/rename.html

    因此,如果重命名(A,B),在任何情况下都不应该在两个目录或两个目录中都看到该文件的状态 . 无论你使用fsync()做什么或系统是否崩溃,总会有一个 .

    但这并没有解决确保rename()操作持久的问题 . POSIX回答了这个问题:

    如果定义了_POSIX_SYNCHRONIZED_IO,则fsync()函数将强制与文件描述符fildes指示的文件关联的所有当前排队的I / O操作进入同步I / O完成状态 . 所有I / O操作都应按照同步I / O文件完整性的定义完成 . (来自http://pubs.opengroup.org/onlinepubs/009695399/functions/fsync.html)

    因此,如果fsync()是一个目录,则必须在返回时将挂起的重命名操作传输到磁盘 . 任一目录的fsync()都应该足够了,因为rename()操作的原子性要求两个目录的更改都是原子同步的 .

    最后,与另一个答案中提到的博客文章中的声明相反,其基本原理解释了以下内容:

    fsync()函数用于强制从缓冲区高速缓存中物理写入数据,并确保在系统崩溃或其他故障之后,直到fsync()调用时的所有数据都记录在磁盘上 . 由于此处未定义“缓冲区缓存”,“系统崩溃”,“物理写入”和“非易失性存储”的概念,因此措辞必须更多抽象 .

    声称符合POSIX并且认为完成fsync()并且不会在系统崩溃中持续存在这些更改的正确行为(即不是错误或硬件故障)的系统将不得不故意歪曲自己的规范 .

    (更新了附加信息:特定于Linux的可移植行为)

  • 14

    听起来像你正试图完成文件系统的工作 . 如果移动文件,内核和文件系统负责原子操作和故障恢复,而不是代码 .

    无论如何,这篇文章似乎解决了关于fsync的问题:http://blogs.gnome.org/alexl/2009/03/16/ext4-vs-fsync-my-take/

  • 12

    您的问题的答案将在很大程度上取决于所使用的特定操作系统,正在使用的文件系统的类型以及源和目录是否在同一设备上 .

    我首先阅读您正在使用的平台上的rename(2)手册页 .

相关问题