Skip to content

lmdb

stable

Transactional 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, …}
16 functions Database
/ filter jk navigate Esc clear
Functions (16)
  1. LmdbEnv.new Open or create a database environment
  2. LmdbEnv.begin_txn Start a new transaction
  3. LmdbEnv.stat Get environment statistics
  4. LmdbTxn.put Write a key-value pair in a transaction
  5. LmdbTxn.get Read a value by key in a transaction
  6. LmdbTxn.delete Mark a key deleted in a transaction
  7. LmdbTxn.commit Commit and apply all transaction writes
  8. LmdbTxn.abort Discard all pending transaction writes
  9. LmdbTxn.exists Check if a key exists in the transaction view
  10. LmdbTxn.count Count entries visible in the transaction
  11. LmdbTxn.keys List all keys visible in the transaction
  12. LmdbTxn.cursor_first Move cursor to first entry
  13. LmdbTxn.cursor_next Advance cursor to next entry
  14. LmdbTxn.cursor_last Move cursor to last entry
  15. LmdbTxn.cursor_prev Move cursor to previous entry
  16. 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()
enespt-br