我们有一个应用程序,它以只读模式通过硬链接连接到网络文件系统中的小型SQLite数据库,并执行一些非常简单的SELECT查询。
我们最近将Mac OS升级到10.12,并且该应用程序开始偶尔失败,并显示常规(无用)错误代码SQLITE_IOERR。我们设法获得了扩展的错误代码SQLITE_IOERR_VNODE(6922),但是找不到SQLite_IOERR_VNODE的任何文档,也找不到在SQLite的源代码中使用过的错误代码,只是找到了定义位置。堆栈跟踪中与SQLite相关的唯一有趣的信息是“ /usr/lib/libsqlite3.dylib+00738138 darwinFileTrackEvent + 00000058”。
Google对此错误一无所知,可能是因为它是全新的。有人可以照亮吗?
最佳答案
SQLite的作者说here:
SQLITE_IOERR_VNODE是专有修改使用的错误代码
由Apple实现的SQLite,可在MacOS和iOS上使用。有人告诉我
“代码表明与通话相关的文件已失效
通过调度vnode源事件”,但我不知道那是什么
手段。
并且该线程包含有关可能导致该错误的更多信息和推测。
Apple WWDC在2016年的会议242“核心数据的新变化”幻灯片184(pdf here)中说:
SQLite的新功能
SQLite现在使用调度源来跟踪非法文件操作。非法操作后的API调用将返回SQLITE_IOERR_VNODE
并引用SQLite页面howtocorrupt.html和设置SQLITE_ENABLE_FILE_ASSERTIONS=1
。幻灯片的transcript of the talk表示:
如果直接使用SQLite,则要确保只有一个代码拥有该数据库,并且该代码需要进入独占文件访问权限,以便在打开文件时无法对其进行更改。
我对这个错误的经验
在iOS 13 / Xcode 11之前,这种情况很少发生,因此我忽略了它。
现在,使用Xcode 11.2和iOS 13,我通常会在485 XCTest
UI测试中看到5个失败。测试在SQLite中崩溃,扩展错误代码为6922(在模拟器中运行应用程序时)。没有崩溃的模式。每次都是不同的测试。我还通过几天的自动测试在我的设备上看到了它。以前,这些自动化测试(在Xcode Server上运行)非常稳定。
在此之前,当我使用Apple提供的SQLite库libsqlite3.tbd
时,有时会在物理设备和模拟器中的iOS应用程序中看到此错误。在我的方案中,SQLite .db
文件包含在(只读).ipa
包中。它直接作为只读数据库在此处打开,并且很少使用。很难看到代码如何“更改文件”(如WWDC会话中所建议)。上面引用的第一个线程推测它可能与内存映射文件优化有关,因为vnode通常用于此目的。
我刚刚完成了从https://github.com/swiftlyfalling/SQLiteLib添加方便的Xcode打包的SQLiteLib的操作。这些测试现在正在坚如磐石。几周后,我将知道静态包含SQLite是否已经完全消除了,即使我以前曾遇到过罕见的故障。
TL; DR
苹果不主张直接在iOS中使用操作系统提供的SQLite。即使您的代码是正确的,此错误也可能是随机发生的,并且在iOS 13中更严重。静态链接sqlite
(使用https://github.com/swiftlyfalling/SQLiteLib)似乎可以解决此问题。