我使用 SQLite 已经有一段时间了,并且有幸处理了一些锁定问题。我很确定 SQLite 默认在 Unix 文件系统上使用字节范围锁。
更准确地说,它包含一些替代锁定方法的代码(例如使用flock()
和点锁样式的全文件锁)。SQLITE_ENABLE_LOCKING_STYLE
当使用该选项编译时,它会尝试自动检测底层文件系统的正确锁定方法。
自动检测代码包含一些硬编码的情况(例如“ufs”、“nfs”和“smbfs”),它们都不是AFS。如果没有硬编码的大小写匹配,SQLite 会尝试使用fcntl()
. 然后假设如果fcntl()
调用成功,那么字节范围锁是可用的。
这就是 OpenAFS 让事情变得有趣的地方。显然 ( [1] , [2] , [3] ) OpenAFS 在字节范围锁定问题上向用户空间应用程序撒谎的历史由来已久。从openafs-1.4.14
源代码:
/* next line makes byte range locks always succeed,
* even when they should block */
if (af->l_whence != 0 || af->l_start != 0 || af->l_len != 0) {
DoLockWarning();
afs_PutFakeStat(&fakestate);
return 0;
}
一句话:哎哟!
无论如何,它都允许字节范围锁成功。在 Linux 上,可能会更糟:它使用内核基础设施在同一系统的进程之间提供字节范围锁。这意味着应用程序不能仅仅派生一个新进程并测试锁定机制 - 字节范围锁定似乎工作正常,但在保护文件免受远程进程影响方面却非常失败。
简而言之:你不能在 OpenAFS 中可靠地使用未经修改的 SQLite。大多数其他网络文件系统也存在问题,因此建议完全避免使用网络文件系统。
一些可能的解决方法,没有特定的顺序:
使用适当的 DBMS,例如PostgreSQL。如果可以做到这一点,从长远来看,你会过得更好。
如果一个成熟的 DBMS 太过分的话,请为您的应用程序实现您自己的服务器。
将 SQLite 源代码修改为默认flock()
在 OpenAFS 上。我不确定这是否能正常工作,因为 OpenAFS 有很长的锁定问题历史([1],[2]),即使是 plain-old 也是如此flock()
,但在你测试之前你不会知道。
使用 OpenAFS 用户空间为 SQLite 实现您自己的 OpenAFS VFS,而不是通过内核。
用另一个网络文件系统试试你的运气。
无论您做什么,如果以任何方式涉及 SQLite3 和共享数据库文件,您都必须执行广泛的测试。
编辑:
一位评论者建议使用点锁文件机制。我没有过多地研究 OpenAFS 源代码,但乍一看它似乎支持open(O_CREAT|O_EXCL)
SQLite 使用的创建点锁文件的方法。如果它按预期工作,那么如果你强制 SQLite 使用 dotlock 方法,它可能确实可以与 OpenAFS 一起使用。
也就是说,点锁在常规本地文件系统上就足够了,而不会将网络文件系统的复杂性引入其中——这就是我一开始没有建议它的原因。