Repository navigation
Cut the dev gate's memory and disk cost, and a third of its wall clock - #76
Merged
Merged
Conversation
Two hot paths built a copy of their input and threw it away. packument_size_estimate serialised every signature block to a String purely to read its length. The obvious spelling is the same one serde_json uses internally, so a counting io::Write gives a byte-for-byte identical count with no 64 MiB transient String behind it. The arithmetic is untouched and the exact-value test still pins it. tests/support/tarball.rs staged every fixture tar in a Vec, handed the whole thing to the encoder, and squeezed it at level 6. The bomb fixture is 200 MiB of zeroes and the entry-count fixture is 100_001 headers; in an opt-level 0 build that compression was most of the test. Write the tar straight into the encoder and compress at level 1. The only ratio any test asserts is that the bomb still arrives under 1 MiB. Measured on the dev box, tests/scenarios.rs: 24.26s -> 16.11s wall, 334 MB -> 30 MB peak RSS. gzip_bomb alone: 5.46s/209MB -> 1.50s/19MB. Commit made by claude-sonnet-4-6 in opencode on behalf of Kriday.
the_packument_memo_is_bounded_and_the_estimate_is_not_a_fig_leaf built 64
versions carrying two 2 MiB signature blocks each, 256 MiB of payload,
twice-estimated and once walked. 768 KiB blocks put it at 96 MiB, still
1.5x the 64 MiB ceiling the test exists to prove refuses.
The 4x margin was not what pinned the ceiling, and I checked before
cutting it. the_packument_memo_ceilings_are_the_documented_sizes pins
both constants as values, so a mutant that changes 64 * 1024 * 1024 dies
there whatever this fixture weighs. the_per_document_ceiling_is_strict
pins the one-byte comparison by handing the ceilings in and using a
1057-byte document -- its own comment says the real ceiling "cannot
express this without a 64 MiB fixture", which is why that helper takes
them. the_whole_memo_ceiling_is_strict_and_adds_rather_than_multiplies
covers sum-versus-product on the total. And the_packument_estimate_is_exact
still pins the arithmetic, against to_string, so the counting writer
keeps its independent oracle.
Every assertion is still here and still means something. The floor moved
from a loose "> 200 MiB" to >= SIGNATURE_FIXTURE_BYTES, which is tighter,
not looser: an estimate that dropped the signature term would land near
64 KB and fail either way.
Paired A/B on a quiet box, alternating, three rounds:
OLD 256 MiB 11.85 / 11.88 / 12.02 s 277 MB peak RSS
NEW 96 MiB 4.52 / 4.46 / 4.45 s 112 MB peak RSS
Commit made by claude-sonnet-4-6 in opencode on behalf of Kriday.
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.
Cuts the developer gate's memory and disk cost, and about a third of its wall clock. Two commits, both test-side or measurement-side; no production behaviour changes.
What it changes
1. Fixture tarballs stop staging a full copy of themselves.
tests/support/tarball.rsbuilt every fixture tar in aVec, handed the whole thing to the gzip encoder, and compressed at level 6. The bomb fixture is 200 MiB of zeroes and the entry-count fixture is 100,001 headers, so in anopt-level = 0build the staging and the level-6 deflate were most of the test. It now streams straight into the encoder atCompression::fast(). Nothing downstream can tell: the only compression ratio any test asserts is that the bomb still arrives under 1 MiB, which holds at every level.2. The packument size estimate stops building a
Stringto measure it.packument_size_estimatecalledserde_json::to_string(sig)on every signature block purely to read.len(). It now passes a countingio::Writesink toserde_json::to_writer: sameCompactFormatter, same byte stream, same count, no transient string.3. The 256 MiB memo fixture is now 96 MiB. Same 64 versions, signature blocks of 768 KiB instead of 2 MiB. Still 1.5x the 64 MiB per-document ceiling that the test exists to prove refuses.
Numbers
All on the dev box (Fedora, rustc 1.98.1, 4 cores, load ~1.0). "Paired" means both sides measured back to back on the same box, alternating, so drift hits both.
Warm gate, same box, back to back
scripts/verify.shperf/overlap-and-window(before this branch)1.81x on the warm gate.
The memo fixture alone, paired A/B, three rounds:
Scenario-suite memory, paired A/B, three rounds
Peak RSS 326 MB -> 30 MB, in all three rounds. Wall clock here is inside the noise on a loaded box and no ratio is claimed for it.
Disk
No code needed for this one. The growth was stale artifacts: 237 incremental session dirs and three copies each of the four largest test binaries, from branch switches.
11.19 GB -> 2.91 GB, 3.8x, and dependencies are untouched.
Honest note on the target
The brief asked for 2-3x. On disk it is 3.8x. On gate wall clock it is 1.81x warm, which misses. Two things did not deliver:
to_stringcall as materialising "~256 MiB of transientString". It never held more than about 4 MiB, because it serialised one version at a time and dropped it. The counting writer is still the right code, but it was worth ~7 MB of RSS and a few percent of wall, not half the test. The real cost was the 256 MiB fixture plus its escaping atopt-level = 0, which is what commit 3 attacks.deps. Same one command clears both.Two known costs remain, both measured and both left alone:
src/registry/npm.rseach burn a fixed 600 ms accept window, plus a 10 s idle poll ina_packument_is_fetched_once_per_package: ~6.8 s of serial sleep, about 1.7 s of lib wall after threading. The fix is a server stopped by the test rather than by a clock. It is mechanical, touches 9 tests with per-test request-count expectations, and wants to be its own commit.touch src/diff.rs && cargo build --lockedis 8.05 s, same as before this branch.What still guards the packument memo ceilings
The 256 MiB was four times the 64 MiB ceiling. Cutting it to 1.5x is safe because the ceiling was never pinned by this fixture's size, and that was checked rather than assumed:
the_packument_memo_ceilings_are_the_documented_sizespins both constants as values (64 * 1024 * 1024,67_108_864,256 * 1024 * 1024,268_435_456), so a mutant that changes the constant dies there regardless of the fixture.the_per_document_ceiling_is_strictpins the one-byte comparison (>vs>=) by handing the ceilings intoinsert_withinand using a 1057-byte document. Its own comment says the real ceiling "cannot express this without a 64 MiB fixture" -- which is why that helper takes the ceilings as parameters.the_whole_memo_ceiling_is_strict_and_adds_rather_than_multipliescovers the total ceiling, including sum-versus-product.the_packument_estimate_is_exactstill computes its expected signature length withto_stringand compares, so the counting writer keeps an independent oracle that did not change.The fixture's remaining job is the wiring: a large many-version packument going through the production
insertwith the real constant and being refused. It still does that. What it no longer buys is a 4x margin, which only mattered against a mutant that raised the constant and the assertion pinning it in the same build.Every assertion is preserved. The floor moved from a loose
> 200 MiBto>= SIGNATURE_FIXTURE_BYTES, which is tighter rather than looser: an estimate that dropped the signature term would land near 64 KB and fail either way.Checks
./scripts/verify.shgreen on this branch:PASS Format, Clippy, Tests, References, 839 lib tests and 22 scenario tests, 0 failures. Rebased ontomainatafd724c; both commits apply cleanly on their own without the rest ofperf/overlap-and-window. NoCargo.lockchange, no new dependency, nounsafe.The red "Supply-chain audit" check is not from this diff
It fails on
rustls 0.23.45, pinned inCargo.lock:All four are dated 2026-10-14 and are patched in
rustls >= 0.23.46.This diff changes no dependency:
git diff main..HEAD --name-onlyissrc/registry/npm.rsandtests/support/tarball.rsonly, andCargo.lockisbyte-identical to main's. The audit job reads only that lockfile. main's last
three CI runs are green because they finished before the advisory database
updated (
last-updated 2026-10-14T15:17:45+02:00); a run of main started nowwould fail the same way.
The fix is a lockfile bump to
rustls 0.23.46, which is a dependency change andso needs its own decision and its own PR — deliberately not smuggled in here.