可靠地暂存SQLite数据库文件

时间:2013-10-18 11:00:52

标签: php sqlite atomic corruption

我有两个SQLite数据库文件:

  • data.db生产
  • data.db.tmp暂存

两个数据库都在WAL journaling mode。此外,登台数据库处于独占锁定模式(使用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*-wal文件的瞬态特性,它不会起作用:如果data.db.tmp-wal没有不存在移动会失败(我想!)并且可能存在的data.db-shm对应物没有原子操作。

根据info coreutils 'mv invocation'

  

在fileutils版本'4.0'之前,'mv'只能定期移动   文件系统之间的文件。例如,现在'mv'可以移动整个   目录层次结构,包括来自一个分区的特殊设备   到另一个。它首先使用'cp -a'使用的一些相同代码   复制请求的目录和文件,然后(假设副本   它取消了原件。如果复制失败,那么部分   已删除复制到目标分区的内容。

重命名整个文件夹也不是原子文件。

如何才能使此暂存过程可靠?


其他一些评论:

  • 我的客户端API是PHP / PDO,因此我无法访问SQLite online backup C interface
  • 数据库的大小为几GB,因此一些内存中的解决方案可能不可行

1 个答案:

答案 0 :(得分:1)

您的命令扩展为:

mv data.db.tmp data.db.tmp-wal data.db data.db-wal

无论如何,多个文件系统操作不是原子操作。


要删除-wal-shm文件,请将日记帐模式更改为DELETE;你以后可以改回来。 一旦有了单个数据库文件,就可以执行原子重命名来替换它。

请注意,WAL模式可以优化写入;将(只读)生产数据库保留为回滚日志模式是个更好的主意。