Files
next.js/test/e2e/filesystem-cache/next.config.js
Luke SandbergandGitHub 2904599735 Optimize how we track data for persistence (#89370)
## Summary

Reworks how the turbo-tasks backend tracks modified tasks for persistence snapshots, reducing overhead and simplifying the snapshot lifecycle.

**Key changes:**

- **Replace `modified` DashMap with per-shard atomic counters + inline flags.** Instead of maintaining a separate `FxDashMap<TaskId, ModifiedState>` that mirrors every modification, track modifications via flags already on `TaskStorage` and use per-shard `AtomicU64` counters to skip unmodified shards during snapshot iteration. This eliminates a major source of  memory overhead.
    - The downside here is needing to scan the map.  per shard counters enable early exits but we will still need to scan entire shards.  For a large site that means scanning thousands of

- **Merge task cache writes into the snapshot pipeline.** New tasks now carry a `new_task` flag and their type hash in `SnapshotItem`, so task cache entries are written in the same batch as task data/meta — removing the separate `persisted_task_cache_log` (`Sharded<ChunkedVec<...>>`) and its associated locking.

- **Remove `local_is_partial` optimization.** The backing storage layer already short-circuits on empty databases, and new tasks eagerly set `restored` flags at allocation time, making this redundant.

- **Simplify `end_snapshot`.** Instead of a multi-pass retain/iterate/update cycle over the `modified` map, `end_snapshot` now just drains the small `snapshots` map (only tasks concurrently accessed during snapshot mode) and promotes their `modified_during_snapshot` flags.

- **Delete unused utilities.** Removes `Sharded`, `ChunkedVec` (from backing_storage), and `swap_retain` import now that they're no longer needed.

**Other cleanups:**
- `initialize_new_task` sets restored + new_task flags at allocation time for both persistent and transient tasks
- Fuzz test updated to use `active_tracking: true` and `StorageMode::ReadWrite`
- New KV storage test for batch write+flush+reopen pattern
- Minor fix: `SmallVec::into_boxed_slice()` instead of `into_vec().into_boxed_slice()`


## Build Benchmark Results

  Measured over 9 runs (1 warm-up discarded), macOS, `TURBOPACK_PERSISTENT_CACHE=1`.

  ### Cold build (`rm -rf .next/`)

  | | Time (avg) | Time (stddev) | MaxRSS (avg) |
  |---|---|---|---|
  | HEAD | 75.48s | 0.72s | 24,231 MiB |
  | This PR | 75.20s | 1.98s | 23,829 MiB |
  | **Delta** | −0.28s | — | **−402 MiB (−1.7%)** |

  ### Warm build (single file edit)

  | | Time (avg) | MaxRSS (avg) |
  |---|---|---|
  | HEAD | 23.79s | 8,764 MiB |
  | This PR | 23.67s | 8,766 MiB |
  | **Delta** | −0.12s | flat |

  Cold build time difference is within noise (< 1 stddev). The meaningful improvement is a **~400 MiB reduction in peak memory on cold builds**, consistent with the fixed overhead this PR targets. Warm builds are unaffected as expected.
2026-04-07 09:25:27 -07:00

53 lines
1.2 KiB
JavaScript

const enableCaching = !!process.env.ENABLE_CACHING
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
turbopack: {
rules: {
'./app/**/page.{jsx,tsx}': {
loaders: ['./my-timestamp-loader.js'],
},
'./app/loader/page.tsx': {
loaders: ['./my-loader.js'],
},
'./pages/pages.tsx': {
loaders: ['./my-timestamp-loader.js'],
},
},
},
experimental: {
turbopackFileSystemCacheForBuild: enableCaching,
turbopackFileSystemCacheForDev: enableCaching,
},
env: {
NEXT_PUBLIC_CONFIG_ENV: 'hello world',
},
webpack(config, { dev }) {
config.module.rules.push({
test: /app(?:\/.*)?\/page\.[tj]sx|pages\/pages\.tsx/,
use: ['./my-timestamp-loader.js'],
})
config.module.rules.push({
test: /app\/loader(?:\/client)?\/page\.tsx/,
use: ['./my-loader.js'],
})
if (enableCaching) {
config.cache = Object.freeze({
type: 'memory',
})
}
if (dev) {
// Make webpack consider the build as large change which makes it filesystem cache it sooner
config.plugins.push((compiler) => {
compiler.__extra_delay = true
})
}
return config
},
}
module.exports = nextConfig