Skip to content

Concurrency

BisonDB's concurrency story is deliberately conservative: coarse locks, clearly layered, in exactly one process. This page states the model precisely — including what "single-process" rules out.

The server's threading shape

The acceptor hands each connection to a fixed thread pool (default: hardware concurrency); a connection occupies one worker for its lifetime and processes its requests strictly in order. Beyond the connection cap (default 64) new sockets get a ServerBusy frame and a close. Exceptions never kill a worker — they become Internal error responses.

The lock hierarchy

Three layers, each with one job:

LayerLockProtects
Collectionone readers-writer lock per collectionthe combination of log + all its indexes
B+Treeone readers-writer lock per treetree structure during a single operation
Pager / logplain mutexesthe file handle and page cache underneath everything

The collection lock is the one that matters for correctness: insert, delete, and update take it exclusively and update the log and every index inside one critical section, so readers can never observe a document that exists in the log but not in an index, or vice versa. Reads take it shared.

Two practical notes from building it:

  • "Read-only" operations still mutate. A page-cache hit reorders an LRU list; a log read seeks a shared file handle. Both needed their own internal mutexes — found the hard way when concurrent readers corrupted the cache list under load. Locks follow mutation, not the API's notion of "read."
  • Writer preference. The readers-writer lock prefers waiting writers, so a stream of readers can't starve a write forever. (The shipped implementation is hand-rolled over a mutex and condition variable after platform shared_mutex proved unreliable under contention on MinGW.)

What this model costs

One writer per collection at a time — bulk writes serialize. Long range scans hold a shared lock that delays writers. Production engines fix this with page-level latching, MVCC snapshots, or both; those were explicitly scoped out, because each replaces a provably simple invariant ("the collection lock makes log+indexes atomic") with hundreds of subtle ones. The 8-thread × 1000-operation integration soak validates the model that is claimed.

Single-process means single-process

The data directory has no cross-process locking. Two bisond instances on one directory will interleave appends and corrupt the recovery invariant. Run one server per data directory and let every client go through it — that is the deployment model, full stop. Multi-node replication is a different project; the FAQ sketches what it would take.

BisonDB and Prairie are GPLv3 · educational projects.