Skip to content

design(daemon): WAL checkpointing at shutdown across platforms - #934

Draft
kriscendobot wants to merge 1 commit into
llmfrom
design/daemon-sqlite-shutdown-checkpoint
Draft

design(daemon): WAL checkpointing at shutdown across platforms#934
kriscendobot wants to merge 1 commit into
llmfrom
design/daemon-sqlite-shutdown-checkpoint

Conversation

@kriscendobot

Copy link
Copy Markdown
Collaborator

Summary

Design doc: SQLite WAL Checkpointing at Shutdown, Cross-Platform (designs/daemon-sqlite-shutdown-checkpoint.md).

Answers the open question left in the pet-store SQLite parity design (designs/daemon-endor-pet-store-sqlite.md, PR #124), "WAL checkpointing on shutdown?", whose draft answer concluded that journal_mode = WAL plus a clean db.close() was sufficient. Per the maintainer's review comment on that line (#124 (comment)) asking to design checkpointing at shutdown across all supported platforms.

Why the draft answer was incomplete

"Clean db.close() is sufficient" is true only incidentally: SQLite auto-checkpoints the WAL only when the last connection closes cleanly, in PASSIVE mode, and it is skipped on abrupt termination, on a stray second connection, or under SQLITE_FCNTL_PERSIST_WAL. That leaves three gaps once the daemon runs on more than one platform and its state is snapshotted or handed off:

  1. File-level backup captures a stale database. Both parent designs say daemon backup is at the file level; a single-file copy of endo.sqlite while a WAL exists misses every un-checkpointed write.
  2. Cross-platform handoff replays one platform's WAL under another (the companion directive on the same PR: rust hands off to node, node to rust). That couples two independently-bundled SQLite builds through the on-disk WAL format and needs all three files to travel together.
  3. The auto-checkpoint is a default the daemon does not control rather than an operation it performs.

What the design proposes

  • One checkpoint(mode = 'TRUNCATE') method on the Database contract, folded into the shared close() in makeDaemonDatabase before the backend close, uniform across Node (better-sqlite3) and Rust+XS (rusqlite).
  • TRUNCATE leaves a zero-length -wal, so a graceful shutdown produces a self-contained endo.sqlite: single-file snapshot and sidecar-free reopen become correct by construction.
  • No new Rust host function: wal_checkpoint is a pragma and rides the existing host_sqlite_exec seam. The Rust side re-prepares statements per call, so there is no zombie-close risk at sqlite3_close.
  • Crash path (SIGKILL / power loss) is answered by a documented recovery-on-open contract plus a cross-platform WAL-compatibility test, since a killed process cannot checkpoint.
  • Extends the existing cross-supervisor parity suite (sqlite-parity.test.js) with four cases: self-contained-file-after-close, single-file cross-platform handoff, same-platform crash recovery, cross-platform crash recovery.

Registered in designs/README.md (summary table + M11 milestone table).

Draft: design-stage, for review before un-drafting. Mermaid diagram parse-validated. Open questions (suspend/resume checkpoint call, concrete journal_size_limit, defense-in-depth checkpoint in host_sqlite_close) are enumerated in the doc.

Answers the pet-store SQLite parity design's open question
(WAL checkpointing on shutdown?) flagged in PR #124 review.

Replaces the incidental last-connection auto-checkpoint with an
explicit wal_checkpoint(TRUNCATE) folded into the shared close(),
uniform across Node (better-sqlite3) and Rust+XS (rusqlite), so a
graceful shutdown leaves a self-contained endo.sqlite. Makes
file-level snapshot and cross-supervisor handoff single-file-safe
and pins the crash-path recovery-on-open contract. No new Rust
host function.

Registered in designs/README.md (summary table + M11 milestone).
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