File io 在非事务文件系统中实现原子文件写入
许多常见的文件系统不提供原子操作,但在某些情况下,以原子方式编写文件非常重要。我试图想出解决这个问题的办法 我做了以下假设:File io 在非事务文件系统中实现原子文件写入,file-io,transactions,filesystems,atomicity,File Io,Transactions,Filesystems,Atomicity,许多常见的文件系统不提供原子操作,但在某些情况下,以原子方式编写文件非常重要。我试图想出解决这个问题的办法 我做了以下假设: 正在使用的文件系统支持inode级别的原子操作(例如,NTFS)。这意味着移动和删除是原子的 只有程序本身才能访问这些文件 一次只有一个程序实例,它以单线程方式运行 为简单起见,每次都会写入整个文件内容(即截断写入) 这就留下了以下问题:在编写文件时,程序可能会被中断,文件只剩下部分内容要写 我提议以下进程: 将新内容写入临时文件新建 将原始文件原始移动到临时备份位置
- 正在使用的文件系统支持inode级别的原子操作(例如,NTFS)。这意味着移动和删除是原子的
- 只有程序本身才能访问这些文件
- 一次只有一个程序实例,它以单线程方式运行
- 为简单起见,每次都会写入整个文件内容(即截断写入)
- 如果新的存在,但备份不存在,则我们在步骤1中或之后崩溃。删除新的,因为它可能不完整
- 如果存在新的,并且备份也存在,那么我们在第2步之后崩溃了。继续执行步骤3
- 如果备份存在,但新的也不存在,则我们在第3步后崩溃。继续执行步骤4
- 使用同一程序的多个实例时,恢复过程会干扰其他程序中当前正在进行的文件写入
- 只读不写的外部程序通常会得到正确的结果,但如果同时对请求的条目执行写入操作,它们可能会错误地找不到条目
最后,我的问题是:这有意义吗,还是过程中存在缺陷?是否有任何问题妨碍了这种方法在实践中的应用?您的步骤可以进一步简化:
我曾在管理配置文件时使用过此方法,但在此过程中从未遇到过问题。您只需假设一件事,重命名文件是原子操作 因此,以下步骤将确保纠正(至少在类unix操作系统上)
这样,如果应用程序在重新启动时崩溃,它可以在不需要额外代码的情况下获取旧内容或新内容。我为此编写了一些C#代码,我可以根据请求添加它,但问题已经有一英里长了。这不起作用,因为必须删除旧文件才能启用重命名。@mafurt:not true;重命名可能会覆盖(至少在Unix上)。警告:某些文件系统不保证在提交元数据之前将数据块写入磁盘。在这种情况下,您可能必须在写入临时文件后但在重命名之前调用
fdatasync()
或等效程序。您假定指定的操作按顺序进行。并不是每个文件系统都能保证这一点。@CodeInChaos:这太糟糕了:(所以我必须在步骤之间刷新fs缓冲区?继续你的想法,我听说硬盘会忽略刷新请求。。。