Skip to content

fix(search): reconcile skip_trigram_files with disk-loaded trigram indexes#614

Closed
justrach wants to merge 1 commit into
perf/background-warmupfrom
perf/skip-trigram-reconcile
Closed

fix(search): reconcile skip_trigram_files with disk-loaded trigram indexes#614
justrach wants to merge 1 commit into
perf/background-warmupfrom
perf/skip-trigram-reconcile

Conversation

@justrach

Copy link
Copy Markdown
Owner

Summary

Stacked on #613 (perf/background-warmup) — only the last commit (a8a3797) is new here.

Fixes the dominant production search-tail bug: on the standard serve/mcp/cli-daemon startup path, tier 3 content-scanned the entire project on every fall-through query with recall_complete=false.

Two compounding failures:

  1. Snapshot restore parks every file in skip_trigram_files (it cannot know what a disk trigram index covers), and nothing reconciled the set when the disk index was later mmap-loaded.
  2. loadTrigramFromDiskIfPresent early-returned whenever trigram fileCount() > 0 — and the snapshot freshness pass reindexes changed files into the heap trigram before that check runs, so a single dirty file blocked the disk trigram load entirely.

Measured live on this repo: 613/616 files in the scan set, 9.2ms negative searches -> 0 files, 0.5–0.9ms, recall_complete=true. This matches the production search p90 (30ms).

Fix:

  • adoptTrigramIndex: single funnel for trigram replacement — swaps, bumps the search generation, prunes covered files from the skip set
  • adoptTrigramBase: mmap disk load keeps freshness-reindexed files as a masking overlay, so their newer content wins over stale base entries
  • rebuildTrigrams: now prunes what it covers + bumps the generation (it did neither)
  • both disk-load gates skip only when already disk-backed or the heap covers the whole project
  • watcher: CODEDB_TRIGRAM_CAP env override (measured on a 20k-file corpus: uncapped = zero-hit queries 7.1ms -> 1.4ms for +110MB peak RSS, +300ms index time); provenance meta reports the effective cap. Default unchanged.

Test plan

  • zig build test — 835/835 (includes new overlay test: new content wins / stale masked / base-only files resolve)
  • python3 scripts/e2e_mcp_test.py — 20/20
  • Live verification: skip set 613 -> 0 files after mmap load; overlay search finds new-content matches in freshness-reindexed files alongside base files
  • 20k-file corpus RSS/latency measurements for the cap override

Generated with Devin

…ndexes

Snapshot restore parks EVERY file in skip_trigram_files (it cannot know
what a disk trigram index covers), and nothing ever removed entries when
the index was later mmap-loaded. Worse, loadTrigramFromDiskIfPresent
early-returned whenever trigram fileCount() > 0 — and the snapshot
freshness pass reindexes changed files into the heap trigram BEFORE that
check runs, so one dirty file blocked the disk load entirely. Net
effect on the dominant serve/mcp/cli-daemon startup path: tier 3
content-scanned the ENTIRE project on every fall-through query, with
recall_complete=false. Measured live on this repo: 613/616 files in the
scan set, 9.2ms negative searches -> 0 files, 0.5-0.9ms, recall_complete
=true. This matches the production search tail (p90 30ms).

- adoptTrigramIndex: single funnel for trigram replacement — swaps,
  bumps the search generation, and prunes covered files from the skip set
- adoptTrigramBase: mmap disk load keeps freshness-reindexed files as a
  masking overlay (their newer content wins; stale base entries masked)
- rebuildTrigrams: prunes what it covers + bumps the generation (it did
  neither)
- both disk-load gates now skip only when already disk-backed or the
  heap covers the whole project
- watcher: trigram cap env override CODEDB_TRIGRAM_CAP (measured on a
  20k-file corpus: uncapped = zero-hit queries 7.1->1.4ms for +110MB
  peak RSS); provenance meta reports the effective cap

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

Benchmark Regression Report

Thresholds: 10.00% and 50,000 ns absolute delta

NOISE means the percentage threshold was exceeded, but the absolute delta was too small to fail CI.

Tool Base (ns) Head (ns) Delta Abs Delta (ns) Status
codedb_bundle 100112 103466 +3.35% +3354 OK
codedb_changes 10332 10103 -2.22% -229 OK
codedb_context 781734 780345 -0.18% -1389 OK
codedb_deps 338 327 -3.25% -11 OK
codedb_edit 32371 30154 -6.85% -2217 OK
codedb_find 2515 2964 +17.85% +449 NOISE
codedb_hot 25431 24385 -4.11% -1046 OK
codedb_outline 37797 35761 -5.39% -2036 OK
codedb_read 15725 15978 +1.61% +253 OK
codedb_search 13208 12716 -3.73% -492 OK
codedb_snapshot 66587 69270 +4.03% +2683 OK
codedb_status 9355 8818 -5.74% -537 OK
codedb_symbol 52111 54679 +4.93% +2568 OK
codedb_tree 18811 19126 +1.67% +315 OK
codedb_word 12314 11640 -5.47% -674 OK

@justrach justrach deleted the branch perf/background-warmup June 12, 2026 15:21
@justrach justrach closed this Jun 12, 2026
@justrach justrach deleted the perf/skip-trigram-reconcile branch June 12, 2026 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant