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 当前实现是否已满足该契约;若缺失需补齐,属低风险补强。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions