fix(sstable): 重载时从块索引取 MaxKey,修复重启后已刷盘数据全丢#153
Conversation
LoadSSTableMetaList 此前只读首键作 MinKey,MaxKey 留待 EnsureMeta 懒加载。 但 EnsureMeta 按 [klen][key][vlen][val] 顺序扫描到文件尾,而 SSTable 数据段之后 还接了块索引/布隆/footer——扫过边界后错位解析,MaxKey 实测退化成空串。 于是 getFromSSTables 的 [MinKey,MaxKey] 范围过滤对任意真实 key 都判 key>MaxKey 而整段跳过该文件,导致 standalone 重启后所有已刷盘 key 全部读不到(实测 45/50 丢失, 仅剩还在 memtable/WAL 的尾部数据)。 修复:LoadSSTableMetaList 直接用块索引末项的 LastKey 作 MaxKey 并置 MaxKeyLoaded=true, 绕开会越界的 EnsureMeta 扫描。老格式无 footer(loadBlockIndexFromFile 返回 nil)时 保留原懒加载兜底——纯数据文件的顺序扫描本就正确。 新增 TestReloadRecoversFlushedKeys:小阈值逼多轮刷盘,停机后同目录重载,断言 50/50 恢复。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 33 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🐯 BanGD 数据库内核评审整体风险:🔴 高 变更总结:该 PR 修复了一个致命的 SSTable 加载 bug:重启后已刷盘数据全部丢失。根因是
架构问题(共 3 项)
普通问题(共 2 项)
if idx := ss.loadBlockIndexFromFile(fullPath); len(idx) > 0 {
meta.MaxKey = idx[len(idx)-1].LastKey
meta.MaxKeyLoaded = true
ss.idxMu.Lock()
ss.indexCache[fullPath] = idx
ss.idxMu.Unlock()
}然后第 149 行的 💡 [建议 · 错误处理]
本次评审消耗 token:共 62015 tokens(输入 57113,输出 4902,缓存命中 0,缓存写入 0)|维度 [concurrency, memory, lock, storage, performance]|对抗式复核 3 票/条,过滤疑似误报 0 条 |
致命 bug:standalone 重启后已刷盘数据全部丢失
现象
小 memtable 阈值下写入 50 个 key(多数刷到 SSTable),停机重启后 45/50 读不到,只剩还在 memtable/WAL 的尾部数据。运行时(未重启)读取一切正常。
根因
LoadSSTableMetaList只读首键作 MinKey,MaxKey 交给EnsureMeta懒加载。但EnsureMeta按[klen][key][vlen][val]顺序扫到文件尾,而 SSTable 数据段之后还接了块索引/布隆/footer——越过数据段边界后错位解析,实测 MaxKey 退化成空串。于是getFromSSTables的[MinKey,MaxKey]范围过滤对任意真实 key 都判key > MaxKey而整段跳过该文件。修复
LoadSSTableMetaList直接用块索引末项的LastKey作 MaxKey 并置MaxKeyLoaded=true,绕开会越界的EnsureMeta扫描。老格式无 footer 时保留懒加载兜底(纯数据文件顺序扫描本就正确)。验证
新增
TestReloadRecoversFlushedKeys:小阈值逼多轮刷盘 → 停机 → 同目录重载 → 断言 50/50 恢复。全量 storage/service 测试通过。🤖 Generated with Claude Code