perf(cache): cross-run cache for per-package walk#585
Merged
Conversation
There was a problem hiding this comment.
Benchmark
Details
| Benchmark suite | Current: 93bff76 | Previous: 0b5fe57 | Ratio |
|---|---|---|---|
config_loading/single |
12239 ns/iter (± 235) |
10516 ns/iter (± 92) |
1.16 |
config_loading/mono_10 |
17395 ns/iter (± 247) |
15635 ns/iter (± 739) |
1.11 |
config_loading/mono_50 |
39196 ns/iter (± 1272) |
40629 ns/iter (± 432) |
0.96 |
config_loading/mono_100 |
65742 ns/iter (± 878) |
This comment was automatically generated by workflow using github-action-benchmark.
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.
Closes #508
What
Adds a cross-run cache for the dominant cost of
ferrflow check: the per-package last-tag → HEAD commit walk and bump decision. On CI a PR loops lint → build → test → check on the same commit, recomputing the same result every time. This caches the computed result so repeat invocations on an unchanged (HEAD, tags, config) return instantly.What is cached
The rendered dry-run result of
check: the JSON string (for--json) or the text output lines (default). The value type iscache::CachedRun { json: Option<String>, text_lines: Vec<String> }, written by capturing theRunOutputthat the compute path now returns instead of printing inline. A cache hit reprints these verbatim, so hit output is identical to a fresh compute by construction.Cache key
Hash of HEAD commit sha + a sha256 of the sorted
refs/tags/* → oidlines + a sha256 of the config file bytes, plus an outputvariantmarker (text/json) socheckandcheck --jsondon't collide. Filename:<head>-<tags_hash>-<config_hash>-<variant>.jsonunder.git/ferrflow-cache/(resolved viarepo.git_dir()).Which commands use it
check(default and--json) reads and writes the cache.statusdoes NOT — it has a separate, simpler compute (PackageStatus), not the shared per-package walk, so wiring it in would not be the same result. Left clean.version/tagare already cheap; uncached on purpose.releaseMUST NOT and does NOT touch the cache (always recomputes — mutating on stale data is unsafe). This bounds the blast radius: a cache bug can only affect advisorycheckoutput.Caching is also skipped when
--verbose, a--channeloverride is set, or the config has hooks/publishers configured (those produce side-effecting dry-run previews that aren't part of the cached value).Edge cases
.git: every write is best-effort (atomic temp + rename) and silently no-ops on any IO error — never errors.New subcommand
ferrflow cache cleardeletes.git/ferrflow-cache/.Tests
cache.rs: write→read round-trip, tamper→miss, read-only parent→no-op no-error, freshness window, prune by age + by cap, ignore non-json files, filename varies per key component, and key busts on new HEAD / new tag / config edit (against real temp repos).monorepo/tests.rs: end-to-end — firstcheckwrites the cache, second hits with the same key and identical lines; a new commit busts the key.Verified manually in a temp repo: two
checkruns on the same commit (miss then hit, identical output), a new commit busts it, andcache clearremoves the dir.release --dry-runcreates no cache dir.Follow-ups (separate repos, out of scope here)
cache clearsubcommand and the perf win.cache clearon ferrflow.com (FerrFlow-Cloud).