Skip to content

perf(cache): use synchronous=NORMAL in WAL mode - #871

Open
magurotuna wants to merge 6 commits into
voidzero-dev:mainfrom
magurotuna:perf/cache-wal-synchronous-normal
Open

magurotuna wants to merge 6 commits into
voidzero-dev:mainfrom
magurotuna:perf/cache-wal-synchronous-normal

Conversation

@magurotuna

Copy link
Copy Markdown
Member

Motivation

Every cache commit in vp run waits for an fsync of the WAL. The cache opens the database in WAL mode but leaves SQLite's default synchronous=FULL, and saving one task's result commits twice: once for cache_entries and once for task_fingerprints. Each cache miss therefore adds two disk syncs before the task counts as finished, so the tasks that depend on it start later.

image

Each run in the chart starts right after vt cache clean, so every task misses the cache and saves its result. The two workspaces are synthetic pnpm workspaces. Each package has one cached task, build, which is a Node.js script that joins five one-line files into dist/out.js. The 3 packages form a chain (app → lib → utils). Each of the 100 packages depends on 0–3 other packages, chosen by a seeded random generator.

Notice that macOS gains almost nothing with this change. This is because a sync there is already fast; SQLite calls fsync(), and on macOS, fsync() moves the data to the drive, but the drive can keep it in its own cache and write it later (fsync(2)).

I haven't measured Windows.

Changes

  • Add the enable_wal function, which runs PRAGMA journal_mode=WAL and checks the returned mode. It sets synchronous=NORMAL only if the result is wal. With NORMAL, commits no longer sync; SQLite syncs the WAL at checkpoints, including the checkpoint when the last connection closes.

Safety

  • In WAL mode, synchronous=NORMAL can't corrupt the database after a power loss or an OS crash, but it can roll back the most recent commits (SQLite docs). For this cache, a rolled-back commit means a cache miss on the next run, so the task runs again. The cache exists only to save time, so this is acceptable.
    • In one rare case, the next run fails instead. When a new entry replaces an old one, vp run first deletes the old entry's output archive. If the new entry is rolled back, the old entry points to the deleted archive, and the run fails with "Cache restore failed. Run vp cache clean to clear the cache". This can already happen on main, because nothing syncs the archives.
  • PRAGMA journal_mode=WAL does not report an error when SQLite cannot use WAL. It keeps the current mode, usually a rollback journal, and returns that mode's name. With a rollback journal, NORMAL has a small chance of corrupting the database after a power loss, so synchronous stays FULL unless the result is wal.
  • A process crash, including SIGKILL, does not lose committed transactions, because the data is already in the OS page cache.
  • The schema and the file format don't change, and SQLite doesn't store synchronous in the file. I checked that main and this PR can use the cache entries that the other wrote.

magurotuna and others added 6 commits October 21, 2026 12:44
The cache database runs in WAL mode with SQLite's default
`synchronous=FULL`, so every commit waits for a sync of the WAL. Saving a
task's result commits twice (the cache entry and the task fingerprint), so
each task that misses the cache waits for two syncs before the run moves on.

Set `synchronous=NORMAL` when WAL mode is on. In WAL mode this never
corrupts the database: a power loss or an OS crash can only roll back the
most recent commits, which become cache misses. The WAL is still synced at
checkpoints, including the one when the last connection closes. If SQLite
can't use WAL (for example, on a network share on macOS), `synchronous`
stays `FULL`, because `NORMAL` with a rollback journal can corrupt the
database after a power loss.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@fengmk2
fengmk2 requested a review from wan9chi October 21, 2026 07:17

This branch has not been deployed

No deployments
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.

1 participant