首页 > 解决方案 > 如何在 Postgres 中对文件系统和数据库进行原子操作?

问题描述

我认为以下应该是一个很常见的模式:

说我们要修改文件路径时可能会出现问题:我们需要修改数据库文件路径并在文件系统中移动文件。重要的是,这是“原子地”完成的。实际上,当我们进行修改时,另一个进程可能会尝试读取数据数据库中的文件路径,然后尝试访问文件系统中的文件。我们应该确保元组

(“文件路径”,“实际文件位置”)

始终保持一致。

使用 Postgres/Linux 是否有规范/简单的方法来实现这一点?

标签: databasepostgresqlfilefilesystemsatomic

解决方案


数据库的主要特征之一是进程可以一致地看到它。这也意味着不同的客户端会看到不同的数据库状态。

这意味着当您更正数据库中的文件路径并提交更改时,在提交之前启动的任何事务都可以在提交后的一段时间内看到旧路径。

因此,实际上要确保没有人会尝试读取旧文件路径,您必须等到提交之前的所有事务结束。这可能需要几毫秒,或者在极端情况下需要几天。如果你有一个

我会尝试实现以下方案(伪代码):

sql("begin")
os.hardlink(old_path, new_path)
sql("update files set path=? where path=?, new_path, old_path)
sql("insert into files_to_clean values (?, txid_current())", old_path)
sql("commit")

if random()<CLEANUP_PROBABILITY:
  sql("begin")
  for delete_path in sql("
    delete from files_to_clean
    where txid<txid_snapshot_xmin(txid_current_snapshot())
    returning path skip locked
  "):
    os.delete(delete_path)
  sql("commit")

推荐阅读