【发布时间】:2012-09-04 17:34:52
【问题描述】:
文件中有我想要覆盖的区域(可能很小)。 假设我调用 fseek、fwrite、fsync。有什么方法可以确保这种区域重写操作的原子性,例如我需要确定的是,在任何失败的情况下,该区域将只包含旧的(修改前)数据,或者只包含新的(修改后的)数据,但不能混合使用。
我想强调两件事。
首先:如果没有办法原子地写入任何大小的区域也没关系 - 我们可以通过将数据附加到文件,fsync'ing,然后重写文件中的“指针”区域来处理它,然后再次fsyncing。但是,如果“指针”写入不是原子的,我们仍然可以使用非法指针损坏文件。
第二:我很确定,写入 1 字节区域是原子性的:我不会在文件中看到我从未放入的任何字节。所以我们可以使用一些技巧来为地址分配两个区域并使用 1 字节开关,因此区域的重写变成了 - 追加新数据,同步,重写两个(未使用的)指针槽之一,再次同步,然后重写'switch byte ' 并再次同步。所以覆盖区域操作现在至少包含 3 个 fsync 调用。
所有这一切都会容易得多,如果我将有很长的原子写作,但我真的有吗?
有没有办法在不使用方法的情况下处理这种情况,在第2点中提到?
另一个问题是 - 写入和同步之间是否有任何顺序保证? 例如,如果我调用 fseek、fwrite [1]、fseek、fwrite [2]、fsync,我是否可以在 [2] 处写入,而在 [1] 处写入 - 未提交?
这个问题适用于linux和windows操作系统,任何特定的答案(例如在ubuntu版本a.b.c ....)也需要。
【问题讨论】:
-
fsync 似乎非常依赖于实现/文件系统。 blogs.gnome.org/alexl/2009/03/16/ext4-vs-fsync-my-take
-
你所说的被称为“承诺控制”,或“提交/回滚”,或“交易”。
-
(唯一(几乎)完全可靠的方式来做你想做的事,在盒子上没有一些事务处理设施,是做旧文件交换——将旧文件复制到新文件,更改新文件,重命名新的以替换旧的。)
-
@Hot Licks - 我不能使用文件交换的唯一原因是因为整个文件可能很大 -> 对于任何更改我必须复制它,这会对性能产生影响。
-
在某些版本的 Unix 上,我认为也许可以使用“写时复制”策略来缩短副本。但可能不在 Linux 或 Windoze 上。