Skip to content

[turbopack] Reduce persistence buffer lifetimes#92413

Closed
lukesandberg wants to merge 2 commits intographite-base/92413from
04-06-streaming_reads
Closed

[turbopack] Reduce persistence buffer lifetimes#92413
lukesandberg wants to merge 2 commits intographite-base/92413from
04-06-streaming_reads

Conversation

@lukesandberg
Copy link
Copy Markdown
Contributor

@lukesandberg lukesandberg commented Apr 6, 2026

What?

Refactor the task restore path to decode persisted bytes directly into the live in-memory TaskStorage, rather than first decoding into a scratch TaskStorage and then copying the fields across.

Also introduces batch_get_with — a streaming callback-based batch lookup that resolves and delivers each value immediately rather than accumulating all decoded values simultaneously.

Why?

The old path allocated a scratch TaskStorage per task, decoded into it, then called restore_from to copy persisted fields into the live task. For large batches (up to 50K tasks) this meant holding every decoded value in memory at once.

The new path:

  • Decodes directly into the live task, eliminating the scratch TaskStorage allocation per task
  • Drops each decoded block before moving to the next, so peak memory is O(1) value blocks instead of O(n)
  • Removes the generated restore_from / restore_meta_from / restore_data_from family of methods from the TaskStorage macro, which were the only consumers of this pattern

Also switches batch_get from returning Vec<Option<ArcBytes>> to a streaming batch_get_with(callback) interface, and replaces the ValueBuffer<'l> associated type on KeyValueDatabase with a concrete ArcBytes return type.

How?

  • turbo-persistence: add batch_get_with on TurboPersistence and KeyValueDatabase; batch_lookup_with on MetaFile now takes a FoundBitset and fires a callback per resolved entry rather than storing LookupValue in the cells vec
  • BackingStorage: lookup_data returns Option<ArcBytes> (raw bytes); batch_lookup_data takes a &mut dyn FnMut(usize, Option<&[u8]>) callback
  • kv_backing_storage: decode removed from the lookup path; callers decode directly using new_turbo_bincode_decoder
  • operation/mod.rs: new restore_batch helper handles single and batch cases uniformly; process_task closure decodes into live storage and fires prepared_task_callback inline without a second pass
  • task_storage_macro.rs: remove restore_from and related generated methods

Copy link
Copy Markdown
Contributor Author

lukesandberg commented Apr 6, 2026

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Apr 6, 2026

Merging this PR will not alter performance

✅ 17 untouched benchmarks
⏩ 3 skipped benchmarks1


Comparing 04-06-streaming_reads (806bd09) with canary (18430c7)2

Open in CodSpeed

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on 04-06-add_family_name_to_many_spans (ed0b4ac) during the generation of this report, so canary (18430c7) was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@lukesandberg lukesandberg changed the base branch from tracing_improvements to graphite-base/92413 April 6, 2026 17:57
@lukesandberg lukesandberg force-pushed the graphite-base/92413 branch from f6297db to 9c3aaf1 Compare April 6, 2026 17:57
@lukesandberg lukesandberg force-pushed the 04-06-streaming_reads branch from 2bc6c08 to 76294c3 Compare April 6, 2026 17:57
@lukesandberg lukesandberg changed the base branch from graphite-base/92413 to 04-06-add_family_name_to_many_spans April 6, 2026 17:58
@nextjs-bot
Copy link
Copy Markdown
Collaborator

nextjs-bot commented Apr 6, 2026

Stats from current PR

✅ No significant changes detected

📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 455ms 455ms ▁█▅▅▅
Cold (Ready in log) 438ms 439ms ▁▂▅▇▄
Cold (First Request) 1.099s 1.102s ▆▁▁▂▂
Warm (Listen) 456ms 456ms █▁██▁
Warm (Ready in log) 443ms 442ms ▂▂▇█▁
Warm (First Request) 345ms 343ms ▃▄▇█▄
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 455ms 455ms ▁▁▅▁▅
Cold (Ready in log) 434ms 434ms ▁▃▆▂▂
Cold (First Request) 1.955s 1.942s ▇▇▇▆▁
Warm (Listen) 456ms 456ms ▁▁▁▁▁
Warm (Ready in log) 433ms 433ms ▁▂▅▁▂
Warm (First Request) 1.927s 1.922s ▆▇█▆▁

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 3.886s 3.883s ▇▆██▁
Cached Build 3.891s 3.949s ▄███▄
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 14.335s 14.315s ▁▂▅▂▂
Cached Build 14.471s 14.447s ▁▂▇▃▄
node_modules Size 488 MB 488 MB █████
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
02fkg8wfh0iju.js gzip 9.19 kB N/A -
050zwt5xh_0tx.js gzip 10.4 kB N/A -
0803-3r6mifdx.js gzip 157 B N/A -
087fzjd-gvlzv.js gzip 450 B N/A -
0cz1d0mv5g_q7.js gzip 39.4 kB 39.4 kB
0d0pcwea0l749.js gzip 151 B N/A -
0d34flh8j9r6u.js gzip 156 B N/A -
0p0khj57rq_v_.js gzip 162 B N/A -
0ppxcl_z43mad.js gzip 8.52 kB N/A -
13mnpc17btogu.js gzip 157 B N/A -
19oha6-znmkcv.js gzip 8.55 kB N/A -
1elt1qium-r2m.css gzip 115 B 115 B
1ppe_gkx_dsny.js gzip 159 B N/A -
2_5rjb7lqxntf.js gzip 221 B 221 B
219prxwxgaalc.js gzip 7.61 kB N/A -
26elcgxnn9zjd.js gzip 8.52 kB N/A -
28s7tbll9vbjr.js gzip 156 B N/A -
2900hudr6gvm0.js gzip 2.28 kB N/A -
2bbl2qamyvimj.js gzip 65.7 kB N/A -
2lv2js3kmdeho.js gzip 8.48 kB N/A -
2rehygrd36hqv.js gzip 8.58 kB N/A -
2scbv16he964r.js gzip 158 B N/A -
2srwswih0m9_h.js gzip 13.3 kB N/A -
3-jz00s4w-r6h.js gzip 13 kB N/A -
3-p9p9mheqhzx.js gzip 8.55 kB N/A -
31030bryqpolg.js gzip 8.53 kB N/A -
31dx5nmrzzuy7.js gzip 225 B N/A -
37r23u64aoktk.js gzip 155 B N/A -
3925v09gtu-5k.js gzip 49 kB N/A -
39x4zj5mjb4d_.js gzip 9.77 kB N/A -
3at2ovgizp8r6.js gzip 158 B N/A -
3bknr2e7m9s7z.js gzip 155 B N/A -
3k-48b78ys_vy.js gzip 10.1 kB N/A -
3m7-5rfj0avoz.js gzip 12.9 kB N/A -
3t39n05ky9z08.js gzip 70.8 kB N/A -
3uqce_6sa526g.js gzip 8.47 kB N/A -
3yurjqk-sjs3y.js gzip 1.46 kB N/A -
3znov3m90-kab.js gzip 168 B N/A -
40ybjx9c192n0.js gzip 13.8 kB N/A -
421vzwdt9j1b_.js gzip 5.62 kB N/A -
44jj5q-kk1jan.js gzip 157 B N/A -
turbopack-03..e7c0.js gzip 4.18 kB N/A -
turbopack-0k..9h2a.js gzip 4.18 kB N/A -
turbopack-0m..6r79.js gzip 4.18 kB N/A -
turbopack-0v..v8st.js gzip 4.18 kB N/A -
turbopack-1s..tsd2.js gzip 4.16 kB N/A -
turbopack-3-..bo-6.js gzip 4.18 kB N/A -
turbopack-31..l4gh.js gzip 4.18 kB N/A -
turbopack-36..rum2.js gzip 4.18 kB N/A -
turbopack-3i..3636.js gzip 4.18 kB N/A -
turbopack-3v..wfxq.js gzip 4.18 kB N/A -
turbopack-3v..1qwv.js gzip 4.19 kB N/A -
turbopack-3z..kcbv.js gzip 4.18 kB N/A -
turbopack-40..j2ay.js gzip 4.18 kB N/A -
turbopack-42..qz47.js gzip 4.17 kB N/A -
03dgzoo-qf3sm.js gzip N/A 9.19 kB -
03i0taczqebbx.js gzip N/A 70.8 kB -
05tx5f25dlivn.js gzip N/A 8.53 kB -
0c7ez6p2qc57f.js gzip N/A 5.62 kB -
0duvj3qk5pvgn.js gzip N/A 13.8 kB -
0ifxao1ktkgwg.js gzip N/A 156 B -
0m-34rm9w_wpm.js gzip N/A 7.6 kB -
0qnwuk92m8i7o.js gzip N/A 10.4 kB -
0r4wrn6n0ue2m.js gzip N/A 8.55 kB -
0rp0fodtbt_6m.js gzip N/A 8.52 kB -
0sfck-km4dl1k.js gzip N/A 8.47 kB -
0x0xuhmxzwkp8.js gzip N/A 8.47 kB -
1-wdvgxnzicj7.js gzip N/A 1.46 kB -
11u6nxujb2eg4.js gzip N/A 450 B -
19uunh8umr1a1.js gzip N/A 157 B -
1el9fuakpgh8m.js gzip N/A 155 B -
1jv-o1_s-zmua.js gzip N/A 49 kB -
1mifo-hcc4vf6.js gzip N/A 154 B -
1o5x2xlfw7x62.js gzip N/A 156 B -
1sk7rrnby7fjt.js gzip N/A 157 B -
2-j7jrt35v955.js gzip N/A 160 B -
27kwgyklbqvcl.js gzip N/A 152 B -
2e2z-03lx4fjc.js gzip N/A 13 kB -
2irxuxkr23i0g.js gzip N/A 160 B -
2k9ax08cjl2id.js gzip N/A 12.9 kB -
2lms6k76q5-6m.js gzip N/A 13.3 kB -
2qx4twi9i3xus.js gzip N/A 2.28 kB -
2srnqic6tvxxd.js gzip N/A 8.52 kB -
2zkc9u4375pyw.js gzip N/A 157 B -
30l7m4nayp73a.js gzip N/A 8.55 kB -
34v1uamxoz09s.js gzip N/A 170 B -
34wde90lr4zme.js gzip N/A 157 B -
3h_ecpiaatwgc.js gzip N/A 10.1 kB -
3hxw-cpxtvy_3.js gzip N/A 156 B -
3ity0aahajapd.js gzip N/A 225 B -
3wrhpuc-j1aw9.js gzip N/A 9.77 kB -
3xlti3rufjlyg.js gzip N/A 65.7 kB -
43mlw9dy_8f02.js gzip N/A 8.58 kB -
turbopack-02..6_tq.js gzip N/A 4.18 kB -
turbopack-0h..r50b.js gzip N/A 4.18 kB -
turbopack-17..z-3u.js gzip N/A 4.19 kB -
turbopack-18..evlj.js gzip N/A 4.17 kB -
turbopack-1c..a07c.js gzip N/A 4.18 kB -
turbopack-1h..a606.js gzip N/A 4.18 kB -
turbopack-1o.._bpf.js gzip N/A 4.18 kB -
turbopack-1w..e9r6.js gzip N/A 4.18 kB -
turbopack-22..wdmr.js gzip N/A 4.18 kB -
turbopack-2c..zde7.js gzip N/A 4.18 kB -
turbopack-31..4lzd.js gzip N/A 4.18 kB -
turbopack-3g..9wtz.js gzip N/A 4.18 kB -
turbopack-3l..q89n.js gzip N/A 4.18 kB -
turbopack-40..aa11.js gzip N/A 4.16 kB -
Total 464 kB 464 kB ✅ -22 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 722 B 714 B 🟢 8 B (-1%)
Total 722 B 714 B ✅ -8 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 434 B 435 B
Total 434 B 435 B ⚠️ +1 B

📦 Webpack

Client

Main Bundles
Canary PR Change
5528-HASH.js gzip 5.54 kB N/A -
6280-HASH.js gzip 60.7 kB N/A -
6335.HASH.js gzip 169 B N/A -
912-HASH.js gzip 4.59 kB N/A -
e8aec2e4-HASH.js gzip 62.8 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB
main-app-HASH.js gzip 255 B 254 B
main-HASH.js gzip 39.4 kB 39.3 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
262-HASH.js gzip N/A 4.59 kB -
2889.HASH.js gzip N/A 169 B -
5602-HASH.js gzip N/A 5.55 kB -
6948ada0-HASH.js gzip N/A 62.8 kB -
9544-HASH.js gzip N/A 61.4 kB -
Total 235 kB 235 kB ⚠️ +580 B
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 194 B 194 B
_error-HASH.js gzip 183 B 180 B 🟢 3 B (-2%)
css-HASH.js gzip 331 B 330 B
dynamic-HASH.js gzip 1.81 kB 1.81 kB
edge-ssr-HASH.js gzip 256 B 256 B
head-HASH.js gzip 351 B 352 B
hooks-HASH.js gzip 384 B 383 B
image-HASH.js gzip 580 B 581 B
index-HASH.js gzip 260 B 260 B
link-HASH.js gzip 2.51 kB 2.51 kB
routerDirect..HASH.js gzip 320 B 319 B
script-HASH.js gzip 386 B 386 B
withRouter-HASH.js gzip 315 B 315 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.98 kB 7.98 kB ✅ -1 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 125 kB 126 kB
page.js gzip 273 kB 273 kB
Total 398 kB 398 kB ⚠️ +180 B
Middleware
Canary PR Change
middleware-b..fest.js gzip 617 B 615 B
middleware-r..fest.js gzip 156 B 155 B
middleware.js gzip 44.2 kB 44.3 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 45.8 kB 45.9 kB ⚠️ +59 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 715 B 718 B
Total 715 B 718 B ⚠️ +3 B
Build Cache
Canary PR Change
0.pack gzip 4.38 MB 4.37 MB 🟢 4.75 kB (0%)
index.pack gzip 113 kB 114 kB
index.pack.old gzip 114 kB 115 kB
Total 4.61 MB 4.6 MB ✅ -3.75 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 342 kB 342 kB
app-page-exp..prod.js gzip 189 kB 189 kB
app-page-tur...dev.js gzip 341 kB 341 kB
app-page-tur..prod.js gzip 189 kB 189 kB
app-page-tur...dev.js gzip 338 kB 338 kB
app-page-tur..prod.js gzip 187 kB 187 kB
app-page.run...dev.js gzip 338 kB 338 kB
app-page.run..prod.js gzip 187 kB 187 kB
app-route-ex...dev.js gzip 76.6 kB 76.6 kB
app-route-ex..prod.js gzip 52.2 kB 52.2 kB
app-route-tu...dev.js gzip 76.6 kB 76.6 kB
app-route-tu..prod.js gzip 52.2 kB 52.2 kB
app-route-tu...dev.js gzip 76.2 kB 76.2 kB
app-route-tu..prod.js gzip 52 kB 52 kB
app-route.ru...dev.js gzip 76.2 kB 76.2 kB
app-route.ru..prod.js gzip 52 kB 52 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 43.8 kB 43.8 kB
pages-api-tu..prod.js gzip 33.4 kB 33.4 kB
pages-api.ru...dev.js gzip 43.8 kB 43.8 kB
pages-api.ru..prod.js gzip 33.4 kB 33.4 kB
pages-turbo....dev.js gzip 53.2 kB 53.2 kB
pages-turbo...prod.js gzip 39 kB 39 kB
pages.runtim...dev.js gzip 53.2 kB 53.2 kB
pages.runtim..prod.js gzip 39 kB 39 kB
server.runti..prod.js gzip 62.8 kB 62.8 kB
Total 3.03 MB 3.03 MB ⚠️ +2 B
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/806bd09d8c93d34f2218ad9576e87b5db9affcbd/next

@lukesandberg lukesandberg force-pushed the 04-06-streaming_reads branch from 76294c3 to 632c22b Compare April 6, 2026 20:11
@lukesandberg lukesandberg changed the title streaming reads [turbopack] Reduce persistence buffer lifetimes Apr 6, 2026
@lukesandberg lukesandberg marked this pull request as ready for review April 6, 2026 20:23
@lukesandberg lukesandberg requested a review from sokra April 6, 2026 20:23
@lukesandberg lukesandberg force-pushed the 04-06-add_family_name_to_many_spans branch 2 times, most recently from bf5f4fe to ed0b4ac Compare April 7, 2026 16:23
deserialize directly into the TaskStorage struct in the in memory cache

this means we need to hold the shard lock while doing it, but we save a bunch of temporary memory allocations from the snapshots
@lukesandberg lukesandberg force-pushed the 04-06-streaming_reads branch from c275d99 to 806bd09 Compare April 7, 2026 16:23
@lukesandberg lukesandberg changed the base branch from 04-06-add_family_name_to_many_spans to graphite-base/92413 April 7, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

created-by: Turbopack team PRs by the Turbopack team. Turbopack Related to Turbopack with Next.js.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants