3

假设我有一组文件。如何确保写入所有这些文件是原子的。

我考虑过写入临时文件,只有在写入成功后,才对每个文件执行原子重命名。然而,一次重命名所有文件并不是原子的。如果我们想附加到这些文件,这也不会扩展到非常大的文件。

相反,我考虑过实施交易,但这本身就变成了一个项目。我意识到这几乎是关于实现一个迷你数据库。

你会如何在 Python 中做到这一点?

d = FileWriter.open(['file1', 'file2'], 'wb+')
d.write('add hello world to files')
d.close()

如果不成功,请确保 d.write 是原子的或至少回滚到原始文件。

4

4 回答 4

5

这就是我的想法。首先确保 open 是同步的,然后执行以下操作:

  1. 写入临时文件:file1~、file2~和特殊文件success~(必须先写入)。
  2. 写入成功后,删除文件成功~。
  3. 将文件重命名为 file1 和 file2。

如果出现问题:

  1. 检查是否成功~存在。
  2. 如果是这样,请不要费心修理。由于文件未更新(未重命名),因此已隐式执行回滚。
  3. 如果success~不存在,则在写入后和重命名过程中出现问题。在这种情况下,修复就像将 filex~ 重命名为 filex 一样简单。
于 2012-08-18T23:27:11.943 回答
1

在当前声明中,您的要求是如此通用,以至于唯一合理的答案是操作系统级别的支持是必要的,而且它甚至不再是严格意义上的 Python 相关问题。查看有关事务文件系统的内容,例如此处此处。关于迄今为止提出的解决方案的一小段摘录:

如果没有文件系统事务,即使不是不可能,确保跨多个文件系统操作的一致性也是很困难的。文件锁定可用作单个文件的并发控制机制,但它通常不保护目录结构或文件元数据。例如,文件锁定不能防止符号链接上的 TOCTTOU 竞争条件。文件锁定也不能自动回滚失败的操作,例如软件升级;这需要原子性。

所以我建议重新考虑你的问题(也许你的问题也是?)并更详细地分析你的要求。最重要的是,您需要的保证越少,您能找到的解决方案就越简单。也许您可以摆脱像文件锁定这样简单的事情,或者您会发现需要一个数据库。

说到这一点,如果您正在考虑文件系统,因为您的体系结构的组件需要访问文件,您是否考虑过FUSE作为在常规数据库之上构建类似文件系统的外观的一种方式?使用python-fuse轻而易举。

于 2012-08-20T05:38:57.600 回答
0

您可以尝试使用flock来实现您的目标。可以在 python 中使用fcntl.flock. 请注意,这只是一个建议措施。要真正保证您想要什么,您应该尝试使用支持严格锁定的数据库或文件系统/内核。

于 2012-08-18T23:10:07.623 回答
0

数据库管理系统通常要么只使用一个预写日志文件,要么使用自定义文件系统,原因是通常的文件系统在保证原子性或执行顺序方面确实很糟糕。

它们针对一致性和性能进行了全面优化。

因此,只有写入单个文件的顺序是可信的,除非您使用专门的文件系统创建分区或映像文件。

但是,您可以在每次写入多个文件时写入事务编号。

并明确写入是否完整,例如使用带有开始/结束标记(如 <element>...</element> 或 { ... } 等)的 xml 或 json 样式块。

然后,您的代码可以轻松检测跨多个文件的任何间隙并确定崩溃后的最后一致状态。

为了避免崩溃后的最后一个一致状态因为一些写入在缓存中等待了几分钟而结束,所以这些方法中的任何一种都可以与 sync / fsync 结合使用。

使用sync / fsync 也使事务提交成为可能,即保证至少从文件系统的角度来看,到目前为止的所有内容都是写入的。

但是,您的存储系统可能仍然会因为断电而丢失最后一次写入,无论是硬盘还是带有内部缓存的 SSD、NAS 等。这些系统提供的保证可能千差万别,这是所有方法都需要考虑的挑战,无论是使用文件系统还是传统的 RDBMS 进行存储。

如果您要写入内置硬盘或 SSD,使用 UPS 绝对是一个很好的补充,尤其是当您在 USP 发出信号时以受控方式关闭系统时 ^^

于 2017-03-06T08:22:56.927 回答