use std::borrow::Cow;
use std::ops::Deref;
use std::ptr::{self, NonNull};
use crate::envs::Env;
use crate::mdb::error::mdb_result;
use crate::mdb::ffi;
use crate::Result;
pub struct RoTxn<'e> {
pub(crate) txn: Option<NonNull<ffi::MDB_txn>>,
env: Cow<'e, Env>,
}
impl<'e> RoTxn<'e> {
pub(crate) fn new(env: &'e Env) -> Result<RoTxn<'e>> {
let mut txn: *mut ffi::MDB_txn = ptr::null_mut();
unsafe {
mdb_result(ffi::mdb_txn_begin(
env.env_mut_ptr().as_mut(),
ptr::null_mut(),
ffi::MDB_RDONLY,
&mut txn,
))?
};
Ok(RoTxn { txn: NonNull::new(txn), env: Cow::Borrowed(env) })
}
pub(crate) fn static_read_txn(env: Env) -> Result<RoTxn<'static>> {
let mut txn: *mut ffi::MDB_txn = ptr::null_mut();
unsafe {
mdb_result(ffi::mdb_txn_begin(
env.env_mut_ptr().as_mut(),
ptr::null_mut(),
ffi::MDB_RDONLY,
&mut txn,
))?
};
Ok(RoTxn { txn: NonNull::new(txn), env: Cow::Owned(env) })
}
pub(crate) fn env_mut_ptr(&self) -> NonNull<ffi::MDB_env> {
self.env.env_mut_ptr()
}
pub fn commit(mut self) -> Result<()> {
let mut txn = self.txn.take().unwrap();
let result = unsafe { mdb_result(ffi::mdb_txn_commit(txn.as_mut())) };
result.map_err(Into::into)
}
}
impl Drop for RoTxn<'_> {
fn drop(&mut self) {
if let Some(mut txn) = self.txn.take() {
unsafe { ffi::mdb_txn_abort(txn.as_mut()) }
}
}
}
#[cfg(feature = "read-txn-no-tls")]
unsafe impl Send for RoTxn<'_> {}
pub struct RwTxn<'p> {
pub(crate) txn: RoTxn<'p>,
}
impl<'p> RwTxn<'p> {
pub(crate) fn new(env: &'p Env) -> Result<RwTxn<'p>> {
let mut txn: *mut ffi::MDB_txn = ptr::null_mut();
unsafe {
mdb_result(ffi::mdb_txn_begin(
env.env_mut_ptr().as_mut(),
ptr::null_mut(),
0,
&mut txn,
))?
};
Ok(RwTxn { txn: RoTxn { txn: NonNull::new(txn), env: Cow::Borrowed(env) } })
}
pub(crate) fn nested(env: &'p Env, parent: &'p mut RwTxn) -> Result<RwTxn<'p>> {
let mut txn: *mut ffi::MDB_txn = ptr::null_mut();
let parent_ptr: *mut ffi::MDB_txn = unsafe { parent.txn.txn.unwrap().as_mut() };
unsafe {
mdb_result(ffi::mdb_txn_begin(env.env_mut_ptr().as_mut(), parent_ptr, 0, &mut txn))?
};
Ok(RwTxn { txn: RoTxn { txn: NonNull::new(txn), env: Cow::Borrowed(env) } })
}
pub(crate) fn env_mut_ptr(&self) -> NonNull<ffi::MDB_env> {
self.txn.env.env_mut_ptr()
}
pub fn commit(mut self) -> Result<()> {
let mut txn = self.txn.txn.take().unwrap();
let result = unsafe { mdb_result(ffi::mdb_txn_commit(txn.as_mut())) };
result.map_err(Into::into)
}
pub fn abort(mut self) {
let mut txn = self.txn.txn.take().unwrap();
unsafe { ffi::mdb_txn_abort(txn.as_mut()) }
}
}
impl<'p> Deref for RwTxn<'p> {
type Target = RoTxn<'p>;
fn deref(&self) -> &Self::Target {
&self.txn
}
}
#[cfg(master3)]
impl std::ops::DerefMut for RwTxn<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.txn
}
}