Sendpoint

Think out loud while you read.

Make a voice note before the thought gets away.

Download for Mac↓ GitHub

MACOS 14 OR LATER · APPLE SILICON

@texoport__
chatgpt.com
SQLite WAL Mode - SQLite Documentation
Share
···
I'm reading about SQLite WAL mode and I'm confused about reader-writer concurrency. When a reader starts a long query while a writer commits new pages to the WAL, how does the reader get a consistent snapshot without locks—and what happens during a checkpoint? A concrete explanation would help.

In SQLite's WAL (Write-Ahead Logging) mode, changes do not overwrite the main database file directly. Instead, transactions append new committed pages to a separate .wal file.

When a reader begins a transaction, it records a read-mark in the shared-memory WAL index (.shm file), pointing to the last valid commit frame at that exact moment.

That read-mark freezes the reader's view to a point-in-time snapshot. When reading a page, SQLite checks the WAL index to see if a newer frame exists up to that read-mark. If not found, it reads the page from the main database file.

Writers continue appending newer frames to the end of the log:

-- Writer appends frame 42, 43 to .wal
-- Active reader's read-mark remains fixed at frame 40

Writers never block readers because writers append to the end of the log file, while readers only scan frames up to their established read-mark.

Later comes checkpointing, which transfers committed WAL pages back into the main database file:

Checkpoint rule: SQLite cannot truncate or overwrite WAL frames beyond the oldest active reader's read-mark.

If any reader is still active on an older frame, earlier frames remain pinned in the WAL.

This design gives snapshot isolation without read locks, but a stalled reader prevents WAL truncation, causing the log file to grow on disk.


+
Ask ChatGPT
Extra High⌄
✳ Claude Code
Claude Code v2.1.273
Opus 5 (1M context) with medium effort · Claude Max
~/code/sync-engine
❯ explain the conflict resolution architecture in src/sync/reconciler.ts
⏺ Read(src/sync/reconciler.ts)
⎿ Read 78 lines
⏺ reconcile resolves offline client mutations against the server log.
The client never waits for network confirmation before updating local state.
async function reconcileBatch(localLog, remoteBatch) {
const uncommitted = await localLog.pendingMutations();
await localDb.rollbackToSnapshot(remoteBatch.baseRevision);
await localDb.applyRemote(remoteBatch.changes);
return await localLog.rebaseAndReplay(uncommitted);
}
Optimistic UI mutations apply immediately to the local SQLite store.
When server changes arrive, the local store rewinds to the common base,
applies upstream changes, and replays pending mutations on top.
◐ medium · /effort
❯
⏵⏵ auto mode on (shift+tab to cycle)
Search notes in Reading notes Switch stack
New stack⌘N
Reading notes · 7 notes⇥stacks TemplatePlain⌘P Edit↩ Actions⌘K ⌘Ucycle ⇧reverse Release to switch
Reading notes 0