From 9e243625edd55fd89d82ac2f8d67082ecda0d442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 7 May 2025 21:47:52 +0200 Subject: [PATCH 1/4] Implement Send on Cursors so we can move them between threads --- heed/src/cursor.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/heed/src/cursor.rs b/heed/src/cursor.rs index b5d81e6d..de694965 100644 --- a/heed/src/cursor.rs +++ b/heed/src/cursor.rs @@ -1,4 +1,5 @@ use std::ops::{Deref, DerefMut}; +use std::ptr::NonNull; use std::{marker, mem, ptr}; use crate::mdb::error::mdb_result; @@ -6,7 +7,7 @@ use crate::mdb::ffi; use crate::*; pub struct RoCursor<'txn> { - cursor: *mut ffi::MDB_cursor, + cursor: NonNull, _marker: marker::PhantomData<&'txn ()>, } @@ -15,7 +16,7 @@ impl<'txn> RoCursor<'txn> { let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut(); let mut txn = txn.txn_ptr(); unsafe { mdb_result(ffi::mdb_cursor_open(txn.as_mut(), dbi, &mut cursor))? } - Ok(RoCursor { cursor, _marker: marker::PhantomData }) + Ok(RoCursor { cursor: NonNull::new(cursor).unwrap(), _marker: marker::PhantomData }) } pub fn current(&mut self) -> Result> { @@ -242,6 +243,8 @@ impl Drop for RoCursor<'_> { } } +unsafe impl Send for RoCursor<'_> {} + pub struct RwCursor<'txn> { cursor: RoCursor<'txn>, } From 62b1c53cb8f50517ba6d4f6253ee398c23b225a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 7 May 2025 22:11:04 +0200 Subject: [PATCH 2/4] Use NonNull ptr correctly --- heed/src/cursor.rs | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/heed/src/cursor.rs b/heed/src/cursor.rs index de694965..c06986bf 100644 --- a/heed/src/cursor.rs +++ b/heed/src/cursor.rs @@ -26,7 +26,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor on the first database key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor, + self.cursor.as_mut(), key_val.as_mut_ptr(), data_val.as_mut_ptr(), ffi::cursor_op::MDB_GET_CURRENT, @@ -53,7 +53,7 @@ impl<'txn> RoCursor<'txn> { MoveOperation::Dup => { unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor, + self.cursor.as_mut(), ptr::null_mut(), &mut ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() }, ffi::cursor_op::MDB_FIRST_DUP, @@ -67,7 +67,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor on the first database key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor, + self.cursor.as_mut(), key_val.as_mut_ptr(), data_val.as_mut_ptr(), flag, @@ -94,7 +94,7 @@ impl<'txn> RoCursor<'txn> { MoveOperation::Dup => { unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor, + self.cursor.as_mut(), ptr::null_mut(), &mut ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() }, ffi::cursor_op::MDB_LAST_DUP, @@ -108,7 +108,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor on the first database key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor, + self.cursor.as_mut(), key_val.as_mut_ptr(), data_val.as_mut_ptr(), flag, @@ -132,7 +132,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor to the specified key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor, + self.cursor.as_mut(), &mut key_val, &mut ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() }, ffi::cursor_op::MDB_SET, @@ -156,7 +156,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor to the specified key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor, + self.cursor.as_mut(), &mut key_val, data_val.as_mut_ptr(), ffi::cursor_op::MDB_SET_RANGE, @@ -187,7 +187,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor to the previous non-dup key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor, + self.cursor.as_mut(), key_val.as_mut_ptr(), data_val.as_mut_ptr(), flag, @@ -218,7 +218,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor to the next non-dup key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor, + self.cursor.as_mut(), key_val.as_mut_ptr(), data_val.as_mut_ptr(), flag, @@ -239,7 +239,7 @@ impl<'txn> RoCursor<'txn> { impl Drop for RoCursor<'_> { fn drop(&mut self) { - unsafe { ffi::mdb_cursor_close(self.cursor) } + unsafe { ffi::mdb_cursor_close(self.cursor.as_mut()) } } } @@ -269,7 +269,7 @@ impl<'txn> RwCursor<'txn> { /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html pub unsafe fn del_current(&mut self) -> Result { // Delete the current entry - let result = mdb_result(ffi::mdb_cursor_del(self.cursor.cursor, 0)); + let result = mdb_result(ffi::mdb_cursor_del(self.cursor.cursor.as_mut(), 0)); match result { Ok(()) => Ok(true), @@ -307,7 +307,7 @@ impl<'txn> RwCursor<'txn> { // Modify the pointed data let result = mdb_result(ffi::mdb_cursor_put( - self.cursor.cursor, + self.cursor.cursor.as_mut(), &mut key_val, &mut data_val, ffi::MDB_CURRENT, @@ -347,8 +347,12 @@ impl<'txn> RwCursor<'txn> { let mut reserved = ffi::reserve_size_val(data_size); let flags = ffi::MDB_RESERVE | flags.bits(); - let result = - mdb_result(ffi::mdb_cursor_put(self.cursor.cursor, &mut key_val, &mut reserved, flags)); + let result = mdb_result(ffi::mdb_cursor_put( + self.cursor.cursor.as_mut(), + &mut key_val, + &mut reserved, + flags, + )); let found = match result { Ok(()) => true, @@ -395,7 +399,7 @@ impl<'txn> RwCursor<'txn> { // Modify the pointed data let result = mdb_result(ffi::mdb_cursor_put( - self.cursor.cursor, + self.cursor.cursor.as_mut(), &mut key_val, &mut data_val, flags.bits(), From 8a43f1d4481b0da99dc68699651b79e8ef07de2d Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Wed, 16 Jul 2025 14:14:45 +0200 Subject: [PATCH 3/4] Prefer using NonNull::as_ptr than NonNull::as_mut --- heed/src/cursor.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/heed/src/cursor.rs b/heed/src/cursor.rs index c06986bf..a26479d6 100644 --- a/heed/src/cursor.rs +++ b/heed/src/cursor.rs @@ -26,7 +26,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor on the first database key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor.as_mut(), + self.cursor.as_ptr(), key_val.as_mut_ptr(), data_val.as_mut_ptr(), ffi::cursor_op::MDB_GET_CURRENT, @@ -53,7 +53,7 @@ impl<'txn> RoCursor<'txn> { MoveOperation::Dup => { unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor.as_mut(), + self.cursor.as_ptr(), ptr::null_mut(), &mut ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() }, ffi::cursor_op::MDB_FIRST_DUP, @@ -67,7 +67,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor on the first database key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor.as_mut(), + self.cursor.as_ptr(), key_val.as_mut_ptr(), data_val.as_mut_ptr(), flag, @@ -94,7 +94,7 @@ impl<'txn> RoCursor<'txn> { MoveOperation::Dup => { unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor.as_mut(), + self.cursor.as_ptr(), ptr::null_mut(), &mut ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() }, ffi::cursor_op::MDB_LAST_DUP, @@ -108,7 +108,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor on the first database key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor.as_mut(), + self.cursor.as_ptr(), key_val.as_mut_ptr(), data_val.as_mut_ptr(), flag, @@ -132,7 +132,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor to the specified key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor.as_mut(), + self.cursor.as_ptr(), &mut key_val, &mut ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() }, ffi::cursor_op::MDB_SET, @@ -156,7 +156,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor to the specified key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor.as_mut(), + self.cursor.as_ptr(), &mut key_val, data_val.as_mut_ptr(), ffi::cursor_op::MDB_SET_RANGE, @@ -187,7 +187,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor to the previous non-dup key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor.as_mut(), + self.cursor.as_ptr(), key_val.as_mut_ptr(), data_val.as_mut_ptr(), flag, @@ -218,7 +218,7 @@ impl<'txn> RoCursor<'txn> { // Move the cursor to the next non-dup key let result = unsafe { mdb_result(ffi::mdb_cursor_get( - self.cursor.as_mut(), + self.cursor.as_ptr(), key_val.as_mut_ptr(), data_val.as_mut_ptr(), flag, @@ -239,7 +239,7 @@ impl<'txn> RoCursor<'txn> { impl Drop for RoCursor<'_> { fn drop(&mut self) { - unsafe { ffi::mdb_cursor_close(self.cursor.as_mut()) } + unsafe { ffi::mdb_cursor_close(self.cursor.as_ptr()) } } } From 25cacf88ee4f9a9f61cf0f68a62a763878583cdf Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Wed, 16 Jul 2025 14:15:57 +0200 Subject: [PATCH 4/4] Use NonNull::new_unchecked instead of unwraping a NonNull::new --- heed/src/cursor.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/heed/src/cursor.rs b/heed/src/cursor.rs index a26479d6..3a069142 100644 --- a/heed/src/cursor.rs +++ b/heed/src/cursor.rs @@ -16,7 +16,10 @@ impl<'txn> RoCursor<'txn> { let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut(); let mut txn = txn.txn_ptr(); unsafe { mdb_result(ffi::mdb_cursor_open(txn.as_mut(), dbi, &mut cursor))? } - Ok(RoCursor { cursor: NonNull::new(cursor).unwrap(), _marker: marker::PhantomData }) + Ok(RoCursor { + cursor: unsafe { NonNull::new_unchecked(cursor) }, + _marker: marker::PhantomData, + }) } pub fn current(&mut self) -> Result> {