2013-10-18 45 views
0

我有两个SQLite数据库文件:分期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'

此前的文件实用程序的版本 '4.0', 'MV' 可以移动文件系统之间只有经常 文件。例如,现在“mv”可以将包括来自一个分区 的特殊设备文件的整个 目录层次结构移动到另一个分区。它首先使用'cp -a' 用于复制请求的目录和文件的相同代码,然后(假设复制 成功)它将删除原始文件。如果复制失败,则复制到目标分区的部分 将被删除。

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

我该怎么做才能使这个分期过程可靠?


一些补充说明:

  • 我的客户端API是PHP/PDO,所以我要在SQLite online backup C interface
  • 数据库不能访问是几个GB的大小,所以一些在 - 存储器解决方案可能不是可行

回答

1

你的命令将扩展为:

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

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


为了摆脱这两个-wal-shm文件,更改日记模式下删除;您可以稍后再更改它。 一旦你有一个数据库文件,你可以执行原子重命名来替换它。

请注意WAL模式优化写入;将(只读)生产数据库置于回滚日志模式将是一个更好的主意。

+0

这件事发生在我身上,但我不确定它会是那么简单。在临时数据库上将日志模式更改为DELETE是否足以让生产连接检测到它不再需要'-wal'和'-shm'文件? –

+0

我的担心是,如果我需要将** production **数据库的日志模式更改为DELETE,读者可能会连接到它并因此将日记模式再次更改回WAL(在mv发生之前)。解决这个问题的一种方法是,将锁定模式设置为在两个数据库上独占,但这会破坏未来的读者,并且 - 我不确定 - 如果在特定时间有任何具有共享锁的活动读取器,则可能会失败。 –

+1

活跃阅读者将继续阅读旧文件;他们只有在重新打开新文件时才会看到新文件,即使用新的数据库连接。 –