首页 文章

SQLite 3 WAL模式多个进程经常破坏数据库

提问于
浏览
1

我在使用这些标志编译的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代码构建的同一共享库 . 文档说多个进程可能随时读取,但只有一个进程可能实际进行修改 . 这是否意味着我需要以某种方式编排和协调进程之间的写入?

我问,因为自从've adopted WAL, I frequently am seeing reports of malformed databases. This seems to mostly occur if a process crashed after having opened a connection (doesn'无论是否用 SQLITE_OPEN_READONLY 标志打开,并且另一个进程已经打开了一个连接或稍后打开了一个连接 . 我不能总是可靠地重现这一点,但它似乎与一个进程创建的-shm和-wal索引文件有关,另一个进程要么在内存中有自己的副本,要么产生了一些不匹配不知何故 . 不应该是这种情况,但可能是新进程使用的-shm文件以某种方式修改它(或.db文件)而没有第一个进程发现,从而导致数据库损坏(如前所述)在如何腐蚀SQLite的2.4下?

我唯一的猜测是,有两个进程写入同一个db是这些损坏实例的根本原因 . 如果这是真的,我们如何在没有复杂的进程间通信的情况下在两个独立的进程之间进行协调?有任何想法吗?我不想使用 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 打开我的阅读器,则在连接上调用 sqlite3_close_v2(...) 后会正确删除-shm和-wal文件 . 如果我切换回 SQLITE_OPEN_READONLY ,我发现即使进程干净地关闭,-shm和-wal文件也永远不会被删除 . 我在我的一个插件中使用只读模式(这似乎主要是导致损坏,特别是在它退出或使用插件崩溃的主机应用程序等),我'm seeing this change in behaviour. I wonder if this is an indication of a bug in SQLite or just some behaviour I wasn't知道 . 我很乐意切换到readwrite模式并使用 PRAGMA query_only 如果在锁定方面不会破坏SQLite中的任何其他内容,实际上我所有的读者实际上都是编写者,但从不执行任何修改 .

1 回答

  • 0

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

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

相关问题