Skip to content

[Perf+Enhancement] AdBlock 性能与可观测性 follow-up(trie + 指标 + cache 清理) #199

Description

@flyhigher139

跟踪:#191

问题

三个相对独立的 follow-up,单个 PR 都不大,但都属于"长期债",合并到一个 tracking issue 里便于分配。

A. 域名前缀 trie 替换 HashMap/HashSet

现状(src-tauri/crates/mhost-dns/src/adblock.rs:105,2026-09-15 更新行号):规则以 HashMap<String, IpAddr> / HashSet<String> 存储,每个域名 String 24 字节指针 + len + capacity,100k 规则 ≈ 50 MB 堆。注意 #205 已把单源硬顶提到 500k 规则、响应上限 64MB,大列表源的内存压力比本文写作时更现实。

Arc::swap 时旧 snapshot 再驻留一会儿,高峰期内存压力明显。

建议:换成 reversed-domain trie(按 label 反序建树,com → example → ads → tracker)。同 100k 规则压到 5–10 MB,lookup 从 O(走链 × 哈希) → O(域名 label 数)。

验收:

  • 替换 RulesSnapshot 内部表示
  • 公开 API(rebuild / check / rule_count / *_count)不变
  • walk_parents 逻辑可以保留(用 trie 的 descend 替代 HashMap lookup),或者改成 trie 自身支持 "find longest suffix prefix match"
  • benchmark:cargo bench 100k 规则下 lookup p99 < 1µs
  • 现有所有 AdBlockEngine 单测不动

工作量:3–5 天。

B. ad-block 命中率 / 刷新耗时指标

现状:AdBlockEngine 只暴露 rule_count / *_count,没有命中率、没有刷新成功率。

建议:

  • AdBlockEngine 加 AtomicU64:hits_zero_addr / hits_nxdomain / hits_whitelist / misses
  • 每个 source 加 last_refresh_duration_ms / last_refresh_success_at / last_refresh_failed_at
  • 新增 IPC get_ad_block_stats() -> AdBlockStats
  • AdBlock.tsx 加一个 "Stats" 折叠面板:今日命中次数、最后一次刷新耗时、源失败率

验收:

  • check 返回 Some 时 hits_* 累加
  • check 返回 None 且 master switch on 时 misses 累加(不要把 whitelist 命中算 miss)
  • 周期刷新任务在 fetch 前后记时间戳、写回 source
  • 单测:100 次查询混合 whitelist + block + miss,断言计数准确

工作量:1 天。

C. 禁用源 cache 文件清理

现状:用户禁用一个 source 后,adblock-cache/{id}.txt 仍占空间。purge_source(src-tauri/crates/mhost-storage/src/adblock.rs:243,2026-09-15 更新行号)只在源被删除时清 cache,禁用不清。

2026-09-15 补充:现在已有 sweep_orphan_caches(同文件 ~L204)清扫不在 state.sources 中的孤儿 cache 文件(覆盖已删除的源),但禁用源仍在 state.sources 里、cache 不受影响——本项仍按原计划有效,实现时勿重复造清扫。

建议:

  • 二选一:
    • A. 禁用即清:source 切到 disabled 时调 delete_cache,下次 enable 时自动重 fetch
    • B. 禁用不清:但 add_ad_block_source_impl 列表超过 N 条时 LRU 清理最久未刷新成功的 cache
  • 优先 A(行为更可预测,但需要确保切回 enabled 时主动 refresh)

验收:

  • 选 A:set_ad_block_source_enabled(false, _) 末尾 delete_cache;切回 enabled 时 set_ad_block_source_enabled(true, _) 末尾调一次 fetch_and_cache_source
  • 选 B:在 mhost_storage 里加 prune_idle_caches(root, keep_n: usize),周期任务跑前调一次

工作量:0.5 天。

优先

P3。这三项都属于"等真出问题再做也不迟"的优化。但 trie 那项可以在跑大列表源(>200k 规则)用户反馈内存时立刻启动。

涉及文件

  • src-tauri/crates/mhost-dns/src/adblock.rs(trie + counters)
  • src-tauri/crates/mhost-storage/src/adblock.rs(cache 清理)
  • src-tauri/src/commands/adblock.rs(stats IPC)
  • src-tauri/src/commands/dns.rs(refresh 耗时记录)
  • src/lib/tauri.ts + src/stores/profiles/actions.ts + src/pages/AdBlock.tsx(前端 stats 面板)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    dns-modeDNS mode (本地 DNS server) 相关问题enhancementNew feature or requestperfPerformance issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions