【问题标题】:How to update part of a file atomically?如何以原子方式更新文件的一部分?
【发布时间】:2018-08-25 16:08:13
【问题描述】:

我有一个大文件(几 GB),我想更新其中的一小部分(用新值覆盖一些字节)。这必须以原子方式完成(要么操作成功,要么文件保持不变)。我该怎么做?

目的是将进度信息存储在需要大量时间来生成/上传的文件中(它可以在远程文件系统上)。可能有时我需要在文件的不同位置写入(并一次提交所有更改),但如果需要,我可以重写整个索引,这是一个连续的块,与文件的其余部分相比相对较小.在任何给定时间,只有一个进程和线程写入文件。

【问题讨论】:

  • 您计划使用 node.js 并期望对远程文件系统进行原子更新,直至并包括“在文件的不同位置写入(并一次提交所有更改)”?即使对于本地文件系统,node.js 也无法提供those kinds of guarantees
  • 你能在所有写入之前完成所有读取吗?

标签: node.js linux filesystems sshfs


【解决方案1】:

普通磁盘不是事务性的,也不提供原子性保证。 如果底层文件系统不提供原子写入(并且大多数不提供),那么您需要在自己的应用程序/数据结构中创建原子性。这可以通过日志(就像许多文件系统和数据库一样)、写时复制技术等来完成。

在 Windows 中,事务性文件系统 (TxF) 功能完全可以满足您的需求 - 但您的应用程序需要明确使用 Win32 事务性文件 I/O API 来实现。

【讨论】:

  • 确实,我得出的结论是,编写自己的事务日志(日志系统)是我的案例的最佳解决方案。我选择了一个固定大小的通用更新日志,加上两个完整性哈希码:一个用于实际数据,一个用于事务日志。如果至少有一个哈希值,则该文件是有效的(这是由我在写另一个之前完成写一个事实来保证的)。如果实际数据没有通过哈希检查,我读取日志以恢复以前的版本(必须通过哈希检查)。我接受您的回答,因为其他建议是“仅”cmets。
【解决方案2】:

我觉得简单的lockfile就足够了……

例如proper-lockfile:

const lockfile = require('proper-lockfile');

lockfile.lock('some/file')
  .then(() => doStuff())
  .finally(() => lockfile.unlock('some/file'));

请注意,任何使用some/file 的逻辑都必须尊重lockfile

【讨论】:

  • 感谢您的回答。我没有锁定问题,我有原子性问题。我想防止我的文件在更新时损坏(每次原子更新都必须生成有效文件)。潜在问题可能是(进程或整个服务器的)崩溃、重新启动、远程文件系统的网络问题等。另一方面,我没有有并发进程试图读取或写入文件。
  • 我明白了,这更复杂......我不知道如何在系统级别上确保这一点 - 我认为这是不可能的。您可能必须编写transaction log 并自己实现回滚。我将把答案原样保留在这里,我会再考虑一下这个问题 - 如果我想出一些东西,我会发布更新。
  • 感谢事务日志指针;这似乎确实是解决这个问题的一种方法。但在我的情况下可能太复杂了。最后也许我会放弃单个文件的想法,将我的进度数据放在一个单独的文件中,并在需要时完全覆盖它(使用原子文件移动)。
  • (write to temp file + rename ) 是最简单的方法。如果您的文件系统支持引用链接 (XFS/BTRFS),您可以将引用链接文件用于要更新的​​临时副本。这样可以节省一些磁盘空间。
  • 感谢 reflink 指针。我确实知道写时复制,它可以解决我的问题,但如果可能的话,我还没有搜索。目前我正在使用 sshfs 访问文件,但我希望我的解决方案尽可能通用,所以我现在不探索这种可能性。我已经开始研究一个简单的事务日志系统,我认为它会更便携。
猜你喜欢
  • 2014-12-06
  • 1970-01-01
  • 2013-04-17
  • 1970-01-01
  • 1970-01-01
  • 2020-06-10
  • 1970-01-01
相关资源
最近更新 更多