Files
nanoreth/crates/storage/db/src/implementation/mdbx/tx.rs
2022-12-09 23:14:07 -08:00

133 lines
4.0 KiB
Rust

//! Transaction wrapper for libmdbx-sys.
use super::cursor::Cursor;
use crate::{
table::{Compress, DupSort, Encode, Table},
tables::utils::decode_one,
transaction::{DbTx, DbTxGAT, DbTxMut, DbTxMutGAT},
Error,
};
use reth_libmdbx::{EnvironmentKind, Transaction, TransactionKind, WriteFlags, RW};
use std::marker::PhantomData;
/// Wrapper for the libmdbx transaction.
#[derive(Debug)]
pub struct Tx<'a, K: TransactionKind, E: EnvironmentKind> {
/// Libmdbx-sys transaction.
pub inner: Transaction<'a, K, E>,
}
impl<'env, K: TransactionKind, E: EnvironmentKind> Tx<'env, K, E> {
/// Creates new `Tx` object with a `RO` or `RW` transaction.
pub fn new<'a>(inner: Transaction<'a, K, E>) -> Self
where
'a: 'env,
{
Self { inner }
}
/// Gets this transaction ID.
pub fn id(&self) -> u64 {
self.inner.id()
}
/// Create db Cursor
pub fn new_cursor<T: Table>(&self) -> Result<Cursor<'env, K, T>, Error> {
Ok(Cursor {
inner: self
.inner
.cursor(
&self.inner.open_db(Some(T::NAME)).map_err(|e| Error::InitCursor(e.into()))?,
)
.map_err(|e| Error::InitCursor(e.into()))?,
table: T::NAME,
_dbi: PhantomData,
})
}
}
impl<'a, K: TransactionKind, E: EnvironmentKind> DbTxGAT<'a> for Tx<'_, K, E> {
type Cursor<T: Table> = Cursor<'a, K, T>;
type DupCursor<T: DupSort> = Cursor<'a, K, T>;
}
impl<'a, K: TransactionKind, E: EnvironmentKind> DbTxMutGAT<'a> for Tx<'_, K, E> {
type CursorMut<T: Table> = Cursor<'a, RW, T>;
type DupCursorMut<T: DupSort> = Cursor<'a, RW, T>;
}
impl<'tx, K: TransactionKind, E: EnvironmentKind> DbTx<'tx> for Tx<'tx, K, E> {
// Iterate over read only values in database.
fn cursor<T: Table>(&self) -> Result<<Self as DbTxGAT<'_>>::Cursor<T>, Error> {
self.new_cursor()
}
/// Iterate over read only values in database.
fn cursor_dup<T: DupSort>(&self) -> Result<<Self as DbTxGAT<'_>>::DupCursor<T>, Error> {
self.new_cursor()
}
fn commit(self) -> Result<bool, Error> {
self.inner.commit().map_err(|e| Error::Commit(e.into()))
}
fn get<T: Table>(&self, key: T::Key) -> Result<Option<<T as Table>::Value>, Error> {
self.inner
.get(
&self.inner.open_db(Some(T::NAME)).map_err(|e| Error::Read(e.into()))?,
key.encode().as_ref(),
)
.map_err(|e| Error::Read(e.into()))?
.map(decode_one::<T>)
.transpose()
}
}
impl<E: EnvironmentKind> DbTxMut<'_> for Tx<'_, RW, E> {
fn put<T: Table>(&self, key: T::Key, value: T::Value) -> Result<(), Error> {
self.inner
.put(
&self.inner.open_db(Some(T::NAME)).map_err(|e| Error::Write(e.into()))?,
&key.encode(),
&value.compress(),
WriteFlags::UPSERT,
)
.map_err(|e| Error::Write(e.into()))
}
fn delete<T: Table>(&self, key: T::Key, value: Option<T::Value>) -> Result<bool, Error> {
let mut data = None;
let value = value.map(Compress::compress);
if let Some(value) = &value {
data = Some(value.as_ref());
};
self.inner
.del(
&self.inner.open_db(Some(T::NAME)).map_err(|e| Error::Delete(e.into()))?,
key.encode(),
data,
)
.map_err(|e| Error::Delete(e.into()))
}
fn clear<T: Table>(&self) -> Result<(), Error> {
self.inner
.clear_db(&self.inner.open_db(Some(T::NAME)).map_err(|e| Error::Delete(e.into()))?)
.map_err(|e| Error::Delete(e.into()))?;
Ok(())
}
fn cursor_mut<T: Table>(&self) -> Result<<Self as DbTxMutGAT<'_>>::CursorMut<T>, Error> {
self.new_cursor()
}
fn cursor_dup_mut<T: DupSort>(
&self,
) -> Result<<Self as DbTxMutGAT<'_>>::DupCursorMut<T>, Error> {
self.new_cursor()
}
}