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
9 changes: 1 addition & 8 deletions 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.5.0"
version = "0.6.0"
edition = "2024"
rust-version = "1.92"
license = "MIT OR Apache-2.0"
Expand Down Expand Up @@ -40,13 +40,6 @@ smallvec = "1.15.1"
thiserror = "2.0.18"
tracing = "0.1.44"

dashmap = { version = "6.1.0", features = ["inline"], optional = true }

[features]
default = []
return-borrowed = []
read-tx-timeouts = ["dep:dashmap"]

[dev-dependencies]
criterion = "0.8.1"
proptest = "1"
Expand Down
58 changes: 32 additions & 26 deletions benches/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
mod utils;

use criterion::{Criterion, criterion_group, criterion_main};
use signet_libmdbx::{Cursor, ObjectLength, ReadResult, TransactionKind, ffi::*, tx::TxPtrAccess};
use signet_libmdbx::{Cursor, ObjectLength, ReadResult, TransactionKind, ffi::*};
use std::{hint::black_box, ptr};
use utils::*;

Expand Down Expand Up @@ -34,9 +34,7 @@ fn bench_get_seq_iter(c: &mut Criterion) {
count += 1;
}

fn iterate<K: TransactionKind, A: TxPtrAccess>(
cursor: &mut Cursor<K, A>,
) -> ReadResult<()> {
fn iterate<K: TransactionKind>(cursor: &mut Cursor<K>) -> ReadResult<()> {
let mut i = 0;
for result in cursor.iter::<ObjectLength, ObjectLength>() {
let (key_len, data_len) = result?;
Expand Down Expand Up @@ -107,7 +105,7 @@ fn bench_get_seq_for_loop(c: &mut Criterion) {
fn bench_get_seq_iter_single_thread(c: &mut Criterion) {
let n = 100;
let (_dir, env) = setup_bench_db(n);
let mut txn = create_ro_unsync(&env);
let txn = create_ro_unsync(&env);
let db = txn.open_db(None).unwrap();
// Note: setup_bench_db creates a named database which adds metadata to the
// main database, so actual item count is n + 1
Expand All @@ -131,9 +129,7 @@ fn bench_get_seq_iter_single_thread(c: &mut Criterion) {
count += 1;
}

fn iterate<K: TransactionKind, A: TxPtrAccess>(
cursor: &mut Cursor<K, A>,
) -> ReadResult<()> {
fn iterate<K: TransactionKind>(cursor: &mut Cursor<K>) -> ReadResult<()> {
let mut i = 0;
for result in cursor.iter::<ObjectLength, ObjectLength>() {
let (key_len, data_len) = result?;
Expand All @@ -154,7 +150,7 @@ fn bench_get_seq_iter_single_thread(c: &mut Criterion) {
fn bench_get_seq_cursor_single_thread(c: &mut Criterion) {
let n = 100;
let (_dir, env) = setup_bench_db(n);
let mut txn = create_ro_unsync(&env);
let txn = create_ro_unsync(&env);
let db = txn.open_db(None).unwrap();
// Note: setup_bench_db creates a named database which adds metadata to the
// main database, so actual item count is n + 1
Expand All @@ -177,7 +173,7 @@ fn bench_get_seq_cursor_single_thread(c: &mut Criterion) {
fn bench_get_seq_for_loop_single_thread(c: &mut Criterion) {
let n = 100;
let (_dir, env) = setup_bench_db(n);
let mut txn = create_ro_unsync(&env);
let txn = create_ro_unsync(&env);
let db = txn.open_db(None).unwrap();
// Note: setup_bench_db creates a named database which adds metadata to the
// main database, so actual item count is n + 1
Expand Down Expand Up @@ -205,9 +201,6 @@ fn bench_get_seq_raw(c: &mut Criterion) {
let n = 100;
let (_dir, env) = setup_bench_db(n);

let dbi = create_ro_sync(&env).open_db(None).unwrap().dbi();
let txn = create_ro_sync(&env);

let mut key = MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
let mut data = MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
let mut cursor: *mut MDBX_cursor = ptr::null_mut();
Expand All @@ -216,23 +209,36 @@ fn bench_get_seq_raw(c: &mut Criterion) {
// main database, so actual item count is n + 1
let actual_items = n + 1;

let txn = unsafe {
let mut txn: *mut MDBX_txn = ptr::null_mut();
env.with_raw_env_ptr(|env_ptr| {
txn = create_ro_raw(env_ptr);
});
txn
};

let mut dbi: MDBX_dbi = 0;
unsafe {
match mdbx_dbi_open(txn, ptr::null(), 0, &mut dbi) {
MDBX_SUCCESS | MDBX_RESULT_TRUE => {}
err => panic!("mdbx_dbi_open failed: {}", err),
}
};

c.bench_function("cursor::traverse::raw", |b| {
b.iter(|| unsafe {
txn.txn_execute(|txn| {
mdbx_cursor_open(txn, dbi, &raw mut cursor);
let mut i = 0;
let mut count = 0u32;
mdbx_cursor_open(txn, dbi, &raw mut cursor);
let mut i = 0;
let mut count = 0u32;

while mdbx_cursor_get(cursor, &raw mut key, &raw mut data, MDBX_NEXT) == 0 {
i += key.iov_len + data.iov_len;
count += 1;
}
while mdbx_cursor_get(cursor, &raw mut key, &raw mut data, MDBX_NEXT) == 0 {
i += key.iov_len + data.iov_len;
count += 1;
}

black_box(i);
assert_eq!(count, actual_items);
mdbx_cursor_close(cursor);
})
.unwrap();
black_box(i);
assert_eq!(count, actual_items);
mdbx_cursor_close(cursor);
})
});
}
Expand Down
86 changes: 57 additions & 29 deletions benches/db_open.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,62 +9,90 @@ use std::{hint::black_box, ptr};
/// Benchmark mdbx_dbi_flags_ex in isolation (on already-open DBI)
fn bench_dbi_flags_ex_only(c: &mut Criterion) {
let (_dir, env) = setup_bench_db(10);
let txn = env.begin_ro_txn().unwrap();
let db = txn.open_db(None).unwrap();
let dbi = db.dbi();

let txn = unsafe {
let mut txn: *mut MDBX_txn = ptr::null_mut();
env.with_raw_env_ptr(|env_ptr| {
txn = create_ro_raw(env_ptr);
});
txn
};

let mut dbi: MDBX_dbi = 0;
let flags = 0;
match unsafe { mdbx_dbi_open(txn, ptr::null(), flags, &mut dbi) } {
MDBX_SUCCESS | MDBX_RESULT_TRUE => {}
err => panic!("mdbx_dbi_open failed: {}", err),
};

c.bench_function("db_cache::ffi::flags", |b| {
b.iter(|| {
txn.txn_execute(|txn_ptr| unsafe {
let mut flags: u32 = 0;
let mut state: u32 = 0;
black_box(mdbx_dbi_flags_ex(txn_ptr.cast_const(), dbi, &mut flags, &mut state));
})
.unwrap();
let mut flags: u32 = 0;
let mut state: u32 = 0;
black_box(unsafe { mdbx_dbi_flags_ex(txn.cast_const(), dbi, &mut flags, &mut state) });
})
});
}

/// Baseline: just mdbx_dbi_open without flags_ex
fn bench_dbi_open_only(c: &mut Criterion) {
let (_dir, env) = setup_bench_db(10);
let txn = env.begin_ro_txn().unwrap();

let txn = unsafe {
let mut txn: *mut MDBX_txn = ptr::null_mut();
env.with_raw_env_ptr(|env_ptr| {
txn = create_ro_raw(env_ptr);
});
txn
};

c.bench_function("db_cache::ffi::open", |b| {
b.iter(|| {
txn.txn_execute(|txn_ptr| unsafe {
let mut dbi: MDBX_dbi = 0;
black_box(mdbx_dbi_open(txn_ptr, ptr::null(), 0, &mut dbi));
})
.unwrap();
let mut dbi: MDBX_dbi = 0;
let flags = 0;
black_box(match unsafe { mdbx_dbi_open(txn, ptr::null(), flags, &mut dbi) } {
MDBX_SUCCESS => false,
MDBX_RESULT_TRUE => true,
_ => panic!(),
});
})
});
}

/// Full open path: mdbx_dbi_open + mdbx_dbi_flags_ex
fn bench_dbi_open_with_flags_ex(c: &mut Criterion) {
let (_dir, env) = setup_bench_db(10);
let txn = env.begin_ro_txn().unwrap();

let txn = unsafe {
let mut txn: *mut MDBX_txn = ptr::null_mut();
env.with_raw_env_ptr(|env_ptr| {
txn = create_ro_raw(env_ptr);
});
txn
};

c.bench_function("db_cache::ffi::open_plus_flags", |b| {
b.iter(|| {
txn.txn_execute(|txn_ptr| unsafe {
let mut dbi: MDBX_dbi = 0;
mdbx_dbi_open(txn_ptr, ptr::null(), 0, &mut dbi);
let mut flags: u32 = 0;
let mut state: u32 = 0;
black_box(mdbx_dbi_flags_ex(txn_ptr.cast_const(), dbi, &mut flags, &mut state));
})
.unwrap();
})
let mut dbi: MDBX_dbi = 0;
let flags = 0;
black_box(match unsafe { mdbx_dbi_open(txn, ptr::null(), flags, &mut dbi) } {
MDBX_SUCCESS => false,
MDBX_RESULT_TRUE => true,
_ => panic!(),
});
let mut flags: u32 = 0;
let mut state: u32 = 0;
black_box(unsafe { mdbx_dbi_flags_ex(txn.cast_const(), dbi, &mut flags, &mut state) });
});
});
}

/// Benchmark cached DB opens (cache hits after first call)
fn bench_open_db_cached(c: &mut Criterion) {
let (_dir, env) = setup_bench_db(10);
let txn = env.begin_ro_txn().unwrap();

// Prime the cache
let txn = env.begin_ro_unsync().unwrap();
let _ = txn.open_db(None).unwrap();

c.bench_function("db_cache::unnamed::hit", |b| {
Expand All @@ -75,7 +103,7 @@ fn bench_open_db_cached(c: &mut Criterion) {
/// Benchmark uncached DB opens (always FFI call)
fn bench_open_db_no_cache(c: &mut Criterion) {
let (_dir, env) = setup_bench_db(10);
let txn = env.begin_ro_txn().unwrap();
let txn = env.begin_ro_unsync().unwrap();

c.bench_function("db_cache::unnamed::disabled", |b| {
b.iter(|| black_box(txn.open_db_no_cache(None).unwrap()))
Expand All @@ -85,7 +113,7 @@ fn bench_open_db_no_cache(c: &mut Criterion) {
/// Benchmark cached DB opens (cache hits after first call)
fn bench_open_db_cached_named(c: &mut Criterion) {
let (_dir, env) = setup_bench_db(10);
let txn = env.begin_ro_txn().unwrap();
let txn = env.begin_ro_unsync().unwrap();
// Prime the cache
let _ = txn.open_db(Some(NAMED_DB)).unwrap();

Expand All @@ -97,7 +125,7 @@ fn bench_open_db_cached_named(c: &mut Criterion) {
/// Benchmark uncached DB opens (always FFI call)
fn bench_open_db_no_cache_named(c: &mut Criterion) {
let (_dir, env) = setup_bench_db(10);
let txn = env.begin_ro_txn().unwrap();
let txn = env.begin_ro_unsync().unwrap();

c.bench_function("db_cache::named::disabled", |b| {
b.iter(|| black_box(txn.open_db_no_cache(Some(NAMED_DB)).unwrap()))
Expand Down
Loading