【问题标题】:How to make atomic operation with both file system and database in Postgres?如何在 Postgres 中对文件系统和数据库进行原子操作?
【发布时间】:2019-01-23 09:38:30
【问题描述】:

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

  • 数据库用于存储文件路径
  • 文件本身存储在文件系统中

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

("文件路径", "实际文件位置")

始终保持一致。

有没有一种规范/简单的方法可以通过 Postgres/Linux 实现这一点?

【问题讨论】:

  • 很难说没有更多的上下文。 “简单”的方法是在您访问文件时锁定数据库记录以防止更新。这对你来说有多实用(以及它对并发性有多大的灾难性)很大程度上取决于你的应用程序。

标签: database postgresql file filesystems atomic


【解决方案1】:

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

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

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

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

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")

【讨论】:

  • 如果有人在修改之前选择了一个路径,然后在文件被删除(通过 os.delete(delete_path))之后尝试读取相应的文件怎么办?也许你做了一些事情让它与“跳过锁定”一起工作?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-25
  • 1970-01-01
相关资源
最近更新 更多