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