🔴 [H3] scroll_during_append 使用过期 PreadReader 导致增长文件 benchmark 失真 #36

Closed
opened 2026-06-05 11:53:22 +08:00 by dailz · 1 comment
Owner

问题

bench_scroll_during_append 在追加线程启动前只打开一次 PreadReaderPlainPreadReaderline_index.total_lines 和文件大小在 open 时缓存,get_line_implidx >= total 直接返回 None

current_line 超过初始行数后,后续读取不再触达追加的新内容,而是快速返回 None

影响

该 benchmark 实际测到的是“部分真实读取 + 大量 None 快速返回”,无法反映滚动读取追加内容的性能。

位置

  • crates/bench/src/suites/growth.rs:183
  • crates/bench/src/suites/growth.rs:188
  • crates/bench/src/pread_reader.rs:109

建议

周期性刷新 reader 或重新设计测试窗口,让读取逻辑能看到追加后的行数;不要每次迭代都重建索引,否则 benchmark 会变成测 reopen 成本。

## 问题 `bench_scroll_during_append` 在追加线程启动前只打开一次 `PreadReaderPlain`。`PreadReader` 的 `line_index.total_lines` 和文件大小在 open 时缓存,`get_line_impl` 对 `idx >= total` 直接返回 `None`。 当 `current_line` 超过初始行数后,后续读取不再触达追加的新内容,而是快速返回 `None`。 ## 影响 该 benchmark 实际测到的是“部分真实读取 + 大量 None 快速返回”,无法反映滚动读取追加内容的性能。 ## 位置 - `crates/bench/src/suites/growth.rs:183` - `crates/bench/src/suites/growth.rs:188` - `crates/bench/src/pread_reader.rs:109` ## 建议 周期性刷新 reader 或重新设计测试窗口,让读取逻辑能看到追加后的行数;不要每次迭代都重建索引,否则 benchmark 会变成测 reopen 成本。
dailz closed this issue 2026-06-05 14:40:44 +08:00
Author
Owner

修复方案

根因: PreadReaderCoreopen_raw 时一次性构建 LineIndexfile_sizetotal_lines 之后永不更新。get_line_implidx >= total_lines 直接返回 None,导致 benchmark 在 current_line 超过初始 150K 行后全部测量 None 快速返回。

修复 (commit 9baec5a):

  1. PreadReaderCore::refresh_index(&mut self) — seek 回文件头,完整重建 LineIndex,更新 file_size,清除读缓存
  2. PreadReaderPlain::refresh_index — 转发到 inner
  3. ReadCache::invalidate — 清空缓存长度,强制下次 get() 执行真实 I/O
  4. 重写 bench_scroll_during_append:
    • 每 250ms 定时刷新索引(不计入 frame latency)
    • 只在 get_line 返回 Some 时记录延迟;None 时 sleep 1ms 等待追加
    • 末尾 assert 确保 max_line_seen > initial_lines,验证确实读到了追加内容
    • 新增指标:refresh_countnone_countinitial_linesmax_line_seen

测试: 新增 2 个回归测试(47/47 全部通过):

  • test_refresh_index_sees_appended_lines — 写 3 行 → 追加 2 行 → refresh → 断言可读新行
  • test_refresh_index_no_change_is_noop — 文件未变时 refresh 不破坏已有索引
## 修复方案 **根因**: `PreadReaderCore` 在 `open_raw` 时一次性构建 `LineIndex`,`file_size` 和 `total_lines` 之后永不更新。`get_line_impl` 对 `idx >= total_lines` 直接返回 `None`,导致 benchmark 在 `current_line` 超过初始 150K 行后全部测量 `None` 快速返回。 **修复** (commit 9baec5a): 1. **`PreadReaderCore::refresh_index(&mut self)`** — seek 回文件头,完整重建 `LineIndex`,更新 `file_size`,清除读缓存 2. **`PreadReaderPlain::refresh_index`** — 转发到 inner 3. **`ReadCache::invalidate`** — 清空缓存长度,强制下次 get() 执行真实 I/O 4. **重写 `bench_scroll_during_append`**: - 每 250ms 定时刷新索引(不计入 frame latency) - 只在 `get_line` 返回 `Some` 时记录延迟;`None` 时 sleep 1ms 等待追加 - 末尾 assert 确保 `max_line_seen > initial_lines`,验证确实读到了追加内容 - 新增指标:`refresh_count`、`none_count`、`initial_lines`、`max_line_seen` **测试**: 新增 2 个回归测试(47/47 全部通过): - `test_refresh_index_sees_appended_lines` — 写 3 行 → 追加 2 行 → refresh → 断言可读新行 - `test_refresh_index_no_change_is_noop` — 文件未变时 refresh 不破坏已有索引
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dailz/logViewer#36