Files
zvfs/plan.md
2026-03-02 08:31:01 +00:00

233 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ZVFS LD_PRELOAD -> RocksDB 加速实施计划(给 Codex 执行)
> 目标:基于当前 `zvfs/zvfs.c` + `zvfs/zvfs_hook.c`,从“单线程 + 接口不全”演进到“可支撑 RocksDB 多线程并有性能收益”。
>
> 约束:**分阶段、可中断、可重入**;每阶段都必须有独立可验证的正确性门槛。
---
## 0. 执行规则(必须遵守)
1. 一次只做一个阶段;阶段内通过验收前不得进入下一阶段。
2. 每阶段结束后必须更新本文“阶段状态”。
3. 每阶段保留一个“恢复锚点”:
- 可编译的代码状态;
- 一组固定验证命令;
- 一条阶段 commit建议
4. 出现阻塞时只回滚当前阶段改动,不回滚已完成阶段。
5.`/zvfs` 路径行为必须始终透传到 libc不得回归。
---
## 1. 阶段状态(可重入入口)
- [ ] Phase 1: 建立基线与 syscall 覆盖清单RocksDB 实际需求)
- [ ] Phase 2: 修正现有 hook 语义缺口(不改线程模型)
- [ ] Phase 3: 补齐 RocksDB P0 接口集(单线程可跑通)
- [ ] Phase 4: 补齐 RocksDB P1 接口集(目录/锁/截断)
- [ ] Phase 5: 多线程执行模型改造Worker + 请求队列)
- [ ] Phase 6: 并发正确性与崩溃恢复强化
- [ ] Phase 7: 面向 RocksDB 的性能优化与验收
> 重入方式:中断后先看本区,继续第一个未完成阶段。
---
## 2. 当前代码关键问题(来自 `zvfs.c`/`zvfs_hook.c`
1. 单线程瓶颈:所有请求依赖 `global_thread + waiter` 同步轮询,调用线程直接 `spdk_thread_poll`,不适合并发。
2. hook 覆盖不足:当前仅 `open/read/write/close/unlink/lseek`RocksDB 常用接口大量缺失(如 `pread/pwrite/fstat/fsync/fdatasync/ftruncate/rename/openat/fcntl` 等)。
3. 语义缺口:`O_TRUNC/O_APPEND/errno` 等语义不完整;元数据保存与文件操作一致性较弱。
4. 线程安全缺口:`g_fs``fd_table``dirent``open_count` 等无锁并发访问。
---
## 3. 分阶段计划
## Phase 1: 建立基线与 syscall 覆盖清单RocksDB 实际需求)
### 目标
明确 RocksDB 在当前环境下真实调用了哪些文件接口,得到“必须实现”的优先级列表。
### 任务
1. 编译基线:`make``make -C test`
2. 跑现有回归:`make run-test`(普通路径和 `/zvfs` 路径各一轮)。
3.`strace -f``db_bench`(或最小 RocksDB workload导出 syscall 统计。
4. 产出 `docs/rocksdb-syscall-matrix.md`P0/P1/P2 分类 + 是否已支持)。
### 验收
- 能给出可复现命令与 syscall 清单。
- 明确哪些接口是“阻塞 RocksDB 跑通”的 P0。
### 中断/重入
- 产物文件存在:`docs/rocksdb-syscall-matrix.md`
- 下一次从该清单继续,不需要重跑全量分析。
---
## Phase 2: 修正现有 hook 语义缺口(不改线程模型)
### 目标
在保持单线程架构不变的前提下,先把已有接口的 POSIX 语义修正到可用状态。
### 任务
1. 修复 `open` 标志位语义:至少覆盖 `O_CREAT/O_EXCL/O_TRUNC/O_APPEND`
2. 统一返回值与 `errno``zvfs_*` 失败路径映射到标准 errno。
3. 修复元数据 I/O 基础问题(如加载/保存边界、错误传播、close 使用 real 函数)。
4. 增加小型语义回归测试(可放 `test/`)。
### 验收
- 现有 `test` 全通过。
- 新增语义测试通过。
-`/zvfs` 路径行为无回归。
### 中断/重入
- 保留旧逻辑兼容开关(如宏开关)直到本阶段稳定。
- 提交后可独立回退,不影响后续接口扩展。
---
## Phase 3: 补齐 RocksDB P0 接口集(单线程可跑通)
### 目标
先实现 RocksDB “必须有才能启动并跑基础 workload” 的接口集合。
### P0 接口(优先)
- 打开类:`open64/openat/openat64/__open_2/__open64_2`
- 偏移 I/O`pread/pread64/pwrite/pwrite64`
- 元数据:`stat/lstat/fstat/fstatat/access`
- 持久化:`fsync/fdatasync`
- 变更:`rename/renameat/unlinkat`
### 任务
1.`zvfs_hook.c` 增加 real 函数指针与统一初始化(建议 `pthread_once`)。
2. 所有新 hook 必须支持“路径过滤 + 非 `/zvfs` 透传”。
3. 对不支持的语义明确返回 `ENOTSUP/EOPNOTSUPP`,禁止静默成功。
4. 增加 `pread/pwrite` 偏移语义测试。
### 验收
- `db_bench` 单线程基础项可跑:`fillseq/fillrandom/readrandom`
- `strace` 显示 P0 接口已被正确接管或透传。
### 中断/重入
- 每新增一类 hook 单独 commitopen/io/meta/sync/rename
- 中断后按未完成类别继续,不影响已完成类别。
---
## Phase 4: 补齐 RocksDB P1 接口集(目录/锁/截断)
### 目标
支持 RocksDB 更完整运行路径,尤其是锁文件、目录操作、截断相关语义。
### P1 接口
- `ftruncate/truncate`
- `fcntl`(至少 `F_SETLK/F_SETLKW/F_GETLK/F_UNLCK`
- `mkdir/rmdir/opendir/readdir/closedir`
- `link/symlink/readlink`(按 strace 结果决定)
### 任务
1. 为目录与锁引入最小可用实现(先保证正确,再优化)。
2. 对暂不支持特性返回明确 errno不可假成功。
3. 补充目录/锁语义测试(多进程或多线程最小场景)。
### 验收
- `db_bench --threads=4` 可稳定执行基础 workload。
- 无明显语义错误锁冲突、目录丢失、truncate 异常)。
### 中断/重入
- `fcntl` 与目录接口分成两个子里程碑。
- 任一子里程碑完成即可落盘并停在该点。
---
## Phase 5: 多线程执行模型改造Worker + 请求队列)
### 目标
把当前“调用线程主动 poll”的模式改为“专用 worker poll + 线程安全请求提交”,解决单线程瓶颈。
### 任务
1. 新增 `zvfs_worker`专用线程、请求队列、完成通知cond/futex/eventfd 均可)。
2.`waiter` 路径替换为 `submit_and_wait` 路径;调用线程不再直接 `spdk_thread_poll`
3. 增加并发保护:
- 全局锁:`g_fs/mount/fd_table/dirent`
- 文件锁:`offset/blob 生命周期`
- 明确锁顺序避免死锁。
4. 保留回退开关(例如 `ZVFS_USE_LEGACY_WAITER`)直到压测稳定。
### 验收
- 线程数 4/8 下功能测试稳定,无死锁/崩溃。
- CPU 火焰图或日志能证明调用线程不再承担 SPDK poll。
### 中断/重入
- 先实现 worker 生命周期,再迁移 read/write再迁移 open/close。
- 每迁移一类操作即可独立验证与提交。
---
## Phase 6: 并发正确性与崩溃恢复强化
### 目标
在多线程基础上补齐一致性:元数据、删除/关闭竞态、异常退出后的可恢复性。
### 任务
1. 元数据持久化改为“原子写入流程”(临时文件 + fsync + rename
2. 修复 `unlink/close/open` 并发竞态(引用计数与删除时机)。
3. 建立故障注入测试:`kill -9`、中途断电模拟(最小可复现脚本)。
4. 明确恢复策略与错误可观测日志。
### 验收
- 故障注入后可重新挂载并读到一致元数据。
- 并发 `open/unlink/close` 压测无崩溃无悬挂。
### 中断/重入
- 先落地元数据原子写入,再处理并发删除,再做故障注入。
---
## Phase 7: 面向 RocksDB 的性能优化与验收
### 目标
在正确性稳定后进行性能优化,并给出“确实加速 RocksDB”的证据。
### 任务
1. 优化优先级:
- 对齐写 fast-path 与非对齐 RMW 优化;
- DMA buffer 复用/池化;
- 减少全局锁粒度;
- 批量/延迟元数据刷新策略。
2. 构建统一 benchmark 脚本:
- 对照组 A不使用 `LD_PRELOAD`
- 对照组 B`LD_PRELOAD=./libzvfs.so` + `/zvfs` 路径。
3. 指标吞吐ops/s、P99 延迟、CPU 使用率、失败率。
### 验收(最终目标)
- 在至少一个 RocksDB workload 上达到可重复的性能提升(建议目标 >= 1.3x,最终以实测为准)。
- 提供完整报告:命令、环境、结果表、结论与剩余瓶颈。
### 中断/重入
- 每个优化项必须可单独开关,可单独回滚。
---
## 4. 阶段验收矩阵(执行时打勾)
- [ ] P1 已产出 syscall matrix 且可复现。
- [ ] P2 已完成现有语义修复且回归通过。
- [ ] P3 已实现 P0 接口并单线程跑通 RocksDB。
- [ ] P4 已实现 P1 接口并多线程稳定运行。
- [ ] P5 已切换到 worker 并通过并发稳定性测试。
- [ ] P6 已通过崩溃恢复与并发竞态测试。
- [ ] P7 已完成性能对照并证明加速收益。
---
## 5. 每阶段固定输出模板(执行时复用)
1. 改动清单(文件 + 关键点)。
2. 验证命令与结果。
3. 风险/已知问题。
4. 阶段状态勾选更新。
5. 下一阶段入口条件是否满足。