我们有一个应用程序通过只读模式的硬链接连接到网络文件系统中的小型SQLite数据库,并执行一些非常简单的SELECT查询。
我们最近将Mac OS升级到10.12,并且应用程序开始偶尔失败,并出现一般(无用)错误代码SQLITE_IOERR。我们设法得到扩展错误代码SQLITE_IOERR_VNODE(6922),但找不到任何关于它的文档或找到它在SQLite源代码中的使用位置,除了我们找到它的定义位置。堆栈跟踪中与SQLite相关的唯一有趣信息是“/usr/lib/libsqlite3.dylib+00738138 darwinFileTrackEvent + 00000058”。
谷歌对此错误一无所知,可能是因为它是全新的。有人可以解释一下吗?
答案 0 :(得分:2)
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是否已完全消除,即使我以前曾遇到过的罕见故障也是如此。
Apple不主张直接在iOS中使用操作系统提供的SQLite。即使您的代码是正确的,此错误也可能是随机发生的,并且在iOS 13中更严重。静态链接sqlite
(使用https://github.com/swiftlyfalling/SQLiteLib)似乎可以解决此问题。
答案 1 :(得分:0)
答案 2 :(得分:0)
错误是操作系统检测到有人直接从 SQLite API 下方对您打开的数据库文件执行了非法文件操作,SQLite 不支持该 API,并且是破坏数据库的好方法{{3} }.这些错误并非特定于 Core Data。无论你在做什么,OSS SQLite 库都不支持。
恢复机制与所有 SQLite I/O 错误一样,您需要关闭 sqlite3* 并打开一个新的。您应该正确响应从 sqlite API 返回的所有错误。
静态链接不同的 SQLite 库以抑制错误报告并不会神奇地使 SQLite 支持从其底层进行的裸文件操作。它只是忽略了一个错误,该错误试图告诉您文件损坏的严重风险。
检测到许多可能的操作,包括从您的下方删除文件、从您下方截断文件或从您下方卸载文件系统。如果要安全地进行这些操作,需要先关闭sqlite数据库。