---
phase: 01-measurement
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - benches/parser_benchmark.rs
autonomous: true
requirements:
  - MEAS-01
  - MEAS-02
  - MEAS-03

must_haves:
  truths:
    - "cargo bench 输出包含 GB/s 吞吐量（Throughput::Bytes 变体）"
    - "cargo bench 输出包含 records/sec 吞吐量（Throughput::Elements 变体，名称后缀 _rps）"
    - "benchmark 包含 parse_sqllog_multiline_5mb 变体，语料库中 20% 为多行 SQL 记录（每 5 条中第 1 条为多行）"
    - "benchmark 包含 parse_sqllog_metrics_5mb 变体，循环内调用 parse_performance_metrics()"
    - "现有 parse_sqllog_file_5mb 变体保留不变（语料库和代码均不修改）"
  artifacts:
    - path: "benches/parser_benchmark.rs"
      provides: "扩展后的 benchmark 文件，包含多行语料库生成函数和 5 个新变体"
      contains:
        - "fn generate_synthetic_log_multiline"
        - "parse_sqllog_multiline_5mb"
        - "parse_sqllog_metrics_5mb"
        - "parse_sqllog_file_5mb_rps"
        - "Throughput::Bytes"
        - "Throughput::Elements"
  key_links:
    - from: "generate_synthetic_log_multiline"
      to: "parse_sqllog_multiline_5mb bench_function"
      via: "NamedTempFile 临时文件路径"
    - from: "parse_sqllog_metrics_5mb"
      to: "parse_performance_metrics()"
      via: "LogParser::from_path().iter().filter_map().map()"
---

<objective>
扩展 benches/parser_benchmark.rs：新增多行合成语料库生成函数，注册 5 个新 benchmark 变体，使 cargo bench 同时输出 GB/s 和 records/sec，并覆盖含多行 SQL 的真实工作负载。

Purpose: 当前 benchmark 只测 iter().count()，语料库全为均匀单行记录，无法反映真实热路径工作量（parse_performance_metrics 调用）和真实语料库分布（含 DDL/复杂查询的多行 SQL）。
Output: 扩展后的 benches/parser_benchmark.rs，包含 generate_synthetic_log_multiline 函数和 5 个新变体。
</objective>

<execution_context>
@/Users/guang/.claude/get-shit-done/workflows/execute-plan.md
@/Users/guang/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/01-measurement/01-CONTEXT.md

<interfaces>
<!-- 现有代码接口，执行者直接使用，无需探索代码库 -->

From benches/parser_benchmark.rs（现有代码）:
```rust
// 现有语料库生成函数（保留不变）
fn generate_synthetic_log(target_bytes: usize) -> NamedTempFile {
    // 生成单行 SQL 记录，每条约 206 字节
    // 单行记录内容：2025-08-12 10:57:09.548 (...) [SEL] SELECT id, name, value FROM benchmark_table WHERE id = 12345 EXECTIME: 1(ms) ROWCOUNT: 1(rows) EXEC_ID: 289655178.\n
}

// 现有 benchmark 注册方式
fn benchmark_parser(c: &mut Criterion) {
    let mut group = c.benchmark_group("parser_group");
    group.sample_size(30);
    group.measurement_time(Duration::from_secs(60));
    group.warm_up_time(Duration::from_secs(5));
    // group.throughput() + group.bench_function() 模式
    group.finish();
}
```

From src/sqllog.rs（调用方法签名）:
```rust
// parse_performance_metrics() 返回 Result，在 bench 中用 filter_map(|r| r.ok()).map(|s| s.parse_performance_metrics())
// 无需知道返回类型，count() 即可
pub fn parse_performance_metrics(&self) -> Result<PerformanceMetrics, ParseError>
```

From src/parser.rs（LogParser 接口）:
```rust
pub struct LogParser { ... }
impl LogParser {
    pub fn from_path(path: impl AsRef<Path>) -> Result<Self, ParseError>
    pub fn iter(&self) -> LogIterator<'_>
}
// LogIterator 实现 Iterator<Item = Result<Sqllog<'_>, ParseError>>
```
</interfaces>
</context>

<tasks>

<task type="auto" tdd="false">
  <name>Task 1: 新增多行合成语料库生成函数</name>
  <files>benches/parser_benchmark.rs</files>
  <read_first>
    - benches/parser_benchmark.rs（了解现有 generate_synthetic_log 函数和 imports，新函数紧随其后）
    - src/sqllog.rs（确认 parse_performance_metrics 方法可正常调用，记录格式需以 "." 结尾）
  </read_first>
  <action>
在 benches/parser_benchmark.rs 的 generate_synthetic_log 函数之后，添加新函数 generate_synthetic_log_multiline。

函数签名：fn generate_synthetic_log_multiline(target_bytes: usize) -> NamedTempFile

实现规则（所有规则均为决策 D-01/D-02/D-03/D-04 的落实）：
- 使用取模计数（record_index % 5 == 0）精确控制 20% 多行记录，不用随机数
- 单行记录与现有 generate_synthetic_log 内容相同：
  `b"2025-08-12 10:57:09.548 (EP[0] sess:0x178ebca0 thrd:757455 user:BENCHMARK trxid:0 stmt:0x285eb060 appname:bench) [SEL] SELECT id, name, value FROM benchmark_table WHERE id = 12345 EXECTIME: 1(ms) ROWCOUNT: 1(rows) EXEC_ID: 289655178.\n"`
- 多行记录（record_index % 5 == 0）包含 3 行换行的 SQL body（满足 D-02 的 2-5 行要求）：
  ```
  b"2025-08-12 10:57:09.548 (EP[0] sess:0x178ebca0 thrd:757455 user:BENCHMARK trxid:0 stmt:0x285eb060 appname:bench) [SEL] SELECT\n    t1.id,\n    t2.name\nFROM benchmark_table t1\nJOIN other_table t2 ON t1.id = t2.id\nWHERE t1.id = 12345 EXECTIME: 1(ms) ROWCOUNT: 1(rows) EXEC_ID: 289655178.\n"
  ```
- 循环结构与现有函数相同：`while written < target_bytes { ... written += record.len(); record_index += 1; }`
- 函数返回 NamedTempFile

注意：多行记录中 SQL body 包含 `\n`，但记录依然以 `EXECTIME: 1(ms) ROWCOUNT: 1(rows) EXEC_ID: 289655178.\n` 结尾（以 `.` 结尾，符合 parse_performance_metrics 的解析要求）。
  </action>
  <verify>
    <automated>cargo build --bench parser_benchmark 2>&1 | grep -v "^$"</automated>
  </verify>
  <acceptance_criteria>
    - benches/parser_benchmark.rs 包含 `fn generate_synthetic_log_multiline`
    - 函数体包含 `record_index % 5 == 0`（精确 20% 比例）
    - 多行记录中包含字面 `\n    t1.id`（多行 SQL body）
    - 单行记录中包含 `EXECTIME: 1(ms) ROWCOUNT: 1(rows) EXEC_ID: 289655178.\n`
    - `cargo build --bench parser_benchmark` 编译通过，无错误
  </acceptance_criteria>
  <done>generate_synthetic_log_multiline 函数已添加，编译通过，20% 多行记录比例通过取模实现</done>
</task>

<task type="auto" tdd="false">
  <name>Task 2: 注册 5 个新 benchmark 变体</name>
  <files>benches/parser_benchmark.rs</files>
  <read_first>
    - benches/parser_benchmark.rs（在 Task 1 完成后读取，确认函数已添加，确认 group.finish() 位置）
  </read_first>
  <action>
在 benchmark_parser 函数中，group.finish() 之前，添加以下内容（完整替换 group.finish() 之前的现有代码块，保留现有 parse_sqllog_file_5mb，在其之后插入新变体）：

**步骤 1：为现有 parse_sqllog_file_5mb 添加 Throughput::Bytes 设置**

在现有 `group.bench_function("parse_sqllog_file_5mb", ...)` 之前添加：
```rust
group.throughput(criterion::Throughput::Bytes(5 * 1024 * 1024));
```

（注意：group.throughput() 是 group 级设置，下面的 bench_function 会继承）

**步骤 2：在 parse_sqllog_file_5mb 之后，group.finish() 之前插入以下代码块：**

```rust
// MEAS-01: records/sec 变体（与 parse_sqllog_file_5mb 测相同代码）
let record_count_single = {
    let parser = LogParser::from_path(&tmp_path).unwrap();
    parser.iter().filter_map(|r| r.ok()).count() as u64
};
group.throughput(criterion::Throughput::Elements(record_count_single));
group.bench_function("parse_sqllog_file_5mb_rps", |b| {
    b.iter(|| {
        let parser = LogParser::from_path(&tmp_path).unwrap();
        criterion::black_box(parser.iter().count())
    })
});

// MEAS-03: 多行语料库（20% 多行 SQL，D-04）
let tmp_multiline = generate_synthetic_log_multiline(5 * 1024 * 1024);
let tmp_multiline_path = tmp_multiline.path().to_path_buf();

group.throughput(criterion::Throughput::Bytes(5 * 1024 * 1024));
group.bench_function("parse_sqllog_multiline_5mb", |b| {
    b.iter(|| {
        let parser = LogParser::from_path(&tmp_multiline_path).unwrap();
        criterion::black_box(parser.iter().count())
    })
});

// MEAS-01: 多行 records/sec 变体
let record_count_multi = {
    let parser = LogParser::from_path(&tmp_multiline_path).unwrap();
    parser.iter().filter_map(|r| r.ok()).count() as u64
};
group.throughput(criterion::Throughput::Elements(record_count_multi));
group.bench_function("parse_sqllog_multiline_5mb_rps", |b| {
    b.iter(|| {
        let parser = LogParser::from_path(&tmp_multiline_path).unwrap();
        criterion::black_box(parser.iter().count())
    })
});

// MEAS-02: parse_performance_metrics() 变体（复用多行语料库，反映真实热路径）
group.throughput(criterion::Throughput::Bytes(5 * 1024 * 1024));
group.bench_function("parse_sqllog_metrics_5mb", |b| {
    b.iter(|| {
        let parser = LogParser::from_path(&tmp_multiline_path).unwrap();
        let count = parser
            .iter()
            .filter_map(|r| r.ok())
            .map(|s| s.parse_performance_metrics())
            .count();
        criterion::black_box(count)
    })
});

group.finish();
drop(tmp);
drop(tmp_multiline);
```

**注意事项：**
- 不要删除原有 `group.finish()` 和 `drop(tmp)`，用上面的代码块替换它们（上面代码块已包含 group.finish() 和 drop）
- `parse_sqllog_file_5mb` 现有代码本身不变，只是在其前面添加 `group.throughput(Throughput::Bytes(...))`
- `tmp_multiline` 需要在函数末尾 drop，避免临时文件被提前删除
- 使用 `criterion::Throughput::Bytes` 和 `criterion::Throughput::Elements`（带完整路径或在文件顶部添加 `use criterion::Throughput;`）
  </action>
  <verify>
    <automated>cargo bench --bench parser_benchmark -- --list 2>&1</automated>
  </verify>
  <acceptance_criteria>
    - `cargo bench --bench parser_benchmark -- --list` 输出包含 `parse_sqllog_file_5mb`（现有）
    - 输出包含 `parse_sqllog_file_5mb_rps`
    - 输出包含 `parse_sqllog_multiline_5mb`
    - 输出包含 `parse_sqllog_multiline_5mb_rps`
    - 输出包含 `parse_sqllog_metrics_5mb`
    - benches/parser_benchmark.rs 包含 `Throughput::Bytes`
    - benches/parser_benchmark.rs 包含 `Throughput::Elements`
    - benches/parser_benchmark.rs 包含 `parse_performance_metrics()`
    - `cargo build --bench parser_benchmark` 无编译错误
  </acceptance_criteria>
  <done>5 个新变体注册完毕，cargo bench --list 显示所有变体，cargo build 通过</done>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| 无 | 本 Plan 仅修改 benchmark 代码，无用户输入、无网络请求、无认证逻辑 |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-01-01 | Tampering | 合成语料库生成（generate_synthetic_log_multiline） | accept | benchmark 代码不处理外部输入，语料库完全由硬编码常量生成；无攻击面 |
</threat_model>

<verification>
```bash
# 验证所有变体存在
cargo bench --bench parser_benchmark -- --list 2>&1 | grep -E "(parse_sqllog_file_5mb|parse_sqllog_multiline_5mb|parse_sqllog_metrics_5mb)"

# 验证新函数存在
grep -n "fn generate_synthetic_log_multiline" benches/parser_benchmark.rs

# 验证 Throughput API 使用
grep -n "Throughput::" benches/parser_benchmark.rs

# 验证 20% 多行比例实现
grep -n "record_index % 5" benches/parser_benchmark.rs

# 验证 parse_performance_metrics 调用
grep -n "parse_performance_metrics" benches/parser_benchmark.rs

# 完整编译验证
cargo build --bench parser_benchmark
```
</verification>

<success_criteria>
- `cargo bench --bench parser_benchmark -- --list` 输出 6 个 benchmark（1 个现有 + 5 个新增）
- benches/parser_benchmark.rs 包含 `generate_synthetic_log_multiline` 函数，使用 `record_index % 5 == 0` 实现精确 20% 多行比例
- 多行记录包含 3 行换行的 SQL body（`SELECT\n    t1.id,\n    t2.name\nFROM ...`）
- GB/s 变体（`Throughput::Bytes`）和 records/sec 变体（`Throughput::Elements`，名称含 `_rps`）均注册
- `parse_sqllog_metrics_5mb` 在 bench 循环内调用 `parse_performance_metrics()`
- 现有 `parse_sqllog_file_5mb` 变体语料库和代码均未改变
- `cargo build --bench parser_benchmark` 无编译错误
</success_criteria>

<output>
完成后创建 `.planning/phases/01-measurement/01-01-SUMMARY.md`
</output>
