原子文件修改

时间:2012-09-04 17:34:52

标签: java windows unix

我想要覆盖文件中的区域(可能很小)。 假设我调用fseek,fwrite,fsync。有没有办法确保这种区域重写操作的原子性,例如,我需要确定,在任何情况下失败的区域都只包含旧的(修改前)数据,或者只包含新的(修改过的)数据,但不包含这些数据。

我想强调两件事。

首先:如果没有办法原子地写任何大小的区域就可以了 - 我们可以通过将数据附加到文件,fsync'ing,然后在文件中重写'指针'区域来处理它,然后再次fsyncing。但是,如果'指针'写入不是原子的,我们仍然可以使用非法指针来破坏文件。

第二次:我很确定,写1字节区域是原子的:我不会在文件中看到任何我从未放过的字节。因此我们可以使用一些技巧为地址分配两个区域并使用1字节开关,因此重写区域变为 - 附加新数据,同步,重写两个(未使用的)指针槽中的一个,再次同步,然后重写'切换字节'并再次同步。因此,覆盖区域操作现在至少包含3个fsync调用。

所有这一切都会更加轻松,如果我有长时间的原子写作,但我真的拥有它吗?

有没有办法在不使用第2点中提到的方法的情况下处理这种情况?

另一个问题是 - 写作和同步之间是否有任何顺序保证? 例如,如果我调用fseek,fwrite [1],fseek,fwrite [2],fsync,我可以在[2]提交写入,写入[1] - 不提交吗?

这个问题适用于linux和windows操作系统,任何特定的答案(例如在ubuntu版本a.b.c ....)也是如此。

1 个答案:

答案 0 :(得分:1)

通常可以安全地假设在HDD的一次写入中写入512字节的块。 但是,我不会这么认为。相反,我会使用您的第二个解决方案,同时在更改文件中的指针之前为您的写入添加校验和并验证它。

通常,将校验和添加到写入磁盘的所有内容是一种很好的做法。

要回答“同步”保证 - 您可以认为。虽然同步是FS和磁盘相关的,但我们假设我们正在讨论“合理”的实现。

  • 在第一个sync之后,保证数据被刷新到磁盘(磁盘可能有它 在它的缓存中仍然存在)并且如果您希望得到的数据得到你所写的任何内容。
  • 如果在第二个sync之后,两个同步的数据都在磁盘缓存中,那么您所描述的情况可能会发生,但恕我直言的可能性非常低。

无论如何,没有其他机制可以保证数据在磁盘上。这就是必须有校验和的原因。

更多信息:Ensure fsync did its job