Persistence & WAL
ArcFlow uses a write-ahead log (WAL) for durability. All mutations are journaled before they're applied.
In-memory vs. persistent#
import { open, openInMemory } from 'arcflow'
// In-memory: fast, lost on exit. Great for tests.
const mem = openInMemory()
// Persistent: WAL-journaled, survives crashes and restarts.
const disk = open('./data/graph')How persistence works#
- Write: mutations are appended to the WAL before being applied
- Crash: if the process dies, the WAL retains all committed mutations
- Recovery: on next
open(), the WAL replays automatically — no data loss - Background checkpoint: the WAL is periodically compacted into a snapshot in a background thread — no write pause
Read path — MVCC lock-free reads#
The read path uses a copy-on-write store with atomic snapshot swaps. Readers load the current graph snapshot via an atomic pointer swap — no read lock, no contention with writers. Writes produce a new snapshot and atomically swap it in. This means:
db.query()never blocks on a concurrentdb.mutate()db.mutate()never blocks on concurrent reads- Zero-copy commit: the committed snapshot is swapped in atomically without copying
const db = open('./my-graph')
// This mutation is WAL-journaled
db.mutate("CREATE (n:Important {data: 'critical'})")
// Process crashes here...
// On restart — WAL replays, data is recovered
const db2 = open('./my-graph')
const result = db2.query("MATCH (n:Important) RETURN n.data")
console.log(result.rows[0].get('data')) // "critical"Checkpoints#
Query checkpoint metadata:
const cp = db.query("CALL db.checkpointMeta")
console.log(cp.rows[0].toObject()) // { generation, nodeCount, mutationSeq }In the CLI REPL, use :checkpoint to save a snapshot:
arcflow> :checkpoint
Integrity verification#
Compute a cryptographic fingerprint of the graph state:
const fp = db.query("CALL db.fingerprint")
console.log(fp.rows[0].get('fingerprint')) // sha256:...Data directory structure#
./my-graph/
├── worldcypher.snapshot.json # Compacted snapshot (after checkpoint)
└── wal/ # Write-ahead log segments
Closing the database#
Call close() for a clean shutdown that flushes the WAL:
db.close()After closing, all operations will throw an ArcflowError with code DB_CLOSED.
See Also#
- Persistence & WAL — server-mode persistence and WAL configuration
- Snapshot & Restore — graph backup and migration
- Event Sourcing — every mutation as a temporal fact in the WAL
- Temporal Queries —
AS OF seq Nqueries over the persisted history
Try it
Open ↗⌘↵ to run
Loading engine…