11# LMDB.jl
22
3- Julia bindings for [ LMDB] ( http://www.lmdb.tech/doc/ ) , the
4- Lightning Memory-Mapped Database — an embedded, memory-mapped, ACID
5- key-value store developed by Symas for OpenLDAP. It is small, fast, and
6- persists to disk while reading at near in-memory speeds.
3+ [ ![ CI] ( https://github.com/JuliaDatabases/LMDB.jl/actions/workflows/CI.yml/badge.svg )] ( https://github.com/JuliaDatabases/LMDB.jl/actions/workflows/CI.yml )
4+ [ ![ codecov] ( https://codecov.io/gh/JuliaDatabases/LMDB.jl/branch/main/graph/badge.svg )] ( https://codecov.io/gh/JuliaDatabases/LMDB.jl )
5+ [ ![ Stable] ( https://img.shields.io/badge/docs-stable-blue.svg )] ( https://JuliaDatabases.github.io/LMDB.jl/stable )
6+ [ ![ Dev] ( https://img.shields.io/badge/docs-dev-blue.svg )] ( https://JuliaDatabases.github.io/LMDB.jl/dev )
7+
8+ Julia bindings for [ LMDB] ( http://www.lmdb.tech/doc/ ) , the Lightning
9+ Memory-Mapped Database: An embedded, memory-mapped, ACID key-value store
10+ developed by Symas for OpenLDAP. Small, fast, persisted to disk, and reads at
11+ near in-memory speeds.
712
813``` julia
914using Pkg; Pkg. add (" LMDB" )
1015```
1116
12- ## Three layers
13-
14- LMDB.jl exposes three tiers, each with a clear consumer:
15-
16- ```
17- Tier 3 LMDBDict — `AbstractDict` over a single LMDB file.
18- Tier 2 Environment, … — Julian wrappers: handles, txns, cursors, dicts.
19- Tier 1 mdb_*, MDB_* — raw bindings + status-code constants.
20- ```
17+ ## Using LMDB.jl
2118
22- Tier 3 is the easy mode. Tier 2 is what most users want. Tier 1 is for
23- power users who need to integrate with custom data layouts or skip
24- allocations on hot paths — its functions auto-throw on non-zero status,
25- and an ` unchecked_* ` companion is available for callers that need to
26- inspect the raw status code.
19+ LMDB.jl exposes the same database through three surfaces:
2720
28- ### Tier 3 — ` LMDBDict `
21+ - ** High-level interface** : ` LMDBDict <: AbstractDict ` , an
22+ ` AbstractDict{K,V} ` over a single LMDB file. Standard library
23+ machinery (` merge! ` , ` filter! ` , ` pairs ` , iteration, …) works out
24+ of the box. Reach for this when you want a persistent ` Dict ` .
25+ - ** Julia wrappers** : ` Environment ` , ` Transaction ` , ` DBI ` , ` Cursor ` .
26+ Julia-shaped wrappers around handles, transactions, and cursors,
27+ with finalizers, ` do ` -block forms, etc. Use this when you want
28+ explicit transactions.
29+ - ** C API** : ` LMDB.mdb_* ` and ` LMDB.MDB_* ` . Raw ` ccall ` bindings and
30+ status-code constants. Use this when the Julia wrappers don't expose
31+ a particular API or you want to inspect status codes directly.
2932
30- ` LMDBDict{K,V} <: AbstractDict{K,V} ` , so the standard library does most
31- of the work — ` merge! ` , ` filter! ` , ` pairs ` , ` == ` , ` hash ` , ` keys ` ,
32- ` values ` , lazy iteration — all come for free:
33+ ### ` LMDBDict `
3334
3435``` julia
3536using LMDB
4950close (d)
5051```
5152
52- Constructor kwargs: ` mapsize ` , ` readers ` , ` dbs ` , ` readonly ` , ` rdahead ` .
53- The env is opened with ` MDB_NOTLS ` so multiple read txns can coexist on
54- one thread — needed for interleaved reads or task-parallel access.
55-
56- ### Tier 2 — explicit env / txn / cursor
53+ ### Julia wrappers
5754
5855``` julia
5956using LMDB
6663 put! (txn, dbi, " k1" , " hello" )
6764 put! (txn, dbi, " k2" , [1.0 , 2.0 , 3.0 ])
6865
69- @show LMDB. tryget (txn, dbi, " k1" , String) # "hello"
66+ @show LMDB. tryget (txn, dbi, " k1" , String)
7067 @show LMDB. get (txn, dbi, " missing" , String, " default" )
71- @show LMDB. stat (txn, dbi). ms_entries # 2
68+ @show LMDB. stat (txn, dbi). entries
7269 end
7370 end
7471
75- # Cursor walk: zero-copy access to raw MDB_val refs .
72+ # Cursor walk over the LMDB-owned mmap (zero-copy access) .
7673 start (env; flags = MDB_RDONLY) do txn
7774 open (txn) do dbi
7875 open (txn, dbi) do cur
79- LMDB. walk (cur) do k_ref, v_ref
80- println (LMDB . mbd_unpack (String, k_ref) )
76+ LMDB. walk (cur, String, String ) do k, v
77+ println (k, " => " , v )
8178 end
8279 end
8380 end
@@ -87,20 +84,24 @@ finally
8784end
8885```
8986
90- Status-code matchers are in ` LMDBError ` :
87+ The package decodes ` String ` , ` Vector{T} ` for any bitstype ` T ` , and the
88+ primitive numeric types out of the box. To plug in a custom representation,
89+ define a ` Base.read(io::IO, ::Type{T}) ` method; it will be picked up by ` tryget `
90+ / ` get ` / ` walk(f, cur, K, V) ` and the cursor accessors ` key ` /` value ` /` item ` .
91+ Status-code matchers live on ` LMDBError ` :
9192
9293``` julia
9394try
9495 LMDB. get (txn, dbi, " missing" , String)
9596catch e
9697 e isa LMDBError && LMDB. is_notfound (e) || rethrow ()
97- # …
98+ # treat as missing
9899end
99100```
100101
101- ### Tier 1 — raw bindings
102+ ### C API bindings
102103
103- The bindings are ` LMDB.mdb_* ` ; constants like ` LMDB.MDB_NOTLS ` ,
104+ The bindings are ` LMDB.mdb_* ` ; constants like ` LMDB.MDB_NOTLS ` and
104105` LMDB.MDB_NOTFOUND ` are public-but-unexported. Status-returning
105106bindings have an auto-throwing default and an ` unchecked_* ` companion:
106107
@@ -114,7 +115,7 @@ LMDB.mdb_env_set_maxreaders(env, Cuint(510))
114115LMDB. mdb_env_set_mapsize (env, Csize_t (1 << 30 ))
115116LMDB. mdb_env_open (env, " /tmp/mydb" ,
116117 LMDB. MDB_NOTLS | LMDB. MDB_NORDAHEAD,
117- Cushort (0o644 ))
118+ LMDB . mode_t (0o644 ))
118119
119120# Inspect the raw status code (e.g. for MDB_NOTFOUND):
120121ret = LMDB. unchecked_mdb_get (txn, dbi, key, val_ref)
@@ -126,4 +127,3 @@ ret == 0 || throw(LMDB.LMDBError(ret))
126127
127128- LMDB upstream: < https://github.com/LMDB/lmdb >
128129- LMDB API docs: < http://www.lmdb.tech/doc/ >
129- - Julia LMDB.jl issues / PRs: this repository.
0 commit comments