当我在 Cygwin 中使用 Subversion 更新一些存储库时,一些目录更新成功,而另一些则失败并显示错误消息:
svn: E200030: sqlite: 磁盘 I/O 错误
对同一个存储库再次执行svn update
时,不同的目录可能会出现相同的错误。有时,在上述错误信息之后会有一条 SVN 指令。
这是因为有人想要在 Cygwin 的SQLite包中进行更改。当被问到这个问题时,我是那个包的维护者,我做了导致这个症状的改变。
该更改作为 Cygwin SQLite 版本发布3.7.12.1-1
,它解决了一个人的问题,但它具有阻止 Cygwin 的 Subversion 包与本机 Windows Subversion 实现合作的不良副作用。
这里的核心问题是Subversion 1.7 改变了工作副本的磁盘格式。该更改的一部分涉及一个新的 SQLite 数据库文件,.svn/wc.db
. 现在,为了实现SQLite 的并发保证,SQLite 在访问数据库文件时会对其进行锁定。
这一切都很好,也很明智,但是当您尝试混合使用 Windows 本机和 POSIX文件锁定语义时会遇到问题。在 Windows 上,文件锁定几乎总是意味着强制锁定,但在 Linux 系统上——Cygwin 试图模仿——锁定通常意味着建议锁定。
这有助于了解“磁盘 I/O 错误”的来源。
Cygwin SQLite 的3.7.12.1-1
变化是以“Unix 模式”而不是“Cygwin 模式”构建库。在 Cygwin 模式下,该库使用 Windows 本机文件锁定,这与 Cygwin 的理念背道而驰:在可能的情况下,Cygwin 包调用 POSIX 函数而不是直接调用 Windows API,这样cygwin1.dll
可以提供正确的 POSIX 语义。
当所有访问相关 SQLite DB 的程序都使用 Cygwin 构建时,POSIX 咨询文件锁定正是您想要的 SQLite,这是 Cygwin 中的默认假设。但是,当您在运行纯 POSIX Cygwin 的同时运行 Windows 原生 Subversion 程序(如 TortoiseSVN svn
)时,就会发生冲突。当 TortoiseSVN Windows Explorer shell 扩展.svn/wc.db
使用强制锁锁定文件并且 Cygwinsvn
出现并尝试对其进行建议锁定时,它会立即失败。Cygwinsvn
假定锁定尝试将立即成功或阻塞直到成功,因此它错误地将锁定失败解释为磁盘 I/O 错误。
在 Cygwin 中,我们总是尽量与 Windows 本地程序配合使用。诀窍是找到一种方法来做到这一点,同时还能很好地使用 Cygwin 程序。
不是每个人都同意我们应该尝试这个。“Cygwin SQLite 是 Cygwin 的一部分,所以它只需要与其他 Cygwin 程序一起工作,”一个小组会说。对方会回答:“Cygwin 在 Windows 上运行,因此它必须与其他 Windows 程序一起运行良好。”
幸运的是,我们想出了一个让两组都开心的方法。
作为 Cygwin SQLite3.7.17-x
打包工作的一部分,我测试了Corinna Vinschen添加到版本 1.7.19的新功能。它允许程序通过 BSD 文件锁定 API 请求强制文件锁定。我的部分更改是让 Cygwin SQLite 在用户的指导下打开和关闭此功能,允许相同的包同时满足以 Cygwin 为中心和 Windows 原生阵营的需求。cygwin1.dll
这个 Cygwin DLL 特性在 1.7.20 中得到了进一步改进,我3.7.13-3
使用最终锁定语义发布了 Cygwin SQLite。此版本允许选择三种锁定策略:POSIX 咨询锁定、BSD 咨询锁定和 BSD/Cygwin 强制锁定。到目前为止,后一种策略已被证明与原生 Windows 锁定完全兼容。
后来,当 Jan Nijtmans 接手 Cygwin SQLite 的维护工作时,他通过将其与SQLite VFS 层完全集成,进一步增强了这一机制。这允许第四个选项:Cygwin SQLite 在我们开始此旅程之前使用的本机 Windows 锁定。这主要是为了避免 BSD/Windows 锁定策略无法与原生 Windows SQLite 程序完美协作的可能性。据我所知,没有人需要使用此选项,但很高兴知道它的存在。
如果您遇到的冲突是 Cygwin 的命令行svn
和 TortoiseSVN Windows Explorer shell 扩展之间的冲突,还有另一个选项可以修复它。TortoiseSVN 也附带原生的 Windows Subversion 命令行程序。如果你把这些放在PATH
Cygwin 的bin
目录之前,你根本不应该遇到这个问题。
遇到同样的问题,它似乎(至少在我的情况下)是与 TortoiseSVN 的交互。禁用 TortoiseSVN 的状态图标缓存(设置>图标覆盖>状态缓存“无”>应用)对我来说一切正常。
(这显然不能解决根本问题,这似乎是由于 Cygwin 的 Subversion 包依赖于更改其访问模式的 SQL 包。在我写的时候,Cygwin 邮件列表上有关于如何来解决这个问题。)
ldd /usr/bin/svn
表明 SVN 依赖于 /usr/bin/cygsqlite3-0.dll。
在我将 libsqlite3 从 3.7.12 更改回 3.7.3 后,问题似乎消失了。所以这可能是一个SQLite库问题。
使用 TortoiseSVN,勾选解决了我的问题Refresh shell overlays
。clean up
供其他人参考,我刚刚遇到同样的错误 ( svn: E200030: sqlite: disk I/O error
),发现我的一个日志文件占用了我的所有空间(并且由于没有可用空间而无法写入 HDD)。
运行(以确保您有足够的磁盘空间)
df -h
(如果你不删除一些大文件(我只是删除了一些备份和日志文件)
然后我只需要运行:
svn cleanup
这为我解决了错误。