database - 如何在 Postgres 中对文件系统和数据库进行原子操作?
问题描述
我认为以下应该是一个很常见的模式:
- 数据库用于存储文件路径
- 文件本身存储在文件系统中
说我们要修改文件路径时可能会出现问题:我们需要修改数据库文件路径并在文件系统中移动文件。重要的是,这是“原子地”完成的。实际上,当我们进行修改时,另一个进程可能会尝试读取数据数据库中的文件路径,然后尝试访问文件系统中的文件。我们应该确保元组
(“文件路径”,“实际文件位置”)
始终保持一致。
使用 Postgres/Linux 是否有规范/简单的方法来实现这一点?
解决方案
数据库的主要特征之一是进程可以一致地看到它。这也意味着不同的客户端会看到不同的数据库状态。
这意味着当您更正数据库中的文件路径并提交更改时,在提交之前启动的任何事务都可以在提交后的一段时间内看到旧路径。
因此,实际上要确保没有人会尝试读取旧文件路径,您必须等到提交之前的所有事务结束。这可能需要几毫秒,或者在极端情况下需要几天。如果你有一个
我会尝试实现以下方案(伪代码):
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")
推荐阅读
- php - 一个类如何作为函数参数启动?
- android - 如何更改主题然后构建我的应用程序?
- kotlin - 在 java 类中使用来自 kotlin 的挂起函数实现接口
- c# - 强制 Identity Server 子应用程序刷新声明
- javascript - 如何在 Firebase 的 where() 中按引用的属性进行过滤
- java - 如何使用柯里化实现泛型类型
- shopify - Shopify 暂存网店身份验证
- pandas - Jupyterlab 表动态输出(排序,过滤,...)
- firebase - BigQuery - 如何按事件排序
- html - 如何从重复选择框保存的数组中获取每个数据