wal

Write-ahead log and checkpoint recovery

What to watch

Which writes survive a crash between checkpoints

Seed: 1 (default). The program asks a question at the interesting moment; with Predict on, the run stops there so you can answer before you see what happens.

Run it

Edit any file and press Run. The tabs hold the program and the packages it uses.

# package main
use github.com/synodlang/examples/wal
use std/lesson
use std/lists
use std/sim
use std/text

define main
  set db to (sim.Spawn wal)
  each i in (lists.Range 1 to 12)
    after (i times 300ms)
      deliver (message wal.Put with Key (text.Join {"k", (text.From i)}), Value (text.From i)) to db
  after 3100ms
    sim.Crash db
    lesson.Ask "The last checkpoint was at 2s. Which writes survive the crash?" choosing {"Only the six writes made before the checkpoint", "All ten acknowledged writes: six from the checkpoint, four replayed from the log", "None: memory is lost with the crash", "Every write, including the one sent during the outage"}
  after 3500ms
    sim.Restart db
    lesson.Note "Writes after the checkpoint come back from the log."
  sim.StopAt 5s
# package wal
use std/disk
use std/lists
use std/sim
use std/text
use std/time

Put has
  set Key to ""
  set Value to ""

Recovered has
  set Replayed to 0

Node has
  set Table to {}
  set Lsn to 0
  set Flushed to 0

# On start: load the last checkpoint, then replay the log written after it
define [n: Node] Recover
  set n.Table to (disk.Read "pages" on n or {})
  set n.Flushed to (disk.Read "flushed" on n or 0)
  set n.Lsn to (disk.Read "last" on n or 0)
  set replayed to 0
  each i in (lists.Range (n.Flushed plus 1) to n.Lsn)
    set entry to (disk.Read (text.From i) on n or (message Put with Key ""))
    set item entry.Key of n.Table to entry.Value
    set replayed to (replayed plus 1)
  emit (message Recovered with Replayed replayed) by n

# A checkpoint writes the whole table, so older log entries are no longer needed
define [n: Node] Checkpoint
  disk.Write n.Table at "pages" on n
  disk.Write n.Lsn at "flushed" on n
  set n.Flushed to n.Lsn

define [n: Node] start
  n.Recover
  time.Every 2s
    n.Checkpoint

# Write-ahead: the log entry is durable before the in-memory table changes
when [n: Node] (sim.Delivered Put)
  set n.Lsn to (n.Lsn plus 1)
  disk.Write Put at (text.From n.Lsn) on n
  disk.Write n.Lsn at "last" on n
  set item Put.Key of n.Table to Put.Value

On your own machine: synod run ./wal. Source on GitHub · all examples