LMDB (Lightning Memory-Mapped Database)

LMDB is an embedded, memory-mapped, B+tree key-value store written in C by Howard Chu of OpenLDAP. It is one of the fastest embedded databases ever built — reads come straight out of the OS page cache via mmap with zero copying, and writes are committed via a single fsync per transaction. LMDB underpins OpenLDAP’s back-mdb backend, the Bitcoin Core block index, monero, several Python ML data loaders, and many other systems where read latency matters more than feature richness.

1. Architecture

LMDB Memory-Mapped Architecture Process A (reader)pointers into mapProcess B (writer)one write txnVirtual memory mapmmap of data.mdbOS page cacheshared by all processesdata.mdb fileB+tree pagesReads return pointers directly into the mapped pages: no copy into an application cache, no decompression.The OS page cache is the only cache, so memory is shared between processes and survives application restarts.

LMDB is a library linked into your process, not a server. A database environment is a directory containing one data file and one lock file. On open, LMDB maps the data file into memory with mmap. A read walks the B+tree by following page offsets in that mapping and returns a pointer to the value bytes in place, which is why reads are so cheap: there is no buffer pool, no serialisation layer and no system call per lookup once pages are cached. The operating system decides which pages stay in RAM, and several processes opening the same environment share those pages.

2. Key Features:

3. LMDB vs. LevelDB / RocksDB:

4. Use Cases:

5. Transactions and Copy-on-Write

Copy-on-Write B+tree Commit Root (txn 41)Leaf ALeaf BRoot (txn 42)new copyLeaf B'modified copyA write copies only the changed leaf and its path to the root, then commits by switching the meta page.Readers that started at txn 41 keep using the old root, so they are never blocked and always see a consistent snapshot.Old pages are reused only after no reader references them; a long-lived read transaction stops that reuse.

LMDB never overwrites live pages. A write transaction copies each page it modifies, along with the path up to a new root, and commits by writing one of two meta pages that point at the current root. A crash before that write leaves the previous meta page intact, so there is no write-ahead log and no recovery step. Readers take a snapshot by recording the current root; they are lock-free and see a fixed version for the duration of the transaction. Only one write transaction can be active at a time per environment, which keeps the design simple and avoids deadlocks, but it means write throughput is limited to what a single writer can achieve.

6. Python Example

import lmdb   # pip install lmdb

# map_size is the maximum database size; it reserves address space, not disk
env = lmdb.open("students.lmdb", map_size=1 << 30, max_dbs=4)
students = env.open_db(b"students")

with env.begin(write=True, db=students) as txn:     # single writer
    txn.put(b"1001", b'{"name": "Alice", "state": "WA"}')
    txn.put(b"1002", b'{"name": "Bob", "state": "OR"}')
    txn.put(b"1003", b'{"name": "Charlie", "state": "CA"}')

with env.begin(db=students) as txn:                 # snapshot read
    print(txn.get(b"1002"))
    cur = txn.cursor()
    cur.set_range(b"1002")                          # range scan from a key
    for key, value in cur:
        print(key, value)

print(env.stat()["entries"], "entries")

Keys are sorted bytewise, so integer keys should be stored big-endian (for example struct.pack(">Q", n)) if numeric order matters. Batching many puts in one write transaction is much faster than committing each put, because each commit flushes to disk by default.

7. Configuration Notes

SettingEffect
map_sizeUpper bound on database size. Writes fail with MapFullError when it is reached; it can be increased later with env.set_mapsize().
sync=False / metasync=FalseFaster commits at the cost of durability of the most recent transactions after an OS crash (still consistent).
readonly=True, lock=FalseFor read-only datasets such as ML training data on shared storage.
max_readersSize of the reader lock table; raise it for many threads or processes.

8. Pitfalls