LeanLmdb (lean_lmdb v0.3.0)
View SourceA lean, binary-first Elixir wrapper for LMDB.
Environments are shared by canonical path within one BEAM OS process. Opaque environment and immutable named-database handles may live across calls; transactions and cursors never do. Keys and values are raw binaries and read results are copied into BEAM-owned binaries.
Example
iex> {name, version} = LeanLmdb.native_version()
iex> {name, Version.parse!(version).major}
{"lean_lmdb", 0}
Summary
Types
An ordered operation accepted by write_batch/2.
The expected state accepted by compare_exchange/4.
The replacement accepted by compare_exchange/4.
LMDB synchronization behavior selected when an environment is opened.
Validated options accepted by open/2.
A stable public error reason.
An option accepted by scan/2.
Functions
Checks the LMDB reader table and clears slots left by terminated processes.
Atomically compares a key's current state and applies a replacement on match.
Creates a named binary database, or reopens it when it already exists.
Deletes key if present.
Gets the value for key.
Returns deterministic lifecycle information for an environment or database.
Returns the tuple {"lean_lmdb", version} without accessing LMDB or the filesystem.
Opens an LMDB environment, sharing native state for its canonical path.
Opens an existing named binary database.
Stores value under key, overwriting any prior value.
Returns the raw binary database wrapped by a codec database.
Returns process-local registry counts and prunes stale weak entries.
Returns one bounded page of key/value pairs in ascending binary-key order.
Forces the environment's pending data and metadata buffers to durable storage.
Creates an opt-in value-codec view over a raw database handle.
Applies an ordered list of puts and deletes atomically across named databases.
Types
@type batch_operation() :: {:put, LeanLmdb.Database.t(), binary(), binary()} | {:put, LeanLmdb.CodecDatabase.t(), binary(), term()} | {:delete, LeanLmdb.Database.t() | LeanLmdb.CodecDatabase.t(), binary()}
An ordered operation accepted by write_batch/2.
@type compare_expected() :: :missing | binary()
The expected state accepted by compare_exchange/4.
@type compare_replacement() :: :delete | {:put, binary()}
The replacement accepted by compare_exchange/4.
@type durability() :: :sync | :no_meta_sync | :no_sync
LMDB synchronization behavior selected when an environment is opened.
@type open_option() :: {:map_size, pos_integer()} | {:max_dbs, pos_integer()} | {:max_readers, pos_integer()} | {:read_only, boolean()} | {:create, boolean()} | {:durability, durability()} | {:fixed_map, boolean()} | {:read_ahead, boolean()}
Validated options accepted by open/2.
@type reason() :: :database_create_failed | :database_not_found | :database_open_failed | :environment_open_failed | :incompatible_environment_options | :invalid_database | :invalid_database_name | :invalid_environment | :invalid_key | :invalid_value | :io_error | :database_error | :map_full | :map_resized | :readers_full | :transaction_full | :out_of_memory | :invalid_environment_options | :invalid_batch | :batch_too_large | :mixed_environments | :invalid_expected | :invalid_replacement | :invalid_mode | :invalid_limit | :invalid_max_bytes | :row_too_large | :invalid_continuation | :stale_continuation | :invalid_path | :path_not_found | :read_only | :resource_id_exhausted | :transaction_failed | :sync_failed | :invalid_value_codec | :codec_encode_failed | :codec_decode_failed | :codec_mismatch | :unsupported_codec_version | :non_deterministic_codec | :invalid_batch_writer_options | :batch_writer_overloaded | :batch_writer_stopping | :batch_writer_worker_failed | :batch_writer_unknown_outcome | {:invalid_option, atom()}
A stable public error reason.
@type scan_option() :: {:prefix, binary()} | {:from, binary() | nil} | {:to, binary() | nil} | {:from_inclusive, boolean()} | {:to_inclusive, boolean()} | {:limit, 1..10000} | {:max_bytes, 1..67_108_864} | {:continuation, binary() | nil}
An option accepted by scan/2.
Functions
@spec clear_stale_readers(LeanLmdb.Environment.t()) :: {:ok, non_neg_integer()} | {:error, reason()}
Checks the LMDB reader table and clears slots left by terminated processes.
Returns {:ok, cleared_count}. Active readers are never cleared. This is
backed by heed's Env::clear_stale_readers and may be called while the
environment is in use. Invalid handles and native failures return {:error, reason}.
@spec compare_exchange( LeanLmdb.Database.t() | LeanLmdb.CodecDatabase.t(), binary(), compare_expected() | term(), compare_replacement() | {:put, term()} ) :: :ok | {:conflict, :missing | term()} | {:error, reason()}
Atomically compares a key's current state and applies a replacement on match.
:missing is distinct from an expected empty binary. A mismatch returns the
exact current state as {:conflict, :missing} or {:conflict, binary} and
never mutates the database. Missing deletes after a successful comparison are
idempotent. A match returns :ok; malformed arguments and native failures
return {:error, reason}. Conflict binaries are copied before return.
Codec handles compare logical values by deterministic encoded envelope bytes
and decode conflicts. Non-deterministic codecs return
{:error, :non_deterministic_codec}; codec versions/options must match the
representation already stored.
@spec create_database(LeanLmdb.Environment.t(), binary()) :: {:ok, LeanLmdb.Database.t()} | {:error, reason()}
Creates a named binary database, or reopens it when it already exists.
Names must contain 1..511 bytes of valid UTF-8 and may not contain NUL.
Returns {:ok, database} or {:error, reason}; read-only environments cannot
create databases. The immutable database handle retains its environment.
@spec delete(LeanLmdb.Database.t() | LeanLmdb.CodecDatabase.t(), binary()) :: :ok | {:error, reason()}
Deletes key if present.
Deletion is idempotent: both present and missing keys return :ok. Validation,
read-only, and LMDB failures return {:error, reason}.
@spec get(LeanLmdb.Database.t() | LeanLmdb.CodecDatabase.t(), binary()) :: {:ok, binary() | term()} | :not_found | {:error, reason()}
Gets the value for key.
Raw database handles return a copied binary. Codec database handles validate
the stored envelope and decode a logical term after the native transaction
ends. Returns {:ok, value} when present and :not_found when missing. Empty
raw values are therefore distinct from missing keys. Keys must be non-empty
binaries no larger than LMDB's runtime maximum key size. Native and codec
failures return {:error, reason}; no zero-copy view escapes the call.
@spec info( LeanLmdb.Environment.t() | LeanLmdb.Database.t() | LeanLmdb.CodecDatabase.t() ) :: map() | {:error, :invalid_environment}
Returns deterministic lifecycle information for an environment or database.
Environment maps contain :resource_id, canonical :path, :map_size,
:max_dbs, :max_readers, :read_only, :durability, :fixed_map, and
:read_ahead; database maps additionally contain :name. Invalid handles return
{:error, :invalid_environment}.
Returns the tuple {"lean_lmdb", version} without accessing LMDB or the filesystem.
@spec open(Path.t(), [open_option()]) :: {:ok, LeanLmdb.Environment.t()} | {:error, reason()}
Opens an LMDB environment, sharing native state for its canonical path.
The path is canonicalized after optional creation, so relative components and
symlinks resolve to the same identity. Defaults are a 64 MiB map, 16 named
databases, 126 readers, writable access, create: true, durability: :sync,
fixed_map: false, and read_ahead: true.
map_size must be between 1 MiB and 1 TiB and divisible by the operating
system page size; max_dbs is limited to 1..1024 and max_readers to
1..4096. A read-only environment cannot be created.
durability: :sync uses LMDB's fully synchronized default. :no_meta_sync
preserves database integrity but a system crash may undo the latest committed
transaction. :no_sync omits commit-time buffer flushes; a system crash can
lose transactions and, on a filesystem that reorders writes, can corrupt the
derived database. Call sync/1 to force pending buffers to durable storage.
fixed_map: true enables experimental MDB_FIXEDMAP. It can fail when the
recorded virtual address is unavailable and every process opening that
environment must use compatible settings. It is never enabled implicitly.
read_ahead: false requests LMDB's MDB_NORDAHEAD performance hint. It may
help random reads when the database is larger than RAM, can hurt sequential
scans, and has no effect on Windows.
Repeats must use the same effective map size, limits, read mode, durability,
fixed-map, and read-ahead settings; create only controls path/open existence
behavior.
Returns {:ok, environment} or {:error, reason}. The map never grows
automatically.
@spec open_database(LeanLmdb.Environment.t(), binary()) :: {:ok, LeanLmdb.Database.t()} | {:error, reason()}
Opens an existing named binary database.
Names follow the same UTF-8, length, and NUL restrictions as
create_database/2. Returns {:ok, database}, {:error, :database_not_found}, or another documented lifecycle error.
@spec put(LeanLmdb.Database.t() | LeanLmdb.CodecDatabase.t(), binary(), term()) :: :ok | {:error, reason()}
Stores value under key, overwriting any prior value.
Raw handles require binary keys and values and perform no serialization.
Codec handles keep keys unchanged and encode/envelope the logical value in the
caller before entering the NIF. Returns :ok after commit or {:error, reason} without a partial commit.
@spec raw_database(LeanLmdb.CodecDatabase.t()) :: LeanLmdb.Database.t() | {:error, :invalid_database}
Returns the raw binary database wrapped by a codec database.
Raw access deliberately bypasses envelope and codec validation and is intended for diagnostics and explicit migrations.
@spec registry_info() :: %{ live: non_neg_integer(), stale: non_neg_integer(), total: non_neg_integer() }
Returns process-local registry counts and prunes stale weak entries.
This exposes counts only; it never reveals native pointers. It is intended for
deterministic lifecycle diagnostics and tests. The returned map always has
non-negative :live, :stale, and :total counts.
@spec scan(LeanLmdb.Database.t() | LeanLmdb.CodecDatabase.t(), [scan_option()]) :: {:ok, [{binary(), term()}], :done | binary()} | {:error, reason()}
Returns one bounded page of key/value pairs in ascending binary-key order.
Raw handles return copied binary values. Codec handles decode copied envelopes
after the native scan ends. max_bytes always counts encoded key/value bytes,
not decoded BEAM heap size; codec implementations require independent decoded
expansion limits.
A scan is either a prefix scan (prefix: binary) or an explicit range scan.
Range endpoints default to nil; the lower endpoint is inclusive and the
upper endpoint exclusive by default. Prefix cannot be mixed with from, to,
or the inclusivity options. Prefixes and endpoints are at most 511 bytes. limit defaults to 100 (maximum 10,000) and
max_bytes defaults to 1 MiB (maximum 64 MiB), counting key plus value bytes.
The third result element is :done or an opaque continuation binary. Pass the
continuation with the same database and bounds to resume exclusively after
the last emitted key. Page limits may change while resuming. If the
first eligible row exceeds max_bytes, the call returns {:error, :row_too_large} and no rows, making the output byte budget a hard bound. Invalid options/tokens and
native read failures also return {:error, reason}. Pages do not share a
snapshot and all row/token bytes are copied before the call returns.
@spec sync(LeanLmdb.Environment.t()) :: :ok | {:error, reason()}
Forces the environment's pending data and metadata buffers to durable storage.
This calls LMDB's forced mdb_env_sync, even when the environment was opened
with durability: :no_sync or :no_meta_sync. It is intended for explicit
group-commit schedules such as a supervised timer. Writes can continue from
other processes while the dirty-I/O call runs; on return, LMDB reports that
all commits visible to that synchronization point have been flushed.
Returns :ok or {:error, reason}. Read-only and invalid handles are rejected.
@spec with_value_codec(LeanLmdb.Database.t(), module(), keyword()) :: {:ok, LeanLmdb.CodecDatabase.t()} | {:error, :invalid_database | :invalid_value_codec}
Creates an opt-in value-codec view over a raw database handle.
The codec module must implement LeanLmdb.ValueCodec. Its stable binary ID,
format version, determinism declaration, callback set, and options are
validated before an immutable LeanLmdb.CodecDatabase is returned. No stored
data is read or migrated by this function.
@spec write_batch(LeanLmdb.Environment.t(), [batch_operation()]) :: :ok | {:error, reason()}
Applies an ordered list of puts and deletes atomically across named databases.
Every database must belong to exactly the supplied environment. The complete
list is validated before one write transaction is opened, operations are
applied in list order, and missing deletes are idempotent. Empty batches are
valid no-ops. A batch is limited to 10,000 operations and 64 MiB of aggregate
encoded key and value bytes. All codec values are encoded before the native
call, so a callback failure leaves the complete mixed raw/codec batch
unexecuted. Returns :ok only after commit; validation, mixed environments,
read-only access, and LMDB failures return {:error, reason} with the
transaction aborted.