fear of code

SQLITE_BUSY is not a deadlock

A job runner started failing under load with database is locked, and because the message says "locked" I went looking for a lock ordering problem that was not there.

SQLite returns SQLITE_BUSY when a connection cannot get the lock it needs within the busy timeout, and the default busy timeout is zero. So the first writer that meets a reader holding the database fails instantly, which looks like contention far worse than it is.

PRAGMA busy_timeout = 5000;
PRAGMA journal_mode = WAL;

WAL matters as much as the timeout: without it readers and writers exclude each other, so the timeout only buys you a queue. With it, readers do not block the writer at all and the busy window shrinks to the moment of commit.

What I would tell myself a day earlier: the error names the symptom, not the cause, and SQLite's defaults are tuned for a single-process command-line tool because that is what it was for.

All notes · Front page