【问题标题】:Atomically swap contents of two files on Linux在 Linux 上原子交换两个文件的内容
【发布时间】:2015-01-09 13:50:54
【问题描述】:

我有两个文件,AB,每个文件都有自己的内容。

我想交换这两个文件,所以A 会变成B,而B 会变成A。但是我想保证没有其他进程会发现这两个文件处于不一致状态,也没有任何进程会发现这些文件中的任何一个丢失,即使是很短的时间。所以,作为一个副业,我也想保证,如果在操作过程中出现任何问题,什么都不会改变(我猜有点像交易)。

在 OS X 上,有一个 exchangedata() 函数,所以我想我正在寻找一个与它等效的 Linux,或者至少是一种用于执行原子文件交换的等效方法。

【问题讨论】:

  • @Frédéric Hamidi - 你发布的问题的答案根本不符合我的标准,所以我想这不是重复的。
  • 我认为那里的答案会适合你,但我猜你不想在出现问题时留下一个临时文件?
  • 是的,而且我想保证我不会删除原始文件。如果第一步成功,我将有效地删除该文件。然后,如果第二步失败,我将不得不回滚。如果回滚也失败了,我会因为破坏客户的系统而陷入困境;)

标签: linux libc


【解决方案1】:

您可以使用(最近的)linux syscall renameat2

这是定义:

int renameat2(int olddir, const char *oldname, 
      int newdir, const char *newname, unsigned int flags);

如果需要,您可以在the kernel's Git repo 上找到它的源代码。

它与renameat 基本相同,但如果您传递标志 RENAME_EXCHANGE,它将交换两个文件,而不是将一个重命名为另一个。

操作是原子的。

【讨论】:

  • 描述这个系统调用的内核文档文档可以在here找到。
【解决方案2】:

我取决于您所说的“不一致状态”是什么意思。如果有一段时间两个文件相同是可以接受的,那么你可以简单地这样做:

ln A C
ln B D
ln -f D A  
# now, A and B have the same content
ln -f C B

这还取决于您希望已打开文件的进程的行为。请记住,路径是不是文件,而只是链接到一个文件,所以如果进程 1 通过路径“A”打开一个文件,然后你交换名称 A 和 B,进程 1 仍然有以名称 A 引用的打开的文件。

【讨论】:

  • 欢迎对不赞成票作出解释。这解决了所提出的问题,但需要注意的是所解决问题的歧义。
  • 我做了一些实验,似乎使用-f 标志无法满足“原子性”约束,因为ln 工具使用unlink 在创建之前删除目标路径带有link 函数的链接。所以ln -f 并不是真正的原子,当文件不存在时有一个(非常短暂但仍然)时间窗口。考虑到这一点,简单地通过使用临时文件名重命名进行交换似乎也能做同样的事情。
猜你喜欢
  • 1970-01-01
  • 2016-10-24
  • 2011-07-09
  • 1970-01-01
  • 2014-12-29
  • 2019-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多