Skip to content

ChengyanOo/a-python-single-file-database

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DBDB — Dog Bed Database 🐕

A tiny, crash-tolerant key/value database written from scratch in pure Python (~350 lines). Built by hand as a learning project, following the classic "DBDB: Dog Bed Database" chapter by Taavi Burns from 500 Lines or Less.

It looks like a Python dictionary:

import dbdb

db = dbdb.connect("dogs.db")   # open (or create) a database file
db["wangcai"] = "golden"       # set
db.commit()                    # durably write to disk
print(db["wangcai"])           # get -> "golden"
db.close()

…but underneath it implements the core mechanics of a real database engine:

  • Append-only storage — data is never overwritten in place, so a crash can't corrupt committed data
  • Immutable binary search tree with copy-on-write — every update creates new nodes along the path to the root; old trees stay intact on disk
  • Atomic commits — a commit is a single 8-byte root-address write into the superblock: it either happens or it doesn't
  • Lazy loading — nodes and values are read from disk only when followed, so the dataset can be larger than memory
  • Multi-process safety — writers take an exclusive file lock; readers always see the last committed root

Crash tolerance in one demo

db = dbdb.connect("dogs.db")
db["a"] = "committed"
db.commit()
db["b"] = "uncommitted"
# 💥 process dies here — no commit, no close

db = dbdb.connect("dogs.db")
db["a"]        # -> "committed"  (still there)
"b" in db      # -> False        (vanished cleanly, no corruption)

Because writes only append and the root address flips atomically, an interrupted write simply leaves unreachable garbage at the end of the file — the last committed tree is untouched.

Install & use

Requires Python 3.8+. The only dependency is portalocker (cross-platform file locking).

git clone https://github.com/ChengyanOo/build-my-own-dog-bed-db-with-python.git
cd build-my-own-dog-bed-db-with-python
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt

As a library

import dbdb

db = dbdb.connect("example.db")
db["key"] = "value"     # stage a write (takes the write lock)
db.commit()             # make it durable (releases the lock)
value = db["key"]       # read
"key" in db             # membership test
len(db)                 # number of keys
del db["key"]           # delete (needs a commit too)
db.close()

From the command line

python -m dbdb.tool example.db set greeting hello
python -m dbdb.tool example.db get greeting
python -m dbdb.tool example.db delete greeting

Exit codes: 0 OK, 1 bad arguments, 2 unknown command, 3 key not found.

Architecture

The layers are stacked bottom-up, each one only talking to the layer below:

Module Layer Responsibility
dbdb/physical.py Physical Storage: append-only file with a 4 KB superblock, length-prefixed records, exclusive locking
dbdb/logical.py Logical ValueRef (lazy disk pointer) and LogicalBase (get/set/pop/commit skeleton for any key/value structure)
dbdb/binary_tree.py Data structure Immutable BinaryNode, pickle-serialized BinaryNodeRef, copy-on-write BinaryTree
dbdb/interface.py API DBDB: the dict-like facade (__getitem__, __setitem__, __delitem__, …)
dbdb/tool.py CLI python -m dbdb.tool DBNAME get/set/delete …

How a commit works:

  1. Every mutation builds new tree nodes in memory; nothing touches disk yet.
  2. commit() serializes the new nodes and appends them to the file, children before parents (so every stored node only references already-stored addresses).
  3. Finally the new root's address is written into the superblock at offset 0. That single write is the commit.

Known limitations (faithful to the original)

This is a teaching project; these gaps are kept intentionally, matching the book chapter:

  • No fsync — commits flush() to the OS, so the process can crash safely, but a power failure can still corrupt the file. A production database must os.fsync.
  • Pickle serialization — never open an untrusted .db file; unpickling can execute arbitrary code.
  • Unbalanced tree — sequential inserts degrade to a linked list and hit RecursionError around ~1000 keys. Balancing (e.g. a B-tree) is the book's suggested exercise.
  • String keys/values only — storing non-strings fails at read/commit time, not at assignment.
  • Write lock is held until commit/close — a writer that never commits blocks all other writers indefinitely.

Credits

Original design and code: Taavi Burns, 500 Lines or Less — DBDB: Dog Bed Database (MIT licensed). This repository is my from-scratch reimplementation of it as a hands-on learning exercise. See LICENSE.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages