Lightning Memory-Mapped Database — embedded key-value store with ACID transactions, zero-copy reads, and sorted cursor iteration.
ppm install lmdb
Requires liblmdb-dev on Ubuntu/Debian: sudo apt install liblmdb-dev
Overview
Memory-mappedReads are zero-copy — as fast as a pointer dereference. No buffer copies.
MVCC transactionsACID with Multi-Version Concurrency Control. Readers never block writers.
Single fileNo log files, no write-ahead log, no recovery needed. Simple to deploy.
Sorted keysKeys always stored in binary order. Range scans are O(log n) + sequential.
Read throughputMillions of reads/sec — used by OpenLDAP, Mozilla, Bitcoin Core, Tor.
Named sub-databasesMultiple key-value spaces (DBI) within one environment file.
Quick Start
uses lmdb;
{ Open environment — 100 MB map, 4 named sub-databases }
var env := EnvOpen('/tmp/mydb', 100 * 1024 * 1024, 4, 126);
{ Write transaction }
var txn := TxnBegin(env);
var dbi := DBIOpen(txn); { default unnamed DB }
Put(txn, dbi, 'hello', 'world');
Put(txn, dbi, 'foo', 'bar');
TxnCommit(txn);
{ Read transaction }
var ro := TxnBeginRO(env);
var v := Get(ro, dbi, 'hello'); { 'world' }
TxnAbort(ro);
EnvClose(env);
Named Sub-Databases
var env := EnvOpen('/tmp/app', 512 * 1024 * 1024, 8, 126);
var txn := TxnBegin(env);
var users := DBIOpenNamed(txn, 'users');
var sessions := DBIOpenNamed(txn, 'sessions');
Put(txn, users, 'u:1001', '{"name":"Alice"}');
Put(txn, sessions, 's:abc123', 'u:1001');
TxnCommit(txn);
Cursor Iteration
var ro := TxnBeginRO(env);
var cur := CursorOpen(ro, dbi);
{ Iterate all keys in sorted order }
if CursorFirst(cur) then
repeat
Writeln(CursorKey(cur) + ' = ' + CursorValue(cur));
until not CursorNext(cur);
{ Range scan: keys starting with 'user:' }
if CursorSeekRange(cur, 'user:') then
repeat
if not StartsWith(CursorKey(cur), 'user:') then break;
Writeln(CursorKey(cur));
until not CursorNext(cur);
CursorClose(cur);
TxnAbort(ro);
Hot Backup
{ Copy the live environment to another path — no downtime }
EnvCopy(env, '/backup/mydb');
{ Get environment info }
var info := EnvInfo(env);
Writeln('Map size: ' + IntToStr(info.MapSize));
Writeln('Readers: ' + IntToStr(info.NumReaders));
API Reference
Environment
| Function | Description |
| EnvOpen(Path, MapSize, MaxDBs, MaxReaders) | Open or create an LMDB environment. MapSize in bytes (can exceed RAM). |
| EnvOpenReadOnly(Path, MapSize) | Open read-only environment. |
| EnvClose(Env) | Close environment and release the memory map. |
| EnvSetMapSize(Env, MapSize) | Resize the map (no open transactions allowed). |
| EnvSync(Env, Force) | Flush buffers to disk. |
| EnvInfo(Env) | Returns TLMDBInfo: MapSize, LastPageNo, MaxReaders, NumReaders. |
| EnvCopy(Env, Path) | Hot-copy the live environment to a directory. |
Transactions
| Function | Description |
| TxnBegin(Env) | Begin a read-write transaction. |
| TxnBeginRO(Env) | Begin a read-only transaction (multiple can run concurrently). |
| TxnCommit(Txn) | Commit the transaction. |
| TxnAbort(Txn) | Abort/rollback the transaction. |
| TxnReset(Txn) | Reset a read-only transaction for reuse. |
| TxnRenew(Txn) | Renew a previously reset read-only transaction. |
Database (DBI)
| Function | Description |
| DBIOpen(Txn) | Open the default unnamed database. |
| DBIOpenNamed(Txn, Name) | Open a named sub-database (created if it doesn't exist). |
| DBIClose(Env, DBI) | Close a DBI handle (rarely needed). |
| DBIDrop(Txn, DBI, DeleteDB) | Clear all entries or delete the sub-database entirely. |
| DBIStat(Txn, DBI) | Returns TLMDBStat: Entries, Depth, PageSize, LeafPages. |
Read / Write
| Function | Description |
| Get(Txn, DBI, Key) | Get value for a key. Returns '' if not found. |
| Exists(Txn, DBI, Key) | Return True if the key exists. |
| Put(Txn, DBI, Key, Value) | Insert or replace a key-value pair. |
| PutNoOverwrite(Txn, DBI, Key, Value) | Insert only if key doesn't exist. Returns False if it does. |
| Delete(Txn, DBI, Key) | Delete a key. Returns False if not found. |
Cursor
| Function | Description |
| CursorOpen(Txn, DBI) | Open a cursor for sorted iteration. |
| CursorClose(Cursor) | Close and free the cursor. |
| CursorFirst/Last(Cursor) | Move to first or last key. Returns False if empty. |
| CursorNext/Prev(Cursor) | Move to next or previous key. |
| CursorSeek(Cursor, Key) | Seek to exact key match. Returns False if not found. |
| CursorSeekRange(Cursor, Key) | Seek to first key >= Key (range scan start). |
| CursorKey/Value(Cursor) | Get current key or value. |
| CursorPut(Cursor, Key, Value) | Write at cursor position. |
| CursorDelete(Cursor) | Delete the entry at cursor position. |