Skip to content

🐯 BanGD [资源] storage/zstorage/memtable.go #113

@github-actions

Description

@github-actions

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

⚠️ [重要 · 资源] storage/zstorage/memtable.go:267

问题根因Close() 现在仅执行 close(m.stopCh) 并返回 nil,不再负责关闭任何资源(原 WAL 的 Close 已删除)。但 MemTable 持有 sst *SSTable(SSTable 内部有文件/元数据),以及 goroutine FlushWorkerListenCompactCh 通过 stopCh 退出——这些 goroutine 的退出由 Close() 触发,但 Close() 不等待它们完成就返回了。若调用方在 Close 后立即退出进程或复用 MemTable 对象,可能存在 goroutine 仍在运行中而 SSTable 未释放的情况。

为什么低级解法不够:简单地补一个 m.sst.Close() 调用可以关闭 SSTable 文件句柄,但没有解决 goroutine 优雅退出的等待问题——FlushWorker 可能还在执行 Flush,此时关闭 SSTable 文件会导致 panic 或数据截断。

架构级方案:为 MemTable 定义清晰的生命周期状态机:Close() 应变为阻塞的 Shutdown()Close(ctx) 方法,依次执行:(1) close(stopCh) 通知所有 goroutine 退出;(2) 等待它们退出(通过 sync.WaitGroup 追踪已启动的 goroutine);(3) 关闭 SSTable。当前实现中 FlushWorker 收到 stopCh 信号后直接 return,但正在执行的 Flush 中 m.sst.WriteToSSTable 可能被中断,这本身也是问题(SSTable 写入中途中断可能留下半写文件)。更彻底的方案:Shutdown 先 Drain FlushChan,完成最后一次 Flush,再关 stopCh。

代价/收益:代价是实现 Shutdown 需要引入 WaitGroup 和 drain 逻辑,代码复杂度上升;收益是 MemTable 生命周期边界清晰,不会在关闭后出现 goroutine 竞态或文件截断。考虑到当前项目以测试和构建验证为主,此问题在实际运行中由 Raft 层管理生命周期,短期影响有限,但作为架构问题应被记录。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions