---
phase: 03-hotpath
plan: 02
type: execute
wave: 2
depends_on:
  - "03-01"
files_modified:
  - src/sqllog.rs
  - src/parser.rs
autonomous: true
requirements:
  - HOT-03
  - HOT-04

must_haves:
  truths:
    - "parse_performance_metrics 被 #[inline(always)] 标注"
    - "parser.rs 中存在 #[cold] 标注的独立错误路径函数，消除主函数中的 InvalidFormat 内联构造"
    - "LogParser::from_path 在 Unix 上调用 mmap.advise(Advice::Sequential)，Windows 上通过 cfg 门控跳过"
    - "cargo test 全部通过，cargo build --release 无 warning"
  artifacts:
    - path: "src/sqllog.rs"
      provides: "#[inline(always)] 标注在 parse_performance_metrics 函数上"
      contains: "#[inline(always)]"
    - path: "src/parser.rs"
      provides: "#[cold] 标注的 make_invalid_format_error 函数"
      contains: "#[cold]"
    - path: "src/parser.rs"
      provides: "#[cfg(unix)] 门控的 mmap advise 调用"
      contains: "Advice::Sequential"
  key_links:
    - from: "src/parser.rs :: parse_record_with_hint"
      to: "make_invalid_format_error"
      via: "替换 ParseError::InvalidFormat 内联构造"
      pattern: "make_invalid_format_error"
    - from: "src/parser.rs :: LogParser::from_path"
      to: "mmap.advise"
      via: "#[cfg(unix)] 门控"
      pattern: "cfg.*unix.*advise"
---

<objective>
对热路径和 I/O 初始化层施加两项编译器/OS 级提示：

1. **HOT-03 内联/cold 标注**：
   - `parse_performance_metrics` 加 `#[inline(always)]`（强制热路径内联）
   - 将 `parse_record_with_hint` 中 `ParseError::InvalidFormat` 构造点提取为独立 `#[cold]` 函数 `make_invalid_format_error`

2. **HOT-04 mmap advise**：
   - `LogParser::from_path` 在 mmap 构造后调用 `mmap.advise(memmap2::Advice::Sequential)`
   - 用 `#[cfg(unix)]` 门控，Windows 上跳过（`advise` 方法 Unix-only）
   - 调用结果用 `let _ = ...` 忽略（失败静默忽略）

Purpose: 消除 `parse_performance_metrics` 的函数调用开销；提升顺序 mmap 读取的 OS 预读效率。
Output: 修改后的 `src/sqllog.rs` 和 `src/parser.rs`。
</objective>

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

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/03-hotpath/03-RESEARCH.md
@.planning/phases/03-hotpath/03-01-SUMMARY.md

<interfaces>
<!-- 从 src/sqllog.rs 提取的目标函数签名 -->

```rust
// 目标：加 #[inline(always)]（src/sqllog.rs ~105行）
pub fn parse_performance_metrics(&self) -> PerformanceMetrics<'a> { ... }
```

<!-- 从 src/parser.rs 提取的错误路径和 mmap 构造 -->

```rust
// parse_record_with_hint 中的 InvalidFormat 返回点（src/parser.rs ~250、265、280行）
// 共有 3 处，格式均为：
return Err(ParseError::InvalidFormat {
    raw: String::from_utf8_lossy(first_line).to_string(),
});

// LogParser::from_path mmap 构造之后（src/parser.rs ~35-45行）
let mmap = unsafe { Mmap::map(&file).map_err(|e| ParseError::IoError(e.to_string()))? };
// HOT-04 插入位置：此行之后，encoding 检测之前
// 当前已有的 use：use memmap2::Mmap;
// 需要新增：use memmap2::Advice;（或改写为 memmap2::Advice::Sequential 限定路径）

// ParseError::InvalidFormat 定义（src/error.rs）
ParseError::InvalidFormat { raw: String }
```
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: HOT-03 内联和 cold 标注</name>
  <files>src/sqllog.rs, src/parser.rs</files>
  <read_first>
    - src/sqllog.rs（必读：确认 parse_performance_metrics 函数签名及当前是否已有属性标注）
    - src/parser.rs（必读：确认 parse_record_with_hint 中 InvalidFormat 出现的行号和数量）
    - .planning/phases/03-hotpath/03-RESEARCH.md（Pitfall 4：#[cold] 只能用于函数定义）
  </read_first>
  <action>
**修改 src/sqllog.rs：**

在 `parse_performance_metrics` 函数定义前一行加 `#[inline(always)]`：

```rust
#[inline(always)]
pub fn parse_performance_metrics(&self) -> PerformanceMetrics<'a> {
    // 函数体不变
}
```

**修改 src/parser.rs：**

1. 在文件末尾（`parse_record_with_hint` 函数之后，模块顶层）添加私有辅助函数：

```rust
/// 将原始字节转换为 InvalidFormat 错误（错误路径，标注 cold 避免影响热路径代码布局）
#[cold]
fn make_invalid_format_error(raw_bytes: &[u8]) -> ParseError {
    ParseError::InvalidFormat {
        raw: String::from_utf8_lossy(raw_bytes).to_string(),
    }
}
```

2. 将 `parse_record_with_hint` 中所有 `return Err(ParseError::InvalidFormat { raw: ... })` 替换为：

```rust
return Err(make_invalid_format_error(first_line));
```

注意：`parse_record_with_hint` 中有 3 处 InvalidFormat 返回（first_line 长度不足、缺少 `(`、缺少 `)`），全部替换为 `make_invalid_format_error(first_line)`。

函数签名中 `raw_bytes: &[u8]` 参数接收 `first_line`（已是 `&[u8]`），无需类型转换。

确保 `make_invalid_format_error` 函数体不超过 5 行（CLAUDE.md：函数 ≤ 40 行）。
  </action>
  <verify>
    <automated>cargo build 2>&1 | grep -E "^error" | head -10; cargo test 2>&1 | tail -5</automated>
  </verify>
  <done>
    - `cargo build` 无 error
    - `cargo test` 全部通过
    - `src/sqllog.rs` 中 `parse_performance_metrics` 前一行为 `#[inline(always)]`
    - `src/parser.rs` 包含 `#[cold]` 和 `make_invalid_format_error`
    - `src/parser.rs` 不再包含内联的 `ParseError::InvalidFormat { raw: String::from_utf8_lossy`（已替换为函数调用）
  </done>
</task>

<task type="auto">
  <name>Task 2: HOT-04 mmap Sequential advise</name>
  <files>src/parser.rs</files>
  <read_first>
    - src/parser.rs（必读：确认 LogParser::from_path 中 mmap 构造行和现有 use memmap2 语句）
    - .planning/phases/03-hotpath/03-RESEARCH.md（HOT-04 Pattern 章节和 Pitfall 5：Windows 编译失败）
  </read_first>
  <action>
**修改 src/parser.rs：**

1. 在文件顶部 use 语句区，将 `use memmap2::Mmap;` 改为：

```rust
use memmap2::{Advice, Mmap};
```

2. 在 `LogParser::from_path` 函数中，`let mmap = unsafe { ... }?;` 之后、`let sample = ...` 之前插入：

```rust
// HOT-04: 告知 OS 以顺序模式预读 mmap 页面，减少 page fault 开销
// Unix-only；Windows 上 advise() 方法不存在，cfg 门控跳过
// 失败（如内核不支持）静默忽略，不影响正确性
#[cfg(unix)]
let _ = mmap.advise(Advice::Sequential);
```

完整目标函数体（仅展示改动区域）：

```rust
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, ParseError> {
    let file = File::open(path).map_err(|e| ParseError::IoError(e.to_string()))?;
    let mmap = unsafe { Mmap::map(&file).map_err(|e| ParseError::IoError(e.to_string()))? };

    #[cfg(unix)]
    let _ = mmap.advise(Advice::Sequential);

    let sample = &mmap[..];
    let encoding = if simd_from_utf8(sample).is_ok() {
        FileEncodingHint::Utf8
    } else {
        FileEncodingHint::Gb18030
    };

    Ok(Self { mmap, encoding })
}
```

不修改函数签名和其他逻辑。
  </action>
  <verify>
    <automated>cargo build 2>&1 | grep -E "^error" | head -10; cargo test 2>&1 | tail -5; grep -n "Advice::Sequential" src/parser.rs</automated>
  </verify>
  <done>
    - `cargo build` 无 error（含 `#[cfg(unix)]` 正确门控，不报 dead_code 或 unused_imports）
    - `cargo test` 全部通过
    - `src/parser.rs` 包含 `Advice::Sequential`
    - `src/parser.rs` 包含 `#[cfg(unix)]` 紧跟 `advise` 调用
    - `src/parser.rs` 的 use memmap2 行包含 `Advice`
  </done>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| OS mmap advise → 内核 | advise 为提示，不影响正确性 |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-03-03 | Availability | HOT-04 advise 失败 | accept | `let _ = mmap.advise(...)` 静默忽略失败；advise 失败只影响性能预读，不影响解析正确性 |
| T-03-04 | Tampering | HOT-03 make_invalid_format_error 参数 | accept | 函数仅将字节转为 lossy UTF-8 字符串用于错误消息，无安全边界穿越；错误路径不处理可信数据 |
</threat_model>

<verification>
整体 Phase 3 最终验证（Plan 01 + Plan 02 均完成后）：

```bash
# 1. 全量测试
cargo test

# 2. Release 构建无 warning
cargo build --release 2>&1 | grep -E "^warning|^error"

# 3. HOT-01 早退存在
grep -n "last_meaningful" src/sqllog.rs

# 4. HOT-02 memrchr 存在
grep -n "memrchr" src/sqllog.rs

# 5. HOT-03 inline 存在
grep -n "inline(always)" src/sqllog.rs

# 6. HOT-03 cold 存在
grep -n "#\[cold\]" src/parser.rs

# 7. HOT-04 advise 存在
grep -n "Advice::Sequential" src/parser.rs

# 8. cfg(unix) 门控存在
grep -n "cfg(unix)" src/parser.rs

# 9. CORR-03 守卫未被删除
grep -n "parse_indicators_from_bytes.*is_none" src/sqllog.rs

# 10. 覆盖率不退化
cargo llvm-cov --workspace --all-features --fail-under-lines 90 2>&1 | tail -5
```
</verification>

<success_criteria>
- `cargo test` 退出码 0
- `cargo build --release` 无 error
- `src/sqllog.rs` 包含 `#[inline(always)]` 紧接 `parse_performance_metrics`
- `src/parser.rs` 包含 `#[cold]` 标注的 `make_invalid_format_error` 函数
- `src/parser.rs` 包含 `#[cfg(unix)]` + `mmap.advise(Advice::Sequential)`
- `src/parser.rs` use memmap2 导入包含 `Advice`
- 覆盖率 ≥ 90%（`cargo llvm-cov --fail-under-lines 90` 通过）
</success_criteria>

<output>
完成后创建 `.planning/phases/03-hotpath/03-02-SUMMARY.md`，记录：
- HOT-03/04 改动摘要
- `make_invalid_format_error` 函数替换的行数
- `#[cfg(unix)]` advise 插入位置
- `cargo test` 和 `cargo build --release` 输出摘要
</output>
