2

我在使用这些标志编译的 WAL 模式下使用 SQLite 3:

#define SQLITE_ENABLE_FTS3 1
#define SQLITE_THREADSAFE 2
#define SQLITE_DEFAULT_MEMSTATUS 0
#define SQLITE_ENABLE_STAT4 1
#define SQLITE_MAX_MMAP_SIZE 0
#define SQLITE_OMIT_DEPRECATED 1
#define SQLITE_OMIT_SHARED_CACHE 1
#define SQLITE_OMIT_AUTOMATIC_INDEX 1

我有一个带有一堆插件的 Mac 应用程序(每个插件都在自己的进程中)随机访问数据库并进行修改。所有进程都链接到使用自定义 SQLite 代码构建的同一个共享库。文档说多个进程可以随时读取,但实际上只有一个进程可以进行修改。这是否意味着我需要以某种方式编排和协调进程之间的写入?

我问是因为自从我采用 WAL 以来,我经常看到有关格式错误的数据库的报告。这似乎主要发生在一个进程在打开一个连接后崩溃(不管它是否用SQLITE_OPEN_READONLY标志打开)并且另一个进程已经打开了一个连接或稍后打开了一个连接。我不能总是可靠地重现这一点,但它似乎与一个进程创建的 -shm 和 -wal 索引文件有关,而另一个进程要么在内存中有自己的副本,要么产生了一些不匹配不知何故。不应该是这种情况,但可能是新进程使用的 -shm 文件以某种方式修改它(或 .db 文件)而没有第一个进程发现,从而导致数据库损坏(如前所述在如何损坏 SQLite 的 2.4 下)?

我唯一的猜测是让两个进程写入同一个数据库是这些损坏实例的根本原因。如果这是真的,我们如何在没有复杂的进程间通信的情况下在两个独立的进程之间进行协调?有任何想法吗?我不想诉诸使用,journal_mode=DELETE因为我有一个高度多线程的应用程序,否则它会从并发读取器和单个写入器中受益。

顺便说一句,这就是我打开阅读器的方式(多个阅读器同时由多个线程打开):

NSString *path = ...

sqlite3 *readOnlyDB = NULL;

BOOL dbOpened = (sqlite3_open_v2(path.UTF8String, &readOnlyDB, SQLITE_OPEN_READONLY | SQLITE_OPEN_WAL, NULL) == SQLITE_OK);

sqlite3_exec(readOnlyDB, "PRAGMA read_uncommitted=1; PRAGMA query_only=1; PRAGMA synchronous=normal;", NULL, NULL, NULL);
sqlite3_unicode_init(readOnlyDB);
sqlite3_busy_timeout(readOnlyDB, 2000)

// I register custom functions here for the connection

这就是我打开作家的方式(单个进程存在一个作家):

BOOL dbOpened = (sqlite3_open_v2(path.UTF8String, &dbConnection, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) == SQLITE_OK);

sqlite3_exec(dbConnection, "PRAGMA main.journal_mode=WAL; PRAGMA synchronous=normal;", NULL, NULL, NULL);
sqlite3_unicode_init(dbConnection);
sqlite3_busy_timeout(dbConnection, 2000);

// I register custom functions here for the connection

在关闭作家之前,我总是运行以下检查点:

  ....
  sqlite3_exec(dbConnection, "PRAGMA wal_checkpoint(PASSIVE)", NULL, NULL, NULL);

编辑:我发现了另一种奇怪的行为,不确定这是否相关。SQLITE_OPEN_READWRITE如果我用而不是打开我的阅读器,则在调用连接后会正确删除SQLITE_OPEN_READONLY-shm 和 -wal 文件。如果我切换回,我会看到 -shm 和 -wal 文件永远不会被删除,即使进程完全关闭也是如此。我在我的一个插件中使用只读模式(这似乎主要导致损坏,特别是在它退出或使用插件的主机应用程序崩溃等情况下),我看到了这种行为变化。我想知道这是否表明 SQLite 中存在错误,或者只是我不知道的一些行为。我很乐意切换到读写模式并使用sqlite3_close_v2(...)SQLITE_OPEN_READONLYPRAGMA query_only如果这不会在锁定方面破坏 SQLite 中的任何其他内容,那么实际上我所有的读者实际上都是作家,但从不进行任何修改。

4

1 回答 1

1

我在 Linux 上使用 Python 客户端的 SQLite3 遇到了类似的问题:当客户端在打开的事务中崩溃时,DB 文件格式错误,而另一个并发进程执行读/写查询。

在我添加异常处理程序以确保事务在崩溃进程终止之前关闭后,该问题得到解决。

于 2018-03-30T18:23:04.453 回答