Skip to content

perf(install): overlap cold-install lockfile write with the link tail - #961

Merged
jdx merged 2 commits into
jdx:mainfrom
jdalton:aube-lockwrite-overlap
Jun 26, 2026
Merged

perf(install): overlap cold-install lockfile write with the link tail#961
jdx merged 2 commits into
jdx:mainfrom
jdalton:aube-lockwrite-overlap

Conversation

@jdalton

@jdalton jdalton commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Measured

Overlapping the cold-install lockfile write with the link tail recovers the full serialize+write span minus a graph clone. Measured with a criterion bench (pnpm_lock_write) on real pnpm-lock.yaml files, release profile, on macOS/arm64:

lockfile packages write_full (recovered) graph_clone (offset) net win
rolldown 1504 11.01 ms ± 0.56 0.64 ms ± 0.03 ~10.4 ms
many-deps (@teambit/bit) 4199 55.82 ms ± 1.73 4.71 ms ± 1.96 ~51 ms

write_full is the serialize + pnpm-parity reformat + atomic fs write — exactly the work that moves off the critical path. graph_clone is the offsetting cost the spawned task pays. The write is ~12-18x the clone, so the net is the recovered write time minus one clone, well outside noise.

Mechanism

On the fresh-resolve cold install the lockfile write ran as a serial blocking span before filter_graph + run_link_phase, with the linker idle. This moves it onto a tokio::task::spawn_blocking task that runs concurrently with filter_graph, the progress reconcile, and the link phase, joining before run_finalize_phase re-reads the graph.

The task operates on a clone of the prepared graph, taken after the write-prep mutations (refresh_lockfile_pin, stamp_pnpm_config_checksums, prepare_resolved_graph_for_lockfile_write) and before filter_graph mutates the original in place — so it serializes the exact same state the inline write did.

Killswitch

On by default. AUBE_DISABLE_LOCKFILE_WRITE_OVERLAP reverts to the inline serial write — byte-identical output, same error point, and no graph clone (exactly the pre-overlap cost). Matches the existing AUBE_DISABLE_* overlap-opt convention (DISABLE_CRITICAL_PATH, DISABLE_TARBALL_STREAM, …) and reads through embedder_env, so a host with no env_prefix exposes no branded toggle.

Error ordering

The rare catch-up integrity-rewrite (when a platform-mismatched survivor needs a computed-integrity refresh) overwrites the same lockfile. It joins the in-flight write first, so the two never race the same atomic-write rename and the on-disk result is the rewrite — preserving the old serial "write, then catch-up rewrite" order. The post-link join surfaces a write error (including a task panic, wrapped distinctly) rather than dropping it.

Tests

  • install.bats: a byte-identical cold-install test that drives a fresh resolve with the overlap on (default) and off (AUBE_DISABLE_LOCKFILE_WRITE_OVERLAP=1) and diffs the resulting aube-lock.yaml — they must be byte-for-byte identical (the overlap changes when the write runs, never what).
  • pnpm_lock_write criterion bench measuring write_full vs graph_clone (feature-gated behind bench).

cargo fmt --check, cargo clippy --all-targets --all-features -- -D warnings, the aube-lockfile unit tests, the hermetic e2e.rs, and the install / lockfile / workspace / resolve bats files all pass.

Summary by CodeRabbit

  • New Features
    • Cold installs can now write lockfiles in parallel with other install phases, reducing overall latency.
    • Added a benchmark to measure lockfile write performance.
  • Bug Fixes
    • Ensures any overlapped lockfile write is properly completed before integrity rewrite and finalization, preventing update races.
    • Allows write overlap to be disabled via DISABLE_LOCKFILE_WRITE_OVERLAP.
  • Tests
    • Added coverage verifying lockfile output is byte-identical whether write overlap is enabled or disabled.

On a fresh-resolve cold install the lockfile serialize + pnpm-parity
reformat + atomic write ran as a serial blocking span before
filter_graph and the link phase. On a large tree that costs 11-55 ms
(measured: 11.0 ms +/- 0.56 at 1.5k packages, 55.8 ms +/- 1.73 at 4.2k)
with the linker idle.

Move that work onto a spawn_blocking task that runs concurrently with
filter_graph, the progress reconcile, and run_link_phase, joining before
run_finalize_phase re-reads the graph. The task operates on a clone of
the prepared graph taken after the write-prep mutations and before
filter_graph mutates the original, so it serializes the exact same state
the inline write did. A full graph clone measures 0.6-3 ms (12-18x less
than the write it hides), so the net win is the recovered write time
minus one clone: ~10 ms at 1.5k packages, ~51 ms at 4.2k.

On by default; AUBE_DISABLE_LOCKFILE_WRITE_OVERLAP reverts to the inline
serial write (byte-identical output, same error point, no graph clone),
matching aube's existing AUBE_DISABLE_* overlap-opt convention. The rare
catch-up integrity-rewrite joins the in-flight write first so the two
never race the same atomic-write rename and the on-disk result is the
rewrite, preserving the old serial ordering. The join surfaces a write
error (including a task panic) rather than dropping it.

Adds a byte-identical cold-install test (install.bats) asserting the
overlapped and serial paths produce identical lockfile bytes, and a
pnpm_lock_write criterion bench measuring write_full vs graph_clone.
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 1f530a40-9aa7-402b-9751-4e3ca93b1e4a

📥 Commits

Reviewing files that changed from the base of the PR and between 585a271 and 0a6bd8c.

📒 Files selected for processing (2)
  • crates/aube/src/commands/install/lockfile_write_overlap.rs
  • crates/aube/src/commands/install/mod.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/aube/src/commands/install/mod.rs

📝 Walkthrough

Walkthrough

The PR adds an optional overlapped lockfile write path during install, with an environment-variable killswitch and joins before integrity rewrite and finalize. It also adds a pnpm lockfile write benchmark and a regression test comparing overlap enabled and disabled outputs.

Changes

Install lockfile write overlap

Layer / File(s) Summary
Overlap contracts and gate
crates/aube/src/commands/install/lockfile_write_overlap.rs
Adds the module docs, owned input bundle, task handle alias, and env-var switch for overlapped lockfile writing.
Shared write routine
crates/aube/src/commands/install/lockfile_write_overlap.rs
Adds the shared write routine plus spawned and inline execution paths, and wraps task panics in join diagnostics.
Install orchestration
crates/aube/src/commands/install/mod.rs, test/install.bats
Wires the overlap helper into install, switches between spawned and inline writes, joins the handle before integrity rewrite and finalize, and adds a byte-identical overlap regression test.

Pnpm lockfile write benchmark

Layer / File(s) Summary
Benchmark target and helper
crates/aube-lockfile/Cargo.toml, crates/aube-lockfile/src/pnpm/mod.rs
Adds the bench target and a bench-only write entrypoint that forwards to write::write(...).
Criterion benchmark
crates/aube-lockfile/benches/pnpm_lock_write.rs
Adds a Criterion benchmark that reads AUBE_BENCH_LOCKFILE, parses the graph, prints package and importer counts, and measures full write versus graph.clone().

Sequence Diagram(s)

sequenceDiagram
  participant InstallMod
  participant lockfile_write_overlap
  participant spawn_blocking
  participant write_one
  participant run_finalize_phase

  InstallMod->>lockfile_write_overlap: overlap_enabled()
  alt overlap enabled
    InstallMod->>lockfile_write_overlap: spawn(LockfileWriteInputs)
    lockfile_write_overlap->>spawn_blocking: run captured write_one
    spawn_blocking->>write_one: write lockfile
  else overlap disabled
    InstallMod->>lockfile_write_overlap: write_one(...)
  end
  InstallMod->>lockfile_write_overlap: join(handle) before integrity rewrite
  InstallMod->>lockfile_write_overlap: join(handle) before run_finalize_phase
  InstallMod->>run_finalize_phase: finalize install
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • jdx/aube#883: Touches the same install lockfile-writing flow in crates/aube/src/commands/install/mod.rs.
  • jdx/aube#927: Also changes the install lockfile-writing orchestration in crates/aube/src/commands/install/mod.rs.

Poem

I thumped the path from root to leaf,
Wrote while I nibbled on clover reef.
One hop overlapped the moonlit link,
One hop stood by to make me think.
Byte-for-byte, the carrots blink. 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: overlapping cold-install lockfile writing with the link phase.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Moves the cold-install lockfile serialize+write off the critical path onto a tokio::task::spawn_blocking task that overlaps with filter_graph and the link phase, joining before run_finalize_phase. A killswitch (AUBE_DISABLE_LOCKFILE_WRITE_OVERLAP) restores inline serial behavior with byte-identical output, verified by a new bats diff test.

  • The catch-up integrity-rewrite race is explicitly handled by joining the in-flight write handle before overwriting, preserving the original serial ordering (write, then catch-up rewrite) and preventing two concurrent atomic-rename operations to the same path.
  • write_one is shared between the overlapped closure (via owned LockfileWriteInputs) and the killswitch inline path, guaranteeing byte-identical output from a single code path.
  • The join helper maps a task panic to a distinct miette::Report via wrap_err, ensuring write errors surface rather than being silently dropped on the success path.

Confidence Score: 5/5

Safe to merge; the race between the overlapped write and the catch-up integrity rewrite is correctly serialized, and write errors are surfaced before finalize on all non-error install paths.

The overlap logic is contained in a dedicated module, the two join points cover the critical ordering constraints, and the killswitch + byte-identity bats test together give high confidence the optimization changes only timing, not output.

No files require special attention.

Important Files Changed

Filename Overview
crates/aube/src/commands/install/lockfile_write_overlap.rs New module encapsulating the overlapped lockfile write; cleanly separates LockfileWriteInputs struct, spawn, and join into distinct public(super) items with well-scoped ownership and proper panic-to-diagnostic bridging.
crates/aube/src/commands/install/mod.rs Adds lockfile_write_handle option-carrying the JoinHandle; joins it in two places (catch-up integrity rewrite early-join and pre-finalize join), covering the important race and the normal success path correctly.
crates/aube-lockfile/src/pnpm/mod.rs Adds bench-only __bench_write_to behind #[cfg(feature = "bench")]; appropriate use of expect() in dev tooling path, correctly hidden from normal API surface.
crates/aube-lockfile/benches/pnpm_lock_write.rs New criterion bench measuring both write_full and graph_clone to validate the net-win claim; correctly uses black_box to prevent dead-code elimination.
crates/aube-lockfile/Cargo.toml Minimal addition of the [[bench]] entry for pnpm_lock_write with required-features = ["bench"], matching the pattern of the existing pnpm_lock_parse bench.
test/install.bats Adds a cold-install byte-identity BATS test; runs two fresh installs (overlap on/off) and diffs the resulting lockfiles; correctly removes node_modules and aube-lock.yaml between runs for a genuine cold install each time.

Reviews (2): Last reviewed commit: "refactor(install): inline single-use wri..." | Re-trigger Greptile

Comment thread crates/aube/src/commands/install/lockfile_write_overlap.rs Outdated
Comment thread crates/aube/src/commands/install/lockfile_write_overlap.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/aube/src/commands/install/mod.rs (1)

2049-2058: 🩺 Stability & Availability | 🔵 Trivial

Log ordering is non-deterministic under concurrency; silent write errors remain a risk

The search confirmed no strict ordering assertions for "Wrote" logs in test/resolve.bats or other .bats files, implying the concurrent emission of debug logs during the link phase does not break existing tests.

However, the behavioral difference regarding error handling persists. If an error occurs between the spawn_blocking call and the subsequent join (e.g., during fetch_packages_with_root or run_link_phase), the lockfile_write_handle is dropped without joining. This results in the blocking task's error being silently swallowed, whereas the inline path would surface it. This breaks strict error-ordering parity.

To ensure deterministic error reporting:

  • Explicitly join the handle and propagate its error on all early-return paths before the join point.
  • Alternatively, wrap the blocking task to propagate failures via a shared channel or Result field if the task must continue independently.

Without this fix, the specific error logged during a failure may be indeterminate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aube/src/commands/install/mod.rs` around lines 2049 - 2058, The
lockfile write path in install/mod.rs drops the in-flight
`lockfile_write_handle` on early returns, so errors from the `spawn_blocking`
write can be lost. Update the
`lockfile_write_handle`/`lockfile_write_overlap::join` flow so every exit path
after spawning the write explicitly joins the handle and propagates any failure
before returning, not only the happy path. Use the existing
`lockfile_write_handle` variable and the join helper in the same install/link
phase logic to keep error reporting consistent with the inline write behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/aube/src/commands/install/mod.rs`:
- Around line 2049-2058: The lockfile write path in install/mod.rs drops the
in-flight `lockfile_write_handle` on early returns, so errors from the
`spawn_blocking` write can be lost. Update the
`lockfile_write_handle`/`lockfile_write_overlap::join` flow so every exit path
after spawning the write explicitly joins the handle and propagates any failure
before returning, not only the happy path. Use the existing
`lockfile_write_handle` variable and the join helper in the same install/link
phase logic to keep error reporting consistent with the inline write behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 3bc088ed-1415-4cf4-82e8-9afab365bd65

📥 Commits

Reviewing files that changed from the base of the PR and between 2bd40f9 and 585a271.

📒 Files selected for processing (6)
  • crates/aube-lockfile/Cargo.toml
  • crates/aube-lockfile/benches/pnpm_lock_write.rs
  • crates/aube-lockfile/src/pnpm/mod.rs
  • crates/aube/src/commands/install/lockfile_write_overlap.rs
  • crates/aube/src/commands/install/mod.rs
  • test/install.bats

…or conversion

Inline the single-use `write_inline` pass-through into its sole caller by
making `write_one` `pub(super)` and calling it directly from the
killswitch-disabled inline path in mod.rs.

Drop the `Err::<(), _>(join_err).into_diagnostic().unwrap_err()` dance in
`join()` for `Result::<(), _>::Err(join_err).into_diagnostic().wrap_err(..)`,
which removes the `unwrap_err()` while keeping the required `into_diagnostic`
bridge (`JoinError` is a plain `std::error::Error`, not a miette `Diagnostic`).

Behavior is unchanged: the killswitch path stays byte-identical to the overlap
path (install.bats byte-identity test green), and the join-error `Report` chain
and panic-context message are preserved.
@jdx
jdx merged commit 1c2520f into jdx:main Jun 26, 2026
17 checks passed
@cursor cursor Bot mentioned this pull request Jun 26, 2026
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.

2 participants