Skip to content

Set DontFork and Unmergeable on all mmap sites in turbo-persistence#90941

Merged
lukesandberg merged 3 commits intocanaryfrom
sokra/dont-fork
Mar 6, 2026
Merged

Set DontFork and Unmergeable on all mmap sites in turbo-persistence#90941
lukesandberg merged 3 commits intocanaryfrom
sokra/dont-fork

Conversation

@sokra
Copy link
Member

@sokra sokra commented Mar 5, 2026

Summary

  • Add madvise(MADV_DONTFORK) and madvise(MADV_UNMERGEABLE) to all mmap sites in turbo-persistence
  • Extract a shared advise_mmap_for_persistence helper into a dedicated mmap_helper module

Why

read_blob in db.rs already correctly sets DontFork and Unmergeable on its mmap, but three other mmap sites were missing these flags:

  • static_sorted_file.rs (open_internal) — SST file mmaps used for lookups and compaction
  • meta_file.rs (open_internal) — meta file mmaps storing AMQF filters and SST metadata
  • sst_inspect.rs (analyze_sst_file) — diagnostic tool mmap

MADV_DONTFORK prevents mmap regions from being copied into child processes on fork(), avoiding unnecessary memory duplication and potential SIGBUS issues if the parent unmaps before the child accesses the page. MADV_UNMERGEABLE opts the pages out of KSM (Kernel Same-page Merging), avoiding the overhead of scanning these pages for deduplication since they contain unique compressed data.

Both flags are Linux-only (#[cfg(target_os = "linux")]), matching the existing pattern in read_blob.

Implementation

Rather than duplicating #[cfg(target_os = "linux")] madvise calls at each mmap site, a shared helper advise_mmap_for_persistence() is extracted into src/mmap_helper.rs. The function applies both flags on Linux and is a no-op on other platforms. All four mmap sites (db.rs, static_sorted_file.rs, meta_file.rs, sst_inspect.rs) now call this single helper.

Test Plan

  • cargo check -p turbo-persistence passes
  • cargo fmt clean
  • No behavioral change on non-Linux platforms (flags are gated behind #[cfg(target_os = "linux")])

Previously only read_blob set these madvise flags. Apply them
consistently to SST file, meta file, and sst_inspect mmaps as well.
@nextjs-bot nextjs-bot added created-by: Turbopack team PRs by the Turbopack team. Turbopack Related to Turbopack with Next.js. labels Mar 5, 2026
@sokra sokra requested review from bgw and lukesandberg March 5, 2026 18:27
@codspeed-hq
Copy link

codspeed-hq bot commented Mar 5, 2026

Merging this PR will not alter performance

✅ 17 untouched benchmarks
⏩ 3 skipped benchmarks1


Comparing sokra/dont-fork (4178046) with canary (9d0fbf1)

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.

@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Mar 5, 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 456ms ▇▇▁▁▁
Cold (Ready in log) 439ms 439ms ▇▇▁▁▁
Cold (First Request) 1.268s 1.258s ▇▇▃▁▃
Warm (Listen) 456ms 456ms ▇▇▁▁▁
Warm (Ready in log) 444ms 443ms ▆▆▁▁▁
Warm (First Request) 348ms 351ms ▆▆▂▂▁
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 456ms 455ms ▁▁▁█▁
Cold (Ready in log) 436ms 436ms ▂▅▆█▁
Cold (First Request) 1.945s 1.949s ▁▄▄█▂
Warm (Listen) 457ms 456ms ▁▁▁█▁
Warm (Ready in log) 436ms 436ms ▂▄▅█▁
Warm (First Request) 1.948s 1.932s ▁▄▄█▁

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 3.937s 3.851s ▆▆▁▃▁
Cached Build 3.889s 3.853s ▆▆▁▃▁
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 14.013s 13.900s ▁▂▂█▁
Cached Build 14.087s 14.036s ▁▁▂█▁
node_modules Size 476 MB 476 MB ▁▁▁▁▁
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles: **401 kB** → **401 kB** ✅ -14 B

80 files with content-based hashes (individual files not comparable between builds)

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 767 B 764 B
Total 767 B 764 B ✅ -3 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 450 B 452 B
Total 450 B 452 B ⚠️ +2 B

📦 Webpack

Client

Main Bundles
Canary PR Change
5528-HASH.js gzip 5.54 kB N/A -
6280-HASH.js gzip 59.4 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.6 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB
main-app-HASH.js gzip 255 B 255 B
main-HASH.js gzip 39.1 kB 39.1 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.6 kB -
9544-HASH.js gzip N/A 60.2 kB -
Total 233 kB 234 kB ⚠️ +735 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 125 kB
page.js gzip 254 kB 254 kB
Total 378 kB 379 kB ⚠️ +499 B
Middleware
Canary PR Change
middleware-b..fest.js gzip 618 B 614 B
middleware-r..fest.js gzip 156 B 155 B
middleware.js gzip 43.6 kB 43.5 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 45.2 kB 45.1 kB ✅ -119 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.04 MB 4.04 MB
index.pack gzip 102 kB 103 kB
index.pack.old gzip 103 kB 102 kB
Total 4.24 MB 4.25 MB ⚠️ +2.48 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 321 kB 321 kB
app-page-exp..prod.js gzip 170 kB 170 kB
app-page-tur...dev.js gzip 321 kB 321 kB
app-page-tur..prod.js gzip 170 kB 170 kB
app-page-tur...dev.js gzip 318 kB 318 kB
app-page-tur..prod.js gzip 168 kB 168 kB
app-page.run...dev.js gzip 318 kB 318 kB
app-page.run..prod.js gzip 168 kB 168 kB
app-route-ex...dev.js gzip 70.3 kB 70.3 kB
app-route-ex..prod.js gzip 48.6 kB 48.6 kB
app-route-tu...dev.js gzip 70.4 kB 70.4 kB
app-route-tu..prod.js gzip 48.7 kB 48.7 kB
app-route-tu...dev.js gzip 69.9 kB 69.9 kB
app-route-tu..prod.js gzip 48.4 kB 48.4 kB
app-route.ru...dev.js gzip 69.9 kB 69.9 kB
app-route.ru..prod.js gzip 48.4 kB 48.4 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.2 kB 43.2 kB
pages-api-tu..prod.js gzip 32.9 kB 32.9 kB
pages-api.ru...dev.js gzip 43.2 kB 43.2 kB
pages-api.ru..prod.js gzip 32.9 kB 32.9 kB
pages-turbo....dev.js gzip 52.6 kB 52.6 kB
pages-turbo...prod.js gzip 38.5 kB 38.5 kB
pages.runtim...dev.js gzip 52.6 kB 52.6 kB
pages.runtim..prod.js gzip 38.5 kB 38.5 kB
server.runti..prod.js gzip 61.8 kB 61.8 kB
Total 2.83 MB 2.83 MB ✅ -5 B
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/41780464ee454e72f9293ace99215d9f56c13f19/next

@bgw
Copy link
Member

bgw commented Mar 5, 2026

We should apply all these flags in a single helper function?

sokra added 2 commits March 5, 2026 20:38
Move duplicated DontFork + Unmergeable madvise calls into a shared
helper function in a dedicated mmap_helper module. All mmap sites
(db.rs, static_sorted_file.rs, meta_file.rs, sst_inspect.rs) now
call this single function instead of inlining the cfg-gated advise
calls.
@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Mar 5, 2026

Tests Passed

@lukesandberg lukesandberg merged commit 83ae8ad into canary Mar 6, 2026
288 of 291 checks passed
Copy link
Contributor

Merge activity

@lukesandberg lukesandberg deleted the sokra/dont-fork branch March 6, 2026 05:45
sokra added a commit that referenced this pull request Mar 6, 2026
…90941)

## Summary

- Add `madvise(MADV_DONTFORK)` and `madvise(MADV_UNMERGEABLE)` to all mmap sites in turbo-persistence
- Extract a shared `advise_mmap_for_persistence` helper into a dedicated `mmap_helper` module

## Why

`read_blob` in `db.rs` already correctly sets `DontFork` and `Unmergeable` on its mmap, but three other mmap sites were missing these flags:

- **`static_sorted_file.rs`** (`open_internal`) — SST file mmaps used for lookups and compaction
- **`meta_file.rs`** (`open_internal`) — meta file mmaps storing AMQF filters and SST metadata
- **`sst_inspect.rs`** (`analyze_sst_file`) — diagnostic tool mmap

`MADV_DONTFORK` prevents mmap regions from being copied into child processes on `fork()`, avoiding unnecessary memory duplication and potential SIGBUS issues if the parent unmaps before the child accesses the page. `MADV_UNMERGEABLE` opts the pages out of KSM (Kernel Same-page Merging), avoiding the overhead of scanning these pages for deduplication since they contain unique compressed data.

Both flags are Linux-only (`#[cfg(target_os = "linux")]`), matching the existing pattern in `read_blob`.

## Implementation

Rather than duplicating `#[cfg(target_os = "linux")]` madvise calls at each mmap site, a shared helper `advise_mmap_for_persistence()` is extracted into `src/mmap_helper.rs`. The function applies both flags on Linux and is a no-op on other platforms. All four mmap sites (`db.rs`, `static_sorted_file.rs`, `meta_file.rs`, `sst_inspect.rs`) now call this single helper.

## Test Plan

- `cargo check -p turbo-persistence` passes
- `cargo fmt` clean
- No behavioral change on non-Linux platforms (flags are gated behind `#[cfg(target_os = "linux")]`)
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.

4 participants