turbo-persistence: add borrowed mmap byte slices - #97888
Conversation
Stats from current PR🔴 2 regressions, 2 improvements
📊 All Metrics📖 Metrics GlossaryDev Server Metrics:
Build Metrics:
Change Thresholds:
⚡ Dev Server
📦 Dev Server (Webpack) (Legacy)📦 Dev Server (Webpack)
⚡ Production Builds
📦 Production Builds (Webpack) (Legacy)📦 Production Builds (Webpack)
📦 Bundle SizesBundle Sizes⚡ TurbopackClient Main Bundles
Server Middleware
Build DetailsBuild Manifests
Build Cache
📦 WebpackClient Main Bundles
Polyfills
Pages
Server Edge SSR
Middleware
Build DetailsBuild Manifests
Build Cache
🔄 Shared (bundler-independent)Runtimes
📝 Changed Files (33 files)Files with changes:
View diffsapp-page-exp..ntime.dev.jsfailed to diffapp-page-exp..time.prod.jsfailed to diffapp-page-tur..ntime.dev.jsfailed to diffapp-page-tur..time.prod.jsfailed to diffapp-page-tur..ntime.dev.jsfailed to diffapp-page-tur..time.prod.jsfailed to diffapp-page.runtime.dev.jsfailed to diffapp-page.runtime.prod.jsfailed to diffapp-route-ex..ntime.dev.jsDiff too large to display app-route-ex..time.prod.jsDiff too large to display app-route-tu..ntime.dev.jsDiff too large to display app-route-tu..time.prod.jsDiff too large to display app-route-tu..ntime.dev.jsDiff too large to display app-route-tu..time.prod.jsDiff too large to display app-route.runtime.dev.jsDiff too large to display app-route.ru..time.prod.jsDiff too large to display dev-validati..ntime.dev.jsfailed to diffdev-validati..ntime.dev.jsfailed to diffdev-validati..ntime.dev.jsfailed to diffdev-validati..ntime.dev.jsfailed to diffpages-api-tu..ntime.dev.jsDiff too large to display pages-api-tu..time.prod.jsDiff too large to display pages-api.runtime.dev.jsDiff too large to display pages-api.ru..time.prod.jsDiff too large to display pages-turbo...ntime.dev.jsDiff too large to display pages-turbo...time.prod.jsDiff too large to display pages.runtime.dev.jsDiff too large to display pages.runtime.prod.jsDiff too large to display server.runtime.prod.jsDiff too large to display use-cache-pr..ntime.dev.jsDiff too large to display use-cache-pr..ntime.dev.jsDiff too large to display use-cache-pr..ntime.dev.jsDiff too large to display use-cache-pr..ntime.dev.jsDiff too large to display 📎 Tarball URLCommit: d3cc343 |
Failing test suitesCommit: d3cc343 | About building and testing Next.js
Expand output● Error overlay - RSC build errors › Skipped in webpack › should handle successive HMR changes with errors correctly |
### What? Stabilize `NextStartInstance.build()` CLI output capture so failed production builds return all trailing stdout/stderr diagnostics. The existing `sync-io-blocks-root` behavioral assertions remain unchanged, including the route-specific `Date.now()` diagnostic, timeout/retry guard, and exit-code check. ### Why? The `--debug-prerender` cases intermittently lost the detailed `Date.now()` diagnostic from `result.cliOutput` in CI even though builds exited normally. Across the reported CI run and two retries, the missing route set varied from 4 to 2 to 3 routes, consistent with an output-drain race rather than a rendering or resource failure. On latest canary with Node 20, `NEXT_TEST_MODE=start`, and `IS_WEBPACK_TEST=1`, 5 baseline campaigns completed 24 builds (20 debug-prerender) without reproducing the intermittent failure locally. A controlled Node 20 reproduction established the lifecycle race directly: the child `exit` event observed no trailing output, while `close` observed the trailing diagnostic. ### How? Wait for the child process `close` event before snapshotting `cliOutput`. Unlike `exit`, `close` is emitted after the piped stdout and stderr streams close, so diagnostics emitted near process shutdown are fully drained before the build result is returned. This is intentionally limited to the affected start-mode build harness and is independent of the mmap persistence PR stack (#97873, #97888, #97889). ### Verification - Baseline on Node 20.20.2 / start mode / Webpack: 5 campaigns, 24 builds total, 20 debug-prerender; 0 failures and no affected local routes - Deterministic child-process lifecycle reproduction: `exit` captured empty output; `close` captured the trailing diagnostic - Post-fix focused test: 5/5 runs passed, covering 20/20 debug-prerender cases - Post-fix complete test: 3/3 runs passed, covering 24/24 cases (12 debug-prerender and 12 normal production) - `pnpm build-all` - Prettier and ESLint for `test/lib/next-modes/next-start.ts` - `pnpm types` <!-- NEXT_JS_LLM --> <!-- fleet a8a423ef-2679-4cb0-ba51-92592630165e --> Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com> Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
What?
Make
ArcByteslifetime-aware and add a borrowedMmapRefbacking that can be promoted to owned storage when a value escapes.This is 2/3 in a dependent PR series.
Why?
The no-mmap layer represents raw reads as either borrowed mmap bytes or owned file bytes. A lifetime-aware
ArcBytesmakes that borrowed view a first-class type, so code can carry the same byte abstraction across a local boundary and clone the mmap handle only when ownership is actually required.This is intentionally a narrow type/ownership refactor; it does not add file-mode behavior and does not change compaction's
RcBytesstrategy.How?
Backing::MmapRef,from_mmap_ref, andinto_static.Cowboundary with borrowedArcBytesand promote on escape.RcBytes/SharedBytesunchanged.Verification
cargo fmt --all -- --checkcargo check -p turbo-persistence --all-targets --all-featurescargo check -p turbo-tasks-backendcargo check -p turbo-persistence --benchescargo test -p turbo-persistence --all-features— 105 passed