perf(scanner): batch inserts + bulk snapshot eviction (~33x on 1 GB) - #18
Open
Dig1taly wants to merge 1 commit into
Open
perf(scanner): batch inserts + bulk snapshot eviction (~33x on 1 GB)#18Dig1taly wants to merge 1 commit into
Dig1taly wants to merge 1 commit into
Conversation
Replace the per-message INSERT/DELETE loop with batched executemany() and a single temp-table-driven eviction pass. Observable behavior is unchanged: scan_file() still tracks per-file byte offsets, partial-line handling is identical, streaming-snapshot dedup still keeps only the final uuid per (session_id, message_id), and full rescans remain idempotent. What changed: - _parse_file(): pure-Python parser, returns lists of dicts (no DB touch) - _dedupe_inflight_snapshots(): collapses streaming snapshots within the in-memory batch before any DB work - _evict_prior_snapshots_bulk(): one temp-table-driven JOIN to find dead uuids, then chunked DELETEs (stays under SQLITE_MAX_VARIABLE_NUMBER) - scan_file(): parse -> dedupe -> evict -> executemany INSERT - scan_dir() unchanged Measured on 1.0 GB / 566 files / ~200k messages: before: 4773 s (~80 min) after: 145 s (~2.4 min) speedup: ~33x All 71 unit tests pass, including the streaming-snapshot dedup tests in test_scanner_dedup.py which exercise the eviction semantics. Stdlib only, no new dependencies, no API changes.
muckybuzzwoo
added a commit
to muckybuzzwoo/token-dashboard
that referenced
this pull request
May 22, 2026
Adapts upstream PR nateherkai#18 (Dig1taly) to this fork. Replaces per-message INSERT/DELETE round-trips with batched executemany() and a single temp-table-driven snapshot eviction pass. Fork-specific additions to preserve correctness: - _parse_file()'s output (and the new scan_file() return value) carries the days and sessions sets that scan_dir() needs for incremental rebuild of the materialised summary tables (introduced by PR nateherkai#13). Without this, summaries would silently grow stale after every scan. - File-level batched commits (BATCH_SIZE=20) from PR nateherkai#13 remain in scan_dir(); the new in-file batching from nateherkai#18 composes on top of that, not as a replacement. Measured locally on this fork: a full rescan of 589 files / 63k messages drops from minutes to ~7.5 seconds. Upstream PR: nateherkai#18
muckybuzzwoo
added a commit
to muckybuzzwoo/token-dashboard
that referenced
this pull request
May 22, 2026
…kai#19 - nateherkai#18 (perf scanner) and nateherkai#19 (attributionSkill + split skills view) added to the Integrated upstream PRs table with adaptation notes. - nateherkai#17 added to Deliberately skipped with the reason: PR nateherkai#17's progress callback signature (scanned, total, totals) is strictly less informative than this fork's (index, total, path, totals) from PR #2, so integrating it would degrade the CLI progress printer. - Differences from upstream rewritten: clarifies the new Skills & Commands route's split between "You ran" (slash commands via attribution_skill) and "Claude invoked" (real Skill tool calls), and notes that the two sources are de-duplicated against each other so the same slash command never inflates both columns. - Scanner performance section updated to reflect the post-nateherkai#18 measurement (~7.5s full rescan of ~600 files / 60k+ messages).
muckybuzzwoo
added a commit
to muckybuzzwoo/token-dashboard
that referenced
this pull request
May 22, 2026
After PR nateherkai#18 the production scan path uses _evict_prior_snapshots_bulk exclusively. The single-row helper was kept "for historical reference" in the PR nateherkai#18 commit, but nothing in the codebase calls it. Removing it eliminates an unowned half-decision and consolidates the eviction docstring on the function that actually runs. The CLAUDE.md "Streaming-snapshot dedup" bullet still points at the old symbol; that reference will be updated in a separate CLAUDE.md revision (out of scope for this fork-integration sweep).
muckybuzzwoo
added a commit
to muckybuzzwoo/token-dashboard
that referenced
this pull request
May 22, 2026
- README clone URL now points at the fork (was upstream). - "The 7 tabs" → "The 8 tabs" — adds RTK and updates the Skills entry to describe the new "You ran" / "Claude invoked" split. Settings section mentions Team plans (PR nateherkai#15) and runtime .claude-folder switching (PR nateherkai#7). - First-run scan-time estimate dropped from 20–60s to 5–10s to reflect the PR nateherkai#18 batched-insert scanner. Prompts entry now mentions the CSV / Markdown export (PR nateherkai#10). - FORK_NOTES.md gains a "Last updated" line at the top pointing at the commits page as the running change log.
|
Integrated this into a fork at https://github.com/muckybuzzwoo/token-dashboard (commit Real-world measurement on the fork's owner's DB: ~600 files / 60k+ messages full rescan completes in ~7.5 seconds. Thanks for the speedup! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the per-message INSERT/DELETE loop in `scan_file()` with batched `executemany()` and a single temp-table-driven snapshot eviction. Observable behavior is unchanged; throughput is dramatically higher on heavy data sets.
Measured speedup
On a real `~/.claude/projects` of 1.0 GB / 566 files / ~200k messages:
Incremental scans (the common case once the DB is built) stay fast either way - the per-file mtime/offset short-circuit short-circuits before the new code path even runs.
What changed
All inside `token_dashboard/scanner.py`. Public API of `scan_file` and `scan_dir` is unchanged.
Constraints respected
Why it's so much faster
Two compounding wins on heavy data sets:
Tests
```
$ python -m unittest discover tests
Ran 71 tests in 17.170s
OK
```
Including the eviction tests in `test_scanner_dedup.py` which directly exercise the new `_evict_prior_snapshots_bulk` path through `scan_file` and verify that earlier snapshots are dropped from both `messages` and `tool_calls` while the final tally survives.
Not in this PR (deliberately)
Happy to split into smaller commits, rename anything, or rework if you'd like a different shape.