# 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 单独 commit(open/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. 下一阶段入口条件是否满足。