lmdb
stableTransactional ordered key-value store with LMDB-style semantics: snapshot-isolated transactions, cursor iteration, range queries, and explicit commit or abort.
use plugin lmdb::{LmdbEnv.new, LmdbEnv.begin_txn, LmdbEnv.stat, …} Functions (16)
- LmdbEnv.new Open or create a database environment
- LmdbEnv.begin_txn Start a new transaction
- LmdbEnv.stat Get environment statistics
- LmdbTxn.put Write a key-value pair in a transaction
- LmdbTxn.get Read a value by key in a transaction
- LmdbTxn.delete Mark a key deleted in a transaction
- LmdbTxn.commit Commit and apply all transaction writes
- LmdbTxn.abort Discard all pending transaction writes
- LmdbTxn.exists Check if a key exists in the transaction view
- LmdbTxn.count Count entries visible in the transaction
- LmdbTxn.keys List all keys visible in the transaction
- LmdbTxn.cursor_first Move cursor to first entry
- LmdbTxn.cursor_next Advance cursor to next entry
- LmdbTxn.cursor_last Move cursor to last entry
- LmdbTxn.cursor_prev Move cursor to previous entry
- LmdbTxn.cursor_range Iterate entries within a key range
Overview
lmdb is a transactional, ordered key-value store modeled on the semantics of
LMDB. The two core concepts are the environment (LmdbEnv), which holds all
committed data, and the transaction (LmdbTxn), through which every read and
write flows. Both are opaque handles returned by the plugin: you create an
environment with LmdbEnv.new, then call begin_txn to open a transaction.
The transaction model gives you snapshot isolation: a transaction captures a
point-in-time view of the committed store when it begins, so its reads are stable
even if other transactions commit in the meantime. Writes (put / delete)
accumulate in a private write set and become visible to the rest of the world only
when you call commit; calling abort throws them away. A finalized transaction
(committed or aborted) cannot be reused.
Keys are kept in sorted order, which makes the cursor API
(cursor_first / cursor_next / cursor_last / cursor_prev) and
cursor_range cheap and predictable. Reach for lmdb when you want an embedded,
ordered store with explicit transactional boundaries rather than a fire-and-forget
map. Note that the current implementation keeps data in memory — the path passed to
LmdbEnv.new is recorded for reference but not written to disk.
Common patterns
Open an environment, write a batch of records in one transaction, and commit:
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/users")
let w = env.begin_txn()
w.put("user:1", "Alice")
w.put("user:2", "Bob")
w.put("user:3", "Carol")
w.commit()
let stats = env.stat()
print("stored {stats["entries"]} users in {stats["total_bytes"]} bytes")
Open a read transaction and walk every entry in sorted order with a cursor:
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/users")
let r = env.begin_txn()
let entry = r.cursor_first()
while entry != nil {
print("{entry["key"]} = {entry["value"]}")
entry = r.cursor_next()
}
r.abort()
Stage tentative writes, then discard them by aborting so the environment stays unchanged:
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/users")
let txn = env.begin_txn()
txn.put("user:tmp", "scratch")
if txn.exists("user:tmp") {
print("staged, but not committing")
}
txn.abort()
Open or create a database environment
Opens (or creates) a database environment at the given path string. The path is stored for reference but the current implementation uses in-memory storage — it does not write to disk at that path.
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/mydb")
Start a new transaction
Begins a new transaction. The transaction receives a snapshot of all committed data at the time it is created, providing read isolation from concurrent changes.
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/mydb")
let txn = env.begin_txn()
txn.put("key1", "value1")
txn.commit()
Get environment statistics
Returns environment statistics as a table with entries (total committed key count) and total_bytes (sum of all key and value byte lengths).
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/mydb")
let stats = env.stat()
print("Entries: {stats["entries"]} Bytes: {stats["total_bytes"]}")
Write a key-value pair in a transaction
Writes a key-value pair into the transaction's pending write set. The value can be a string or bytes. Changes are not visible to other transactions until commit is called.
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/mydb")
let txn = env.begin_txn()
txn.put("user:1", "Alice")
txn.put("user:2", "Bob")
txn.commit()
Read a value by key in a transaction
Reads the value for key within the transaction view (pending writes take priority over the snapshot). Returns nil if the key does not exist or was deleted in this transaction.
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/mydb")
let w = env.begin_txn()
w.put("greeting", "hello")
w.commit()
let r = env.begin_txn()
let val = r.get("greeting")
r.abort()
Within a single transaction a put is visible to a later get even before
commit, because pending writes shadow the snapshot:
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/mydb")
let txn = env.begin_txn()
txn.put("draft", "v1")
print(txn.get("draft"))
txn.abort()
Mark a key deleted in a transaction
Marks key as deleted in the transaction's write set. The deletion is applied to the environment on commit.
let txn = env.begin_txn()
txn.delete("user:1")
txn.commit()
Commit and apply all transaction writes
Applies all pending writes from this transaction to the environment. After commit the transaction is finalized and cannot be used again.
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/mydb")
let txn = env.begin_txn()
txn.put("a", "1")
txn.put("b", "2")
txn.commit()
let stats = env.stat()
print("Entries after commit: {stats["entries"]}")
Discard all pending transaction writes
Discards all pending writes in this transaction. The environment is unchanged. After abort the transaction is finalized and cannot be used again.
let txn = env.begin_txn()
txn.put("temp", "scratch")
txn.abort()
Check if a key exists in the transaction view
Returns true if key is present in the transaction's effective view (snapshot plus pending writes).
let txn = env.begin_txn()
if txn.exists("user:1") {
print("Found user:1")
}
txn.abort()
Count entries visible in the transaction
Returns the total number of entries visible in the transaction's effective view.
let txn = env.begin_txn()
print("Entries: {txn.count()}")
txn.abort()
List all keys visible in the transaction
Returns all keys visible in the transaction's effective view as a sorted array.
let txn = env.begin_txn()
let all_keys = txn.keys()
print("Keys: {all_keys}")
txn.abort()
Move cursor to first entry
Positions the cursor at the first (smallest) key and returns a {key, value} table. Returns nil if the store is empty.
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/mydb")
let w = env.begin_txn()
w.put("a", "1")
w.put("b", "2")
w.commit()
let r = env.begin_txn()
let first = r.cursor_first()
print("First key: {first["key"]}")
r.abort()
Advance cursor to next entry
Advances the cursor to the next entry and returns {key, value}. Returns nil when past the last entry.
let r = env.begin_txn()
let entry = r.cursor_first()
while entry != nil {
print("{entry["key"]}")
entry = r.cursor_next()
}
r.abort()
Move cursor to last entry
Positions the cursor at the last (largest) key and returns {key, value}. Returns nil if the store is empty.
let r = env.begin_txn()
let last = r.cursor_last()
r.abort()
Move cursor to previous entry
Moves the cursor to the previous entry and returns {key, value}. Returns nil when before the first entry.
let r = env.begin_txn()
let last = r.cursor_last()
let prev = r.cursor_prev()
r.abort()
Iterate entries within a key range
Returns all entries whose keys fall in the inclusive range [start, end] as an array of {key, value} tables, in sorted order.
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/mydb")
let w = env.begin_txn()
w.put("user:1", "Alice")
w.put("user:2", "Bob")
w.put("user:3", "Carol")
w.commit()
let r = env.begin_txn()
let page = r.cursor_range("user:1", "user:2")
r.abort()
Because keys are sorted lexicographically, a shared prefix makes range scans act like a "starts with" query when you pair the prefix with a high upper bound:
use plugin lmdb::{LmdbEnv}
let env = LmdbEnv.new("/tmp/mydb")
let w = env.begin_txn()
w.put("log:2026-06-01", "a")
w.put("log:2026-06-02", "b")
w.put("metric:cpu", "99")
w.commit()
let r = env.begin_txn()
let logs = r.cursor_range("log:", "log:~")
print("matched {logs} log entries")
r.abort()