Skip to content

🐯 [资源] 回收删除文件后 fdCache 句柄未清理 · fsm.go #299

Description

@github-actions

来自 #296 的架构级评审建议。不阻塞合入,仅供参考是否有更好的架构解法。

⚠️ [重要 · 资源] 回收删除文件后 fdCache 句柄未清理 service/fsm.go:200

问题根因:ReclaimUpTo 调用 m.sst.DeleteSSTable(meta) + m.sst.RemoveMeta(meta),但需要确认 DeleteSSTable 是否关闭了 fdCache 中对应 path 的常驻文件句柄。从 sstable.go 注释看,「句柄在 DeleteSSTable 中关闭并剔除,否则每轮 compaction 泄漏一个 fd」——即 DeleteSSTable 的确会清理 fdCache。然而 retention_test 的 TestReclaimUpTo_DropsOnlyFullyDeliveredFiles 里通过 os.Stat 确认文件被 delete,但未验证 fdCache 清理后的句柄状态。若 DeleteSSTable 在回收路径的调用语义与 compaction 路径一致(都负责关 fd),则本 finding 可降级为「需确认」;但从代码无法排除 DeleteSSTable 只处理 compaction 场景、未覆盖回收场景的可能。若未清理,每轮回收会永久泄漏一个常驻 fd 与块缓存条目,长跑后 fd 耗尽。

为什么低级解法不够:在回收路径补一句 DeleteSSTable 注释或手动 Close 只能堵当前场景,若 DeleteSSTable 的 fd 清理本身对回收语义覆盖不全(比如 compaction 场景靠 RemoveMeta 后自然淘汰,而回收后不再有别的引用),属于结构不清。

架构级方案:明确将『文件生命周期终结』的动作收敛到单一所有权点:DeleteSSTable 统一负责元数据移除 + fdCache 剔除 + 块缓存失效 + 磁盘 unlink + 日志,compaction 与回收两条路径都只调它、不做各自的清理。在 meta.go 里用一条不变式约束:任何 RemoveMeta 的调用方都必须已经(或正在)通过 DeleteSSTable 完成磁盘与句柄清理。可加一个单测:回收后再次 ScanRange 该路径不产生新 fd 泄漏(对比回收前后 /proc/self/fd 计数)。

代价/收益:收益:fd/块缓存生命周期有单一事实来源,杜绝半清理。代价:需审一遍 DeleteSSTable 当前实现是否已满足该契约;若缺失需补齐,属低风险补强。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions