Skip to content

Commit 479c12f

Browse files
authored
refactor: make dupfixed iter runtime checked (#7)
* refactor: make dupfixed iter runtime checked * chore: finish refactor
1 parent b032a8e commit 479c12f

File tree

16 files changed

+931
-508
lines changed

16 files changed

+931
-508
lines changed

CLAUDE.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@ Rust bindings for libmdbx (MDBX database). Crate name: `signet-libmdbx`.
99

1010
## Crate Mandates
1111

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

1820
## MDBX Synchronization Model
1921

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

2526
## Key Types
2627

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "signet-libmdbx"
33
description = "Idiomatic and safe MDBX wrapper"
4-
version = "0.7.0"
4+
version = "0.8.0"
55
edition = "2024"
66
rust-version = "1.92"
77
license = "MIT OR Apache-2.0"

benches/iter.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ mod utils;
33

44
use crate::utils::{create_ro_sync, create_ro_unsync};
55
use criterion::{Criterion, criterion_group, criterion_main};
6-
use signet_libmdbx::{DatabaseFlags, Environment, WriteFlags};
6+
use signet_libmdbx::{DatabaseFlags, DupItem, Environment, WriteFlags};
77
use std::hint::black_box;
88
use tempfile::{TempDir, tempdir};
99

@@ -42,8 +42,11 @@ fn bench_iter_dupfixed(c: &mut Criterion) {
4242
b.iter(|| {
4343
let mut cursor = txn.cursor(db).unwrap();
4444
let mut count = 0u32;
45-
for result in cursor.iter_dupfixed_start::<[u8; 3], VALUE_SIZE>().unwrap() {
46-
let (_key, value) = result.unwrap();
45+
for result in cursor.iter_dupfixed_start::<[u8; 3], [u8; VALUE_SIZE]>().unwrap() {
46+
let item = result.unwrap();
47+
let value = match item {
48+
DupItem::NewKey(_, v) | DupItem::SameKey(v) => v,
49+
};
4750
black_box(value);
4851
count += 1;
4952
}
@@ -82,8 +85,11 @@ fn bench_iter_dupfixed_sync(c: &mut Criterion) {
8285
b.iter(|| {
8386
let mut cursor = txn.cursor(db).unwrap();
8487
let mut count = 0u32;
85-
for result in cursor.iter_dupfixed_start::<[u8; 3], VALUE_SIZE>().unwrap() {
86-
let (_key, value) = result.unwrap();
88+
for result in cursor.iter_dupfixed_start::<[u8; 3], [u8; VALUE_SIZE]>().unwrap() {
89+
let item = result.unwrap();
90+
let value = match item {
91+
DupItem::NewKey(_, v) | DupItem::SameKey(v) => v,
92+
};
8793
black_box(value);
8894
count += 1;
8995
}

src/lib.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,26 @@
8686
//! [`Tx::open_db`]: crate::tx::Tx::open_db
8787
//! [`Tx::create_db`]: crate::tx::Tx::create_db
8888
//!
89+
//! # Cursor Iterators
90+
//!
91+
//! Cursors provide several iterator types for traversing databases. The
92+
//! iterator to use depends on your database flags and access pattern.
93+
//!
94+
//! | Iterator | Cursor Methods | Yields | Description |
95+
//! |----------|----------------|--------|-------------|
96+
//! | [`Iter`] | `iter_start`, `iter_from` | `(Key, Value)` | Forward iteration over all key-value pairs. |
97+
//! | [`IterDup`] | `iter_dup_start`, `iter_dup_from` | [`DupItem`] | Flat iteration over DUPSORT tables. Yields `NewKey` for first value of each key, `SameKey` for subsequent. |
98+
//! | [`IterDupOfKey`] | `iter_dup_of` | `Value` | Single-key iteration over DUPSORT duplicate values. |
99+
//! | [`IterDupFixed`] | `iter_dupfixed_start`, `iter_dupfixed_from` | [`DupItem`] | Flat iteration over DUPFIXED tables using page-based access. |
100+
//! | [`IterDupFixedOfKey`] | `iter_dupfixed_of` | `Value` | Single-key iteration over DUPFIXED values. Exact `size_hint()`. |
101+
//!
102+
//! [`Iter`]: crate::tx::iter::Iter
103+
//! [`IterDup`]: crate::tx::iter::IterDup
104+
//! [`IterDupOfKey`]: crate::tx::iter::IterDupOfKey
105+
//! [`IterDupFixed`]: crate::tx::iter::IterDupFixed
106+
//! [`IterDupFixedOfKey`]: crate::tx::iter::IterDupFixedOfKey
107+
//! [`DupItem`]: crate::tx::iter::DupItem
108+
//!
89109
//! # Custom Zero-copy Deserialization with [`TableObject`]
90110
//!
91111
//! Implement [`TableObject`] to decode custom types directly from the
@@ -161,6 +181,7 @@ pub use sys::{Environment, EnvironmentBuilder, Geometry, Info, Stat};
161181

162182
pub mod tx;
163183
pub use tx::aliases::{TxSync, TxUnsync};
184+
pub use tx::iter::DupItem;
164185
pub use tx::{CommitLatency, Cursor, Database, Ro, RoSync, Rw, RwSync, TransactionKind};
165186

166187
#[cfg(test)]

src/tx/aliases.rs

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
PtrSync, PtrUnsync,
77
cursor::Cursor,
88
r#impl::Tx,
9-
iter::{Iter, IterDupFixed, IterDupFixedOfKey},
9+
iter::{Iter, IterDup, IterDupFixed, IterDupFixedOfKey, IterDupOfKey},
1010
},
1111
};
1212
use std::{borrow::Cow, sync::Arc};
@@ -65,17 +65,41 @@ pub type RwCursorUnsync<'tx> = Cursor<'tx, Rw>;
6565
pub type IterKeyVals<'tx, 'cur, K, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
6666
Iter<'tx, 'cur, K, Key, Value, { ffi::MDBX_NEXT }>;
6767

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

75-
/// An iterator over the key/value pairs in an MDBX `DUPSORT`, yielding each
76-
/// duplicate value for a specific key.
77-
pub type IterDupVals<'tx, 'cur, K, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
78-
Iter<'tx, 'cur, K, Key, Value, { ffi::MDBX_NEXT_DUP }>;
70+
/// A flat DUPSORT iterator for a synchronized read-only transaction.
71+
pub type RoDupIterSync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
72+
IterDup<'tx, 'cur, RoSync, Key, Value>;
73+
74+
/// A flat DUPSORT iterator for a synchronized read-write transaction.
75+
pub type RwDupIterSync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
76+
IterDup<'tx, 'cur, RwSync, Key, Value>;
77+
78+
/// A flat DUPSORT iterator for an unsynchronized read-only transaction.
79+
pub type RoDupIterUnsync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
80+
IterDup<'tx, 'cur, Ro, Key, Value>;
81+
82+
/// A flat DUPSORT iterator for an unsynchronized read-write transaction.
83+
pub type RwDupIterUnsync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
84+
IterDup<'tx, 'cur, Rw, Key, Value>;
85+
86+
/// A single-key DUPSORT iterator for a synchronized read-only transaction.
87+
pub type RoDupIterOfKeySync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
88+
IterDupOfKey<'tx, 'cur, RoSync, Value>;
89+
90+
/// A single-key DUPSORT iterator for a synchronized read-write transaction.
91+
pub type RwDupIterOfKeySync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
92+
IterDupOfKey<'tx, 'cur, RwSync, Value>;
93+
94+
/// A single-key DUPSORT iterator for an unsynchronized read-only transaction.
95+
pub type RoDupIterOfKeyUnsync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
96+
IterDupOfKey<'tx, 'cur, Ro, Value>;
97+
98+
/// A single-key DUPSORT iterator for an unsynchronized read-write transaction.
99+
pub type RwDupIterOfKeyUnsync<'tx, 'cur, Value = Cow<'tx, [u8]>> =
100+
IterDupOfKey<'tx, 'cur, Rw, Value>;
101+
102+
// --- Transaction-level iterator aliases ---
79103

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

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

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

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

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

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

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

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

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

0 commit comments

Comments
 (0)