【问题标题】:Atomic file modification原子文件修改
【发布时间】: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 上。

标签: java windows unix


【解决方案1】:

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

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

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

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

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

更多信息:Ensure fsync did its job

【讨论】:

  • 感谢您的回复。关于“同步”保证,你能为我提供这个假设的“证据”吗?或者,它来自一些(什么?)源代码跟踪/专家(哪个?)建议?
  • 用一些信息扩充了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-03
  • 1970-01-01
  • 1970-01-01
  • 2017-10-03
  • 2011-01-22
  • 1970-01-01
  • 2011-06-22
相关资源
最近更新 更多