Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ Rust bindings for libmdbx (MDBX database). Crate name: `signet-libmdbx`.

## Crate Mandates

- You MUST NOT expose raw pointers to MDBX types outside of unsafe modules.
- You MUST NOT expose raw pointers to MDBX types via getters.
- You MUST maintain zero-copy semantics for read operations in all new
interfaces.
- You MUST read and respect `SAFETY` comments throughout the codebase.
- You MUST NOT introduce new dependencies without approval.
- All FFI calls MUST be made in the `ops` module.
- All access of the ops module must be done within a `with_txn_ptr` closure.

## MDBX Synchronization Model

When making changes to this codebase you MUST remember and conform to the MDBX
synchronization model for transactions and cursors. Access to raw pointers MUST
be mediated via the `TxAccess` trait. The table below summarizes the
transaction types and their access models.
be mediated via the `TxAccess` trait.

## Key Types

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "signet-libmdbx"
description = "Idiomatic and safe MDBX wrapper"
version = "0.7.0"
version = "0.8.0"
edition = "2024"
rust-version = "1.92"
license = "MIT OR Apache-2.0"
Expand Down
16 changes: 11 additions & 5 deletions benches/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mod utils;

use crate::utils::{create_ro_sync, create_ro_unsync};
use criterion::{Criterion, criterion_group, criterion_main};
use signet_libmdbx::{DatabaseFlags, Environment, WriteFlags};
use signet_libmdbx::{DatabaseFlags, DupItem, Environment, WriteFlags};
use std::hint::black_box;
use tempfile::{TempDir, tempdir};

Expand Down Expand Up @@ -42,8 +42,11 @@ fn bench_iter_dupfixed(c: &mut Criterion) {
b.iter(|| {
let mut cursor = txn.cursor(db).unwrap();
let mut count = 0u32;
for result in cursor.iter_dupfixed_start::<[u8; 3], VALUE_SIZE>().unwrap() {
let (_key, value) = result.unwrap();
for result in cursor.iter_dupfixed_start::<[u8; 3], [u8; VALUE_SIZE]>().unwrap() {
let item = result.unwrap();
let value = match item {
DupItem::NewKey(_, v) | DupItem::SameKey(v) => v,
};
black_box(value);
count += 1;
}
Expand Down Expand Up @@ -82,8 +85,11 @@ fn bench_iter_dupfixed_sync(c: &mut Criterion) {
b.iter(|| {
let mut cursor = txn.cursor(db).unwrap();
let mut count = 0u32;
for result in cursor.iter_dupfixed_start::<[u8; 3], VALUE_SIZE>().unwrap() {
let (_key, value) = result.unwrap();
for result in cursor.iter_dupfixed_start::<[u8; 3], [u8; VALUE_SIZE]>().unwrap() {
let item = result.unwrap();
let value = match item {
DupItem::NewKey(_, v) | DupItem::SameKey(v) => v,
};
black_box(value);
count += 1;
}
Expand Down
21 changes: 21 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,26 @@
//! [`Tx::open_db`]: crate::tx::Tx::open_db
//! [`Tx::create_db`]: crate::tx::Tx::create_db
//!
//! # Cursor Iterators
//!
//! Cursors provide several iterator types for traversing databases. The
//! iterator to use depends on your database flags and access pattern.
//!
//! | Iterator | Cursor Methods | Yields | Description |
//! |----------|----------------|--------|-------------|
//! | [`Iter`] | `iter_start`, `iter_from` | `(Key, Value)` | Forward iteration over all key-value pairs. |
//! | [`IterDup`] | `iter_dup_start`, `iter_dup_from` | [`DupItem`] | Flat iteration over DUPSORT tables. Yields `NewKey` for first value of each key, `SameKey` for subsequent. |
//! | [`IterDupOfKey`] | `iter_dup_of` | `Value` | Single-key iteration over DUPSORT duplicate values. |
//! | [`IterDupFixed`] | `iter_dupfixed_start`, `iter_dupfixed_from` | [`DupItem`] | Flat iteration over DUPFIXED tables using page-based access. |
//! | [`IterDupFixedOfKey`] | `iter_dupfixed_of` | `Value` | Single-key iteration over DUPFIXED values. Exact `size_hint()`. |
//!
//! [`Iter`]: crate::tx::iter::Iter
//! [`IterDup`]: crate::tx::iter::IterDup
//! [`IterDupOfKey`]: crate::tx::iter::IterDupOfKey
//! [`IterDupFixed`]: crate::tx::iter::IterDupFixed
//! [`IterDupFixedOfKey`]: crate::tx::iter::IterDupFixedOfKey
//! [`DupItem`]: crate::tx::iter::DupItem
//!
//! # Custom Zero-copy Deserialization with [`TableObject`]
//!
//! Implement [`TableObject`] to decode custom types directly from the
Expand Down Expand Up @@ -161,6 +181,7 @@ pub use sys::{Environment, EnvironmentBuilder, Geometry, Info, Stat};

pub mod tx;
pub use tx::aliases::{TxSync, TxUnsync};
pub use tx::iter::DupItem;
pub use tx::{CommitLatency, Cursor, Database, Ro, RoSync, Rw, RwSync, TransactionKind};

#[cfg(test)]
Expand Down
78 changes: 51 additions & 27 deletions src/tx/aliases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
PtrSync, PtrUnsync,
cursor::Cursor,
r#impl::Tx,
iter::{Iter, IterDupFixed, IterDupFixedOfKey},
iter::{Iter, IterDup, IterDupFixed, IterDupFixedOfKey, IterDupOfKey},
},
};
use std::{borrow::Cow, sync::Arc};
Expand Down Expand Up @@ -65,17 +65,41 @@ pub type RwCursorUnsync<'tx> = Cursor<'tx, Rw>;
pub type IterKeyVals<'tx, 'cur, K, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
Iter<'tx, 'cur, K, Key, Value, { ffi::MDBX_NEXT }>;

/// An iterator over the key/value pairs in an MDBX `DUPSORT` with duplicate
/// keys, yielding the first value for each key.
///
/// See the [`Iter`] documentation for more details.
pub type IterDupKeys<'tx, 'cur, K, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
Iter<'tx, 'cur, K, Key, Value, { ffi::MDBX_NEXT_NODUP }>;
// --- DUPSORT iterator aliases ---

/// An iterator over the key/value pairs in an MDBX `DUPSORT`, yielding each
/// duplicate value for a specific key.
pub type IterDupVals<'tx, 'cur, K, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
Iter<'tx, 'cur, K, Key, Value, { ffi::MDBX_NEXT_DUP }>;
/// A flat DUPSORT iterator for a synchronized read-only transaction.
pub type RoDupIterSync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterDup<'tx, 'cur, RoSync, Key, Value>;

/// A flat DUPSORT iterator for a synchronized read-write transaction.
pub type RwDupIterSync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterDup<'tx, 'cur, RwSync, Key, Value>;

/// A flat DUPSORT iterator for an unsynchronized read-only transaction.
pub type RoDupIterUnsync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterDup<'tx, 'cur, Ro, Key, Value>;

/// A flat DUPSORT iterator for an unsynchronized read-write transaction.
pub type RwDupIterUnsync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterDup<'tx, 'cur, Rw, Key, Value>;

/// A single-key DUPSORT iterator for a synchronized read-only transaction.
pub type RoDupIterOfKeySync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
IterDupOfKey<'tx, 'cur, RoSync, Value>;

/// A single-key DUPSORT iterator for a synchronized read-write transaction.
pub type RwDupIterOfKeySync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
IterDupOfKey<'tx, 'cur, RwSync, Value>;

/// A single-key DUPSORT iterator for an unsynchronized read-only transaction.
pub type RoDupIterOfKeyUnsync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
IterDupOfKey<'tx, 'cur, Ro, Value>;

/// A single-key DUPSORT iterator for an unsynchronized read-write transaction.
pub type RwDupIterOfKeyUnsync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
IterDupOfKey<'tx, 'cur, Rw, Value>;

// --- Transaction-level iterator aliases ---

/// A key-value iterator for a synchronized read-only transaction.
pub type RoIterSync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
Expand All @@ -94,33 +118,33 @@ pub type RwIterUnsync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterKeyVals<'tx, 'cur, Rw, Key, Value>;

/// A flattening DUPFIXED iterator for a synchronized read-only transaction.
pub type RoDupFixedIterSync<'tx, 'cur, Key = Cow<'tx, [u8]>, const VALUE_SIZE: usize = 0> =
IterDupFixed<'tx, 'cur, RoSync, Key, VALUE_SIZE>;
pub type RoDupFixedIterSync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterDupFixed<'tx, 'cur, RoSync, Key, Value>;

/// A flattening DUPFIXED iterator for a synchronized read-write transaction.
pub type RwDupFixedIterSync<'tx, 'cur, Key = Cow<'tx, [u8]>, const VALUE_SIZE: usize = 0> =
IterDupFixed<'tx, 'cur, RwSync, Key, VALUE_SIZE>;
pub type RwDupFixedIterSync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterDupFixed<'tx, 'cur, RwSync, Key, Value>;

/// A flattening DUPFIXED iterator for an unsynchronized read-only transaction.
pub type RoDupFixedIterUnsync<'tx, 'cur, Key = Cow<'tx, [u8]>, const VALUE_SIZE: usize = 0> =
IterDupFixed<'tx, 'cur, Ro, Key, VALUE_SIZE>;
pub type RoDupFixedIterUnsync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterDupFixed<'tx, 'cur, Ro, Key, Value>;

/// A flattening DUPFIXED iterator for an unsynchronized read-write transaction.
pub type RwDupFixedIterUnsync<'tx, 'cur, Key = Cow<'tx, [u8]>, const VALUE_SIZE: usize = 0> =
IterDupFixed<'tx, 'cur, Rw, Key, VALUE_SIZE>;
pub type RwDupFixedIterUnsync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterDupFixed<'tx, 'cur, Rw, Key, Value>;

/// A single-key DUPFIXED iterator for a synchronized read-only transaction.
pub type RoDupFixedIterOfKeySync<'tx, 'cur, const VALUE_SIZE: usize = 0> =
IterDupFixedOfKey<'tx, 'cur, RoSync, VALUE_SIZE>;
pub type RoDupFixedIterOfKeySync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
IterDupFixedOfKey<'tx, 'cur, RoSync, Value>;

/// A single-key DUPFIXED iterator for a synchronized read-write transaction.
pub type RwDupFixedIterOfKeySync<'tx, 'cur, const VALUE_SIZE: usize = 0> =
IterDupFixedOfKey<'tx, 'cur, RwSync, VALUE_SIZE>;
pub type RwDupFixedIterOfKeySync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
IterDupFixedOfKey<'tx, 'cur, RwSync, Value>;

/// A single-key DUPFIXED iterator for an unsynchronized read-only transaction.
pub type RoDupFixedIterOfKeyUnsync<'tx, 'cur, const VALUE_SIZE: usize = 0> =
IterDupFixedOfKey<'tx, 'cur, Ro, VALUE_SIZE>;
pub type RoDupFixedIterOfKeyUnsync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
IterDupFixedOfKey<'tx, 'cur, Ro, Value>;

/// A single-key DUPFIXED iterator for an unsynchronized read-write transaction.
pub type RwDupFixedIterOfKeyUnsync<'tx, 'cur, const VALUE_SIZE: usize = 0> =
IterDupFixedOfKey<'tx, 'cur, Rw, VALUE_SIZE>;
pub type RwDupFixedIterOfKeyUnsync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
IterDupFixedOfKey<'tx, 'cur, Rw, Value>;
Loading