我有两个 SQLite 数据库文件:
data.db
(生产)data.db.tmp
(分期)
两个数据库都处于WAL 日志模式。此外,暂存数据库处于独占锁定模式(使用PRAGMA locking_mode
),只有一个读取器/写入器,而生产数据库处于共享/正常锁定模式,具有多个读取器而没有写入器。
在任何给定时间点,文件结构可能如下所示:
data.db
data.db-shm
data.db-wal
data.db.tmp
data.db.tmp-wal
有时,我会想用临时数据库替换生产数据库——最好不要破坏现有的 [生产] 阅读器,更重要的是,不要破坏数据库。
我最初(幼稚)的想法很简单mv data.db-tmp data.db
,但是因为有多个相关文件,单个重命名并不能保证原子性或一致性。然后我想到了做一个支撑mv
:
mv data.db{.tmp,.tmp-wal} data{.db,.db-wal}
我不知道上面是否是原子操作,但考虑到*-shm
and*-wal
文件的瞬态性质,它不会很好地工作:如果data.db.tmp-wal
不存在,则移动将失败(我认为!)并且没有原子操作对于可能存在的data.db-shm
对应物。
根据info coreutils 'mv invocation'
:
在 fileutils 的“4.0”版本之前,“mv”只能在文件系统之间移动常规文件。例如,现在“mv”可以将包括特殊设备文件在内的整个目录层次结构从一个分区移动到另一个分区。它首先使用“cp -a”使用的一些相同代码来复制请求的目录和文件,然后(假设复制成功)它会删除原始文件。如果复制失败,则删除复制到目标分区的部分。
重命名整个文件夹也不是原子的。
我可以做些什么来使这个分期过程可靠?
一些补充说明:
- 我的客户端API是PHP/PDO,所以无法访问SQLite在线备份C接口
- 数据库大小为几 GB,因此某些内存解决方案可能不可行