网易首页 > 网易号 > 正文 申请入驻

从忽视再到复现,我是如何一步步发现SQLite Bug

0
分享至

【CSDN 编者按】程序出现错误,你的第一反应是什么呢?“奇怪,明明代码没问题啊?”、“怎么会返回一个硬件错误呢?”本文作者跟大家的反应或许类似,但当从迷雾中拨清头绪,再到复现、解决,你或许会有不一样的收获与感悟。

作者 | Philip O'Toole 翻译 | 王雪迎

出品 | CSDN(ID:CSDNnews)

rqlite 是一款用 Go 语言编写的轻量级、开源、分布式关系数据库,它使用 SQLite 作为存储引擎。最近我向 rqlite 中引入了一个高性能写入方法,大吃一惊的是,我还发现了 SQLite 中的一 个bug。

SQLite 团队很快解决了这个问题,但在此也记录一下发现过程与复现经历。

问题总是始于新特性

rqlite 7.5.0 引入了排队写入功能,它让用户能以高性能方式将大量数据写入 rqlite。当然,这意味着 SQLite INSERT 的执行频率也会增加,这才是重点。

在对排队写入进行压力测试期间,我有时会运行 rqlite 命令行,并通过定期发出以下命令来查看测试进度:


127.0.0.1:4001> SELECT COUNT(*) FROM logs

想象一下当我偶尔收到以下返回结果时的“惊喜”:

ERR! database disk image is malformed

这确实很奇怪。rqlite 默认运行内存数据库,那么磁盘映像怎么会损坏?我把它归因于 SQLite 中的错误代码重用,这是编程中的一种常见做法。但后来才意识到自己犯了真正的错误,我没有认真对待该问题,并认为它可能是暂时的,永远不会再现。

真实情况

11 月 1 日,rqlite 用户 João Arruda 在 GitHub 上提出了以下问题:

现在不可否认,这是一个真正的问题,而且可能是一个严重的问题。谁想在使用数据库时看到“磁盘映像格式错误”?

首先要做的是考虑能否重现 João 所遇到的情况,看看到底发生了什么。我再次启动了压力测试,提高了 INSERT 速率,直到磁盘 IO 达到最大值,然后开始通过 CLI 查询数据库——问题再次出现了。

ERR! database disk image is malformed

经测试表明,这只是一个查询时间问题。一旦 INSERT 流量停止,数据库中总是有正确数量的记录,而且这些记录看起来总是很正常。所以这是个好消息——发生的一切实际上并没有破坏数据库。

我是否可以写一个单元测试来复现此问题?想想发生的情况,我认为写这个测试并不比在一个数据库连接上执行查询,同时在另一个连接上插入行复杂多少。复现应该不会太难。

但事实并非如此。我用 Go 语言编写了一个简单的单元测试,其中不涉及任何 rqlite 代码,并运行了它。


$ go test -run Test_TableCreationInMemoryLoadRaw--- FAIL: Test_TableCreationInMemoryLoadRaw (2.30s)malformed_test.go:59: rows had error after Next() (1203 loops): database disk image is malformedFAILexit status 1FAIL github.com/mattn/go-sqlite3 2.303s

下一步是与 rqlite 使用的 Go-SQLite 驱动程序的维护者进行核实。他们确认 Go 代码没有问题, 而是在 SQLite 内部存在一些问题。

如果不用 C 语言编写代码,就不会出问题

现在该在 SQLite 论坛上发帖了。在 11 月初我第一次发帖寻求帮助,询问为什么在一个内存数据库中,我的查询会返回一个磁盘映像损坏错误。虽然问题得到了一些回应,但没有真正的进展。我认识到仅用 Go 的示例对 SQLite 社区来说不太有说服力。我的代码和 SQLite 实现之间的层次太多,有太多对 SQLite 的使用原因造成该问题,而不是 SQLite 本身。

所以是时候编写一个简单的 C 程序了。问题能重现吗?还是会消失?不管哪种情况,我都希望学到一些东西。

我很容易地拼凑了一个 C 程序——SQLite C AP 非常容易编写代码。然后我编译并执行了它:


$ gcc in-memory.c -pthread -l sqlite3$ ./a.outRunning SQLite version 3.39.4THREADSAFE=1Failed to step data: database disk image is malformed

就是这样,对 SQLite 的简单使用和我完美的查询遇到了数据库损坏的错误。是再次在 SQLite 论坛上发帖的时候了。很快,SQLite 团队确认这是 SQLite 中的一个 bug,并修补了他们的源代码。

从补丁中可以看到,我的查询连接似乎是在不应该访问数据库的时候访问了数据库,然后看到一个正在更改中的数据库。查询代码将此解释为损坏的数据库,并向我的代码返回了一个错误。

这一切都非常令人满意。我意识到发现这个 bug 可能是我整个软件职业生涯中做的最重要的事情。没等新的 SQLite 发布,我就马上给自己的 SQLite 打了补丁。 重构 rqlite 后没有再出现这个问题。在发布的 rqlite 7.12.1 中包括对该问题的修复。

最后 João 确认,在他的生产设置中也不再出现该问题。

经验总结

这里汲取到的经验和往常一样。计算机会严格按照你的指示去做。它们不会在系统中随机插入错误,也不会在运行过程中自己编造错误。当我第一次看到这个问题时,忽视它是一个很大的错误,而且在理智上不够诚实。

非常感谢 João 在 GitHub 上提交了这个问题,rittneje@rqlite 中心维护 GoSQLite 驱动程序的工作人员,并帮助证明这是一个 SQLite 问题,以及 SQLite 团队如此迅速地修复了这个 bug。

网友:我发现过同样的 Bug,但被解雇了!

Euphorbium:

我在 django 中遇到了同样的bug,他们花了 5 年时间才修复。Django 的标语是“有期限的完美主义者的网络框架”。因为这个 bug,我被解雇了。

Hans:

修复方法适用于 memdb。我怀疑你在django上使用了内存数据库…

HacKan:

作为一名维护人员和软件开发者,我可以 100% 理解你一开始“忽略它”的决定,就像“也许这是我的环境或什么”。 作为从中吸取的教训,下次你遇到类似的事情时,面对现实可能是一种有趣的方法:对你所看到的情况添加一个“已知问题”免责声明,说明它很可能发生。如果其他人也设法重现了问题,那就专注解决它,而不是忽略它然后提交问题。 总之干得不错,多棒的成就

dkf:

计算机真的可能在代码中插入随机错误!它们发生在辐射或宇宙射线导致随机位翻转的时候……是的,这确实发生过。但只有在大规模情况下出现,我们在硬件(内存和磁盘)中进行了纠错,以将这些(未纠正的)随机位翻转的比例降至你在整个职业生涯中都看不到的水平之下。

deets:

我曾经编译过一个大型C++代码库,在编译“klass Something”或类似的东西时出错了。源代码中不会包含如此严重的错误。更深研究发现在class关键字中出现了位翻转。重新编译显然解决了这个问题,但还是有点吓人。

Mikko Rantalainen:

我想说,任何软件问题都可能存在正在随机性,直到你可以在另一个不共享任何硬件的系统上复现该问题为止。 这是确保你当下系统不被简单破坏的唯一真正方法。崩溃可能以各种方式发生:存储、电源、内存控制器损坏、L1/L2/L3 缓存损坏、CPU 内核损坏、 CPU 核心中的微操作执行单元损坏等。 只有当你可以用两个完全独立的系统来重现问题时(最好情况下,所有的东西都是不同的,如英特尔 vs AMD CPU,三星 vs ADATA 存储等等)才可能确认。这将需要排除给定硬件组件中的设计问题。 如果你确定问题是由软件引起的,那么是时候投入资源找出确切原因了。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
笑死!周扬青内涵庆奶整容,被回怼到哑口无言,网友:自取其辱

笑死!周扬青内涵庆奶整容,被回怼到哑口无言,网友:自取其辱

丹妮观
2026-02-02 17:49:06
精神病不够,正常人来凑!襄阳精神病院成国内园区,产业链被曝光

精神病不够,正常人来凑!襄阳精神病院成国内园区,产业链被曝光

垛垛糖
2026-02-04 10:52:50
地主王学文救起晕倒的女红军,她拉开衣襟的那刻,王学文吓一跳

地主王学文救起晕倒的女红军,她拉开衣襟的那刻,王学文吓一跳

磊子讲史
2026-01-06 10:38:15
马斯克彻底搞定大圆柱电池!发布五年终落地,独家专利破解量产难题

马斯克彻底搞定大圆柱电池!发布五年终落地,独家专利破解量产难题

车东西
2026-02-02 18:52:55
中国发出禁令,委内瑞拉石油不能靠岸,美方派人打听,遭已读不回

中国发出禁令,委内瑞拉石油不能靠岸,美方派人打听,遭已读不回

长星寄明月
2026-02-04 12:08:00
侍卫救了乾隆的命,乾隆问他要何赏赐?侍卫:就赏我一个宫女吧

侍卫救了乾隆的命,乾隆问他要何赏赐?侍卫:就赏我一个宫女吧

铭记历史呀
2026-01-26 19:47:25
全满贯后的沉默:阿尔卡拉斯与费雷罗之间发生了什么?

全满贯后的沉默:阿尔卡拉斯与费雷罗之间发生了什么?

网球之家
2026-02-04 23:09:31
未成年女性日记曝光:爱泼斯坦将她作为“孵化器”,其痴迷于“优越基因库”

未成年女性日记曝光:爱泼斯坦将她作为“孵化器”,其痴迷于“优越基因库”

红星新闻
2026-02-04 13:50:19
蔡英文可能回锅参选吗?蓝营议员:萧美琴接棒可能性极高

蔡英文可能回锅参选吗?蓝营议员:萧美琴接棒可能性极高

海峡导报社
2026-02-04 10:02:02
在内蒙古草原上,为啥当地人更喜欢煮羊肉,而不是更诱人的烤羊肉

在内蒙古草原上,为啥当地人更喜欢煮羊肉,而不是更诱人的烤羊肉

向航说
2026-01-31 00:55:03
法国猫徒步5个月从西班牙回家!只为再蹭蹭主人的手

法国猫徒步5个月从西班牙回家!只为再蹭蹭主人的手

新欧洲
2026-01-28 21:37:40
以色列首位女穆斯林阿拉伯语发言人上任

以色列首位女穆斯林阿拉伯语发言人上任

桂系007
2026-02-05 00:16:49
三国石油储量对比:俄800亿桶,美700亿,中国储量出人意料

三国石油储量对比:俄800亿桶,美700亿,中国储量出人意料

完善法
2026-02-04 19:29:46
英媒透露安全保障具体措施,美军将在必要时参战:乌克兰不再天真

英媒透露安全保障具体措施,美军将在必要时参战:乌克兰不再天真

鹰眼Defence
2026-02-04 18:17:12
5个首轮签白瞎了!坐拥一群顶级天赋,结果却让伪球星老大耽误了

5个首轮签白瞎了!坐拥一群顶级天赋,结果却让伪球星老大耽误了

你的篮球频道
2026-02-04 14:09:53
明朝锦衣卫的灭亡:大小头目全部遇难,一天之内便被消灭殆尽!

明朝锦衣卫的灭亡:大小头目全部遇难,一天之内便被消灭殆尽!

铭记历史呀
2026-01-31 23:08:25
老板都是怎么把自己生意干黄的?网友:29.7收30,三个月不到就黄了

老板都是怎么把自己生意干黄的?网友:29.7收30,三个月不到就黄了

另子维爱读史
2026-02-02 21:22:54
贝克汉姆再遭打击,大布除掉了“爸爸”刺青,球星对长子的爱仍在

贝克汉姆再遭打击,大布除掉了“爸爸”刺青,球星对长子的爱仍在

译言
2026-02-05 11:01:14
红装登场判若两人!锤娜丽莎逆袭全网直呼不敢认

红装登场判若两人!锤娜丽莎逆袭全网直呼不敢认

淡淡稻花香s
2026-02-05 02:49:17
后怕!如果当初决策层相信了许小年,中国可能会比现在落后二十年

后怕!如果当初决策层相信了许小年,中国可能会比现在落后二十年

蓝色海边
2026-02-05 07:55:38
2026-02-05 12:24:49
CSDN incentive-icons
CSDN
成就一亿技术人
26301文章数 242229关注度
往期回顾 全部

科技要闻

微信给马化腾浇了“一盆冷水”

头条要闻

牛弹琴:中国元首和特朗普通话 特朗普就台湾问题表态

头条要闻

牛弹琴:中国元首和特朗普通话 特朗普就台湾问题表态

体育要闻

奇才:我学生……独行侠:成交!

娱乐要闻

谢娜明年开演唱会:带老歌出来见见人

财经要闻

黄金,出现拐点

汽车要闻

一切交给XWD 捷途旅行者C-DM也能轻松刷冰锅

态度原创

亲子
教育
数码
公开课
军事航空

亲子要闻

孩子的脸,是家庭最诚实的计分器

教育要闻

3分钟看懂浙江首考诊断报告!精准定位提分点

数码要闻

AMD确认:Steam Machine今年开始发货!

公开课

李玫瑾:为什么性格比能力更重要?

军事要闻

卡扎菲儿子被暗杀:4名蒙面人员闯入住所

无障碍浏览 进入关怀版