0001 — Atomicity by temp-dir + rename, not locks¶
Status: Accepted (v0.1.0)
Context¶
A record must never be half-written. The library's one promise is never lose
a failure, and a reader (the CLI, the dashboard, another process) can arrive
at any moment — including the moment a kill -9 lands mid-write. Multiple
processes write to one folder concurrently, on three operating systems, with
no daemon and no server to coordinate them.
Decision¶
A record is assembled in a hidden .tmp-<random>/ directory and renamed
into place. The rename is the commit point. Sequential ids are allocated by
creating the numbered directory, which is atomic on every supported
platform, so two processes cannot claim the same id — the loser takes the next
one.
No lock files guard record writes. The only lock in the system protects
index.json, which is a rebuildable cache, not the source of truth.
Alternatives considered¶
- A lock file around the folder. Locks need an owner, a timeout, and a story for the process that dies while holding one. Windows makes each of those harder. A design where torn states are unrepresentable beats a design that detects and repairs them.
- SQLite. Solves atomicity, loses
cat/grep/rm -rf— the folder being plain files people can read by hand is a feature users rely on.
Consequences¶
- A crash mid-write leaves an ignorable
.tmp-*directory, never corruption.quarantine reindexsweeps them. - Windows sync clients and virus scanners can hold a brand-new directory open, making the commit rename fail transiently — so the rename retries with backoff (v0.1.3 hardened this).
- Object stores have no rename, which is why remote backends need their own commit-point decision: see 0007.