217 lines
7.7 KiB
Markdown
217 lines
7.7 KiB
Markdown
# ZVFS 分阶段改造计划(可重入,用户验收版)
|
||
|
||
> 目标:把当前实现改造成可并发扩展、高性能且语义完整的架构。
|
||
> 约束:我无法使用 root,所有阶段验收由你执行。
|
||
|
||
## 通用约定(所有阶段)
|
||
|
||
- 建议先记录基线:`git rev-parse --short HEAD`。
|
||
- 每阶段都保持“可编译 + 可回归”。
|
||
- 每阶段完成后打一个里程碑 tag(例如 `phase1-done`),中断后可从最近 tag 继续。
|
||
- 验收命令默认:
|
||
|
||
```bash
|
||
make -C zvfs -j4
|
||
make -C test -j4
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_phase2_posix /zvfs
|
||
```
|
||
|
||
## 已落地变更(2026-03-03)
|
||
|
||
1. **stale blob 自愈修复(已完成)**
|
||
- `open(O_CREAT)` 遇到元数据引用失效 blob 时自动重建并回写元数据。
|
||
- `unlink/close(rename 覆盖)` 删除失效 blob 时容忍 `ENOENT/EINVAL`,避免误报 `EIO`。
|
||
|
||
2. **小块写合并(已完成)**
|
||
- hook 层新增 per-fd writeback buffer(默认 128KB),连续小写先合并再 `pwrite`。
|
||
- 在 `read/pread/lseek/fsync/fdatasync/close/ftruncate/fallocate/unlink/rename/sync_file_range` 前补齐 flush,保证可见性。
|
||
|
||
3. **当前观察**
|
||
- 小块写已提升,但小块读仍偏低;读优化作为后续阶段重点。
|
||
|
||
---
|
||
|
||
## Phase 0:基线与护栏
|
||
|
||
### 要做的事情
|
||
1. 固化当前行为基线:功能、性能、CPU 占用。
|
||
2. 在代码中加入轻量统计框架(计数器/延迟桶/开关),不改变行为。
|
||
3. 增加最小并发回归入口(并行跑现有测试)。
|
||
|
||
### 用户验收
|
||
```bash
|
||
make -C zvfs -j4 && make -C test -j4
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_phase2_posix /zvfs
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_single_file_perf /zvfs
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_single_file_random_perf /zvfs
|
||
```
|
||
|
||
### 通过标准
|
||
- 功能测试通过。
|
||
- 有一份可复用的“基线性能记录”(IOPS/BW/延迟)。
|
||
|
||
### 可重入说明
|
||
- 仅增量加观测代码,可重复执行,不影响后续阶段。
|
||
|
||
---
|
||
|
||
## Phase 1:全局运行时与并发安全
|
||
|
||
### 要做的事情
|
||
1. 引入 `zvfs_runtime_t`,统一管理 mount/init 状态与全局资源。
|
||
2. 用 `pthread_once + mount mutex` 保护初始化/挂载过程。
|
||
3. 给 inode/path/fd/dirs 操作补齐锁(rwlock + 细粒度 mutex)。
|
||
4. 保持接口不变:`open/read/write/...` 行为兼容。
|
||
|
||
### 用户验收
|
||
```bash
|
||
make -C zvfs -j4 && make -C test -j4
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_phase2_posix /zvfs
|
||
for i in $(seq 1 8); do
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_dual_open_same_file /zvfs &
|
||
done
|
||
wait
|
||
```
|
||
|
||
### 通过标准
|
||
- 无崩溃/死锁。
|
||
- 并发场景不出现随机 EBADF/ENOENT/元数据错乱。
|
||
|
||
### 可重入说明
|
||
- 锁与 runtime 框架可独立提交;若中断,重新进入本阶段不会破坏状态。
|
||
|
||
---
|
||
|
||
## Phase 2:Worker 化 IO 通路(替换单 global_thread)
|
||
|
||
### 要做的事情
|
||
1. 实现 worker 池(默认 N:M,支持配置 1:1)。
|
||
2. 每 worker 持有独立 `spdk_thread + io_channel`。
|
||
3. read/write/pread/pwrite 路径改为“提交到绑定 worker 执行”。
|
||
4. 保留同步 POSIX 语义,但去掉全局单线程瓶颈。
|
||
|
||
### 用户验收
|
||
```bash
|
||
make -C zvfs -j4 && make -C test -j4
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_phase2_posix /zvfs
|
||
for i in $(seq 1 4); do
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_single_file_random_perf /zvfs &
|
||
done
|
||
wait
|
||
```
|
||
|
||
### 通过标准
|
||
- 功能与 Phase 1 一致。
|
||
- 并发压测吞吐明显高于基线(目标 >= 1.5x,先达成趋势)。
|
||
|
||
### 可重入说明
|
||
- worker 与旧路径可通过编译开关共存,出现问题可快速切回旧路径继续调试。
|
||
|
||
---
|
||
|
||
## Phase 3:完成等待机制与批处理
|
||
|
||
### 要做的事情
|
||
1. 用“提交队列 + 完成通知”替换纯 busy-poll `waiter`。
|
||
2. 增加批量 poll 与背压(队列满、超时、错误传播)。
|
||
3. 补齐延迟与队列深度指标,定位长尾。
|
||
4. 引入读路径流水线(允许并发 in-flight read),把有效 QD 从 1 提升到可配置值。
|
||
|
||
### 用户验收
|
||
```bash
|
||
make -C zvfs -j4 && make -C test -j4
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_single_file_perf /zvfs
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_single_file_random_perf /zvfs
|
||
```
|
||
|
||
### 通过标准
|
||
- 在同等负载下 CPU 空转显著下降。
|
||
- P99 延迟较 Phase 2 收敛(无明显长尾恶化)。
|
||
|
||
### 可重入说明
|
||
- 队列与等待层可单独演进;可先只替换 read,再替换 write。
|
||
|
||
---
|
||
|
||
## Phase 4:页缓存与写回合并
|
||
|
||
### 要做的事情
|
||
1. 引入 per-inode 4KB 页缓存(dirty/clean 状态)。
|
||
2. 小写走 cache + 延迟刷盘,大写/顺序写支持直写或批量写。
|
||
3. 引入 flush 策略:阈值、定时、fsync 强制。
|
||
4. 缩减 `resize + sync_md` 频率(chunk 预分配)。
|
||
5. 读性能专项:
|
||
- 增加顺序读 readahead(如 128KB~1MB 窗口自适应)。
|
||
- 对齐读支持“直接读到用户缓冲”快路径,减少一次 memcpy。
|
||
- 引入 clean page cache(读热点复用,避免重复 blob read)。
|
||
|
||
### 用户验收
|
||
```bash
|
||
make -C zvfs -j4 && make -C test -j4
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_phase2_posix /zvfs
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_single_file_random_noaligned_perf /zvfs
|
||
```
|
||
|
||
### 通过标准
|
||
- 功能语义不回退(truncate/sparse/rename/fstat 通过)。
|
||
- 小块随机写吞吐继续提升,写放大降低。
|
||
|
||
### 可重入说明
|
||
- cache 可先只支持 write-through,再切 write-back;两步都可单独验收。
|
||
|
||
---
|
||
|
||
## Phase 5:元数据日志化与 fsync 语义闭环
|
||
|
||
### 要做的事情
|
||
1. `meta_save/load` 从文本快照升级为 WAL + checkpoint(带 CRC/版本)。
|
||
2. 明确并实现 `fdatasync/fsync` 语义:
|
||
- fdatasync 保证数据持久化;
|
||
- fsync 额外保证必要元数据持久化。
|
||
3. 补齐崩溃恢复流程(checkpoint + replay)。
|
||
|
||
### 用户验收
|
||
```bash
|
||
make -C zvfs -j4 && make -C test -j4
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_phase2_posix /zvfs
|
||
# 建议补充一次“异常退出后重启读取”的恢复验证(手工执行)
|
||
```
|
||
|
||
### 通过标准
|
||
- 重启后目录项与文件大小不丢失、不错乱。
|
||
- 数据库关键路径(fsync/fdatasync)语义满足预期。
|
||
|
||
### 可重入说明
|
||
- WAL 与 checkpoint 支持并存迁移;可先双写验证,再切主读路径。
|
||
|
||
---
|
||
|
||
## Phase 6:性能收敛与上线门槛
|
||
|
||
### 要做的事情
|
||
1. 清理临时开关,保留必要调优参数。
|
||
2. 整理性能报告(与 Phase 0 基线对比)。
|
||
3. 做最终回归矩阵(功能 + 并发 + 性能 + 恢复)。
|
||
|
||
### 用户验收
|
||
```bash
|
||
make -C zvfs -j4 && make -C test -j4
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so make -C test run-test
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_single_file_perf /zvfs
|
||
env LD_PRELOAD=/home/lian/share/10.1-spdk/zvfs/zvfs/libzvfs.so ./test/bin/test_single_file_random_perf /zvfs
|
||
```
|
||
|
||
### 通过标准
|
||
- 全量功能测试通过。
|
||
- 多线程性能达到 `codexplan.md` 目标(或给出量化偏差与原因)。
|
||
|
||
### 可重入说明
|
||
- 本阶段仅收敛与验收,不引入架构性变更;可反复执行直到指标稳定。
|
||
|
||
---
|
||
|
||
## 附:root 权限与运行建议
|
||
|
||
- 若 NVMe/SPDK 环境需要 root,请在你本机按现有流程执行验收。
|
||
- 若希望无 root 回归,建议补一个 `Malloc` bdev 的 JSON 配置,并将 bdev 名改为可配置(环境变量优先)。
|