diff --git a/crates/storage/libmdbx-rs/src/environment.rs b/crates/storage/libmdbx-rs/src/environment.rs index 83860c18c7..2728fad4bb 100644 --- a/crates/storage/libmdbx-rs/src/environment.rs +++ b/crates/storage/libmdbx-rs/src/environment.rs @@ -129,6 +129,14 @@ impl Environment { self.inner.txn_manager.as_ref() } + /// Returns the manager that handles transaction messages. + /// + /// Requires [Mode::ReadWrite] and returns None otherwise. + #[inline] + pub(crate) fn ensure_txn_manager(&self) -> Result<&SyncSender> { + self.txn_manager().ok_or(Error::WriteTransactionUnsupportedInReadOnlyMode) + } + /// Create a read-only transaction for use with the environment. #[inline] pub fn begin_ro_txn(&self) -> Result> { @@ -138,7 +146,7 @@ impl Environment { /// Create a read-write transaction for use with the environment. This method will block while /// there are any other read-write transactions open on the environment. pub fn begin_rw_txn(&self) -> Result> { - let sender = self.txn_manager().ok_or(Error::WriteTransactionUnsupportedInReadOnlyMode)?; + let sender = self.ensure_txn_manager()?; let txn = loop { let (tx, rx) = sync_channel(0); sender diff --git a/crates/storage/libmdbx-rs/src/error.rs b/crates/storage/libmdbx-rs/src/error.rs index 250ca23cad..3b33caa865 100644 --- a/crates/storage/libmdbx-rs/src/error.rs +++ b/crates/storage/libmdbx-rs/src/error.rs @@ -1,6 +1,9 @@ use libc::c_int; use std::{ffi::CStr, fmt, result, str}; +/// An MDBX result. +pub type Result = result::Result; + /// An MDBX error kind. #[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)] pub enum Error { @@ -55,7 +58,12 @@ pub enum Error { Access, TooLarge, DecodeErrorLenDiff, + /// If the [Environment](crate::Environment) was opened with + /// [EnvironmentKind::WriteMap](crate::EnvironmentKind::WriteMap) flag, nested transactions are + /// not supported. NestedTransactionsUnsupportedWithWriteMap, + /// If the [Environment](crate::Environment) was opened with in read-only mode + /// [Mode::ReadOnly](crate::flags::Mode::ReadOnly), write transactions can't be opened.. WriteTransactionUnsupportedInReadOnlyMode, Other(i32), } @@ -125,12 +133,30 @@ impl Error { Error::Multival => ffi::MDBX_EMULTIVAL, Error::WannaRecovery => ffi::MDBX_WANNA_RECOVERY, Error::KeyMismatch => ffi::MDBX_EKEYMISMATCH, - Error::DecodeError => ffi::MDBX_EINVAL, + Error::DecodeErrorLenDiff | Error::DecodeError => ffi::MDBX_EINVAL, Error::Access => ffi::MDBX_EACCESS, Error::TooLarge => ffi::MDBX_TOO_LARGE, Error::BadSignature => ffi::MDBX_EBADSIGN, + Error::WriteTransactionUnsupportedInReadOnlyMode => ffi::MDBX_EACCESS, + Error::NestedTransactionsUnsupportedWithWriteMap => ffi::MDBX_EACCESS, Error::Other(err_code) => *err_code, - _ => unreachable!(), + } + } + + /// Returns the message for this error + pub fn as_str(&self) -> &str { + match self { + Self::DecodeErrorLenDiff => "mismatched data length", + Self::NestedTransactionsUnsupportedWithWriteMap => { + "nested transactions are not supported on an environment with writemap" + } + Self::WriteTransactionUnsupportedInReadOnlyMode => { + "write transactions are not supported on an environment opened in read-only mode" + } + _ => unsafe { + let err = ffi::mdbx_strerror(self.to_err_code()); + str::from_utf8_unchecked(CStr::from_ptr(err).to_bytes()) + }, } } } @@ -143,20 +169,11 @@ impl From for i32 { impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let value = match self { - Self::DecodeErrorLenDiff => "Mismatched data length", - _ => unsafe { - let err = ffi::mdbx_strerror(self.to_err_code()); - str::from_utf8_unchecked(CStr::from_ptr(err).to_bytes()) - }, - }; - write!(fmt, "{value}") + write!(fmt, "{}", self.as_str()) } } -/// An MDBX result. -pub type Result = result::Result; - +#[inline] pub fn mdbx_result(err_code: c_int) -> Result { match err_code { ffi::MDBX_SUCCESS => Ok(false), diff --git a/crates/storage/libmdbx-rs/src/transaction.rs b/crates/storage/libmdbx-rs/src/transaction.rs index 6d3615b208..60df280e69 100644 --- a/crates/storage/libmdbx-rs/src/transaction.rs +++ b/crates/storage/libmdbx-rs/src/transaction.rs @@ -189,7 +189,7 @@ where } else { let (sender, rx) = sync_channel(0); self.env() - .txn_manager() + .ensure_txn_manager() .unwrap() .send(TxnManagerMessage::Commit { tx: TxnPtr(txn), sender }) .unwrap(); @@ -319,7 +319,7 @@ where } else { let (sender, rx) = sync_channel(0); self.env - .txn_manager() + .ensure_txn_manager() .unwrap() .send(TxnManagerMessage::Abort { tx: TxnPtr(txn), sender }) .unwrap(); @@ -486,7 +486,7 @@ impl<'env> Transaction<'env, RW> { self.txn_execute(|txn| { let (tx, rx) = sync_channel(0); self.env() - .txn_manager() + .ensure_txn_manager() .unwrap() .send(TxnManagerMessage::Begin { parent: TxnPtr(txn),