[ sys ]entropysha 901ddb7measured-in-repo
A SQL database engine, built from scratch down to the disk page.
I wrote the real internals of a disk-backed relational engine in C++20: a recursive-descent parser, a cost-based optimizer, Volcano executors, MVCC and two-phase-locking transactions, a WAL with ARIES recovery, and a B+ tree over an LRU buffer pool. No SQL-parsing or storage libraries.
- [ entropy ], noun
- 1.a from-scratch C++20 relational database engine
- 2.parse, plan, execute, persist, recover, end to end
- 3.benchmarked against SQLite on the same harness
- insert throughput
- 1M+ rows/s
- engine size
- ~17.3k
- test coverage
- 355
- lang
- C++20
- license
- MIT
- size
- ~17.3k LOC / 6 src libs
- baseline
- SQLite (libsqlite3)
- harness
- Google Benchmark
- verdict
- measured-in-repo
the shape of the engine
One SELECT all the way down: every box is a compiled library, every arrow is the path a tuple takes from SQL text to a B+ tree leaf, made physical.
- 01api/shellC++ API
SELECT * FROM users WHERE id = 42 - 02parser/lexerrecursive descentprecedence climb
tokens -> AST - 03parser/bindername resolutiontype check
bound AST (resolved cols + types) - 04optimizer/statisticscost modelindex selector
cost-chosen plan: index scan - 05execution/index scanfilterproject
Volcano iterator: next() -> tuple - 06storage/buffer_poolpage tableLRU replacerpin / dirty
pin(page) -> frame (LRU on miss) - 07storage/b_plus_treerootinternalleaf
leaf slot -> tuple #42
SELECT descending the real engine. Each box is a compiled library under src/. Each arrow is the path one tuple takes from SQL text to a B+ tree leaf.Most database projects are a map with SQL bolted on
Most database portfolio projects are a thin SQL wrapper over an in-memory hash map. I wanted the real internals of a disk-backed relational engine, end to end: parse SQL, plan and cost it, execute it through composable operators, and persist it through a buffer pool with ACID transactions and crash recovery.
The constraint that made it real: modern C++20, and no SQL-parsing or storage libraries pulled in. If the parser, the B+ tree, and the recovery log were going to exist, I had to write them.
Mirror the database pipeline as libraries with explicit boundaries
Entropy mirrors the logical pipeline as separately compiled C++ libraries, each with an explicit boundary. A hand-written recursive-descent parser and binder feed a cost-based optimizer (statistics, cost model, index selector), which produces Volcano-style iterators for scans, joins, sort, aggregate, filter, and DML.
Underneath sit MVCC and a two-phase-locking lock manager with deadlock detection, a write-ahead log with ARIES three-phase recovery, and a storage engine of slotted pages, a B+ tree, an extendible hash index, and an LRU buffer pool over a disk manager. The benchmark harness uses Google Benchmark and drives the same queries against SQLite when ENTROPY_BENCH_COMPARE_SQLITE=ON.
Separately compiled libraries under src/, one data path to disk
Layered under src/: parser/, optimizer/, execution/ with about twelve operators, transaction/ (MVCC, lock manager, WAL, recovery), storage/ (pages, B+ tree, hash index, buffer pool, disk manager), catalog/, and a public API in include/entropy/.
src/, with an explicit boundary. The arrows are the data path a statement follows down to disk.Twelve ADRs, including the ones I would defend in review
DESIGN.md carries twelve architecture decision records of roads not taken. Here are the four that shaped the engine most. Each names what I chose, what I gave up, and where the reasoning lives.
- ADR-004road not taken
Hand-written recursive-descent parser
over hsql / libpg_query
- ADR-003road not taken
MVCC + snapshot isolation
over strict 2PL
- ADR-005road not taken
Volcano iterator execution
over vectorized / push-based
- ADR-007/011road not taken
Nested-loop join first, hash join after
over hash join only
Entropy loses to SQLite on point selects. That result is in the chart below at full size.
11% faster than SQLite on batch inserts, slower on point selects
On a batch of 1,000 single-transaction inserts, Entropy runs at 1M+ rows/s, about 11% faster than SQLite through the same Google Benchmark harness.
On point selects it is 2.0-2.6× slower. Both numbers come from the same run, pinned to sha 901ddb7, against system libsqlite3. The chart anchors on SQLite at 1.0×.
- Insert batch · 1k rows · single txn0.90×Entropy 941 µsSQLite 1.05 ms
- Insert batch · 10k rows · single txn1.39×Entropy 9.69 msSQLite 6.99 ms
- Point select · 1k rows2.00×Entropy 46 µsSQLite 23 µs
- Point select · 10k rows2.56×Entropy 460 µsSQLite 180 µs
These are single-repetition results. The harness takes --benchmark_repetitions for p50/p95/p99 when I want them. Raw data.
Five places the engine does the work a toy version skips
Each links into the source at the pinned SHA.
Watch one statement descend the engine
Launch the console below to step a real SQL statement through this exact architecture, next to the Entropy-vs-SQLite benchmark chart.
entropy · sql console