diff --git a/src/environment.rs b/src/environment.rs index 8eee486..12de5b6 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -2,7 +2,7 @@ use crate::database::raw::{RawTable, RawTableTryBuilder}; use crate::database::wrapped::WrappedTable; use crate::wrapper::{ByteWrapper, ZeroCopyByteWrapper}; use anyhow::{ensure, Context}; -use libmdbx::{DatabaseFlags, Environment, WriteMap}; +use libmdbx::{DatabaseFlags, Environment, Transaction, TransactionKind, WriteMap, RO, RW}; use std::marker::PhantomData; use std::sync::Arc; @@ -57,4 +57,40 @@ impl Env { v_wrapper, }) } + + /// Begins a read-only transaction. + pub fn ro_txn(&self) -> anyhow::Result> { + let mdbx_txn = self.mdbx_env.begin_ro_txn()?; + Ok(Txn { mdbx_txn }) + } + + /// Begins a read-write transaction. This one has an awkward name because `rw_txn` is an easier + /// interface (insofar as you don't need to remember to `commit` yourself). + pub fn begin_rw_txn(&self) -> anyhow::Result> { + let mdbx_txn = self.mdbx_env.begin_rw_txn()?; + Ok(Txn { mdbx_txn }) + } + + /// Runs a transaction and commits for you, if the Result variant is `Ok(R)` (NOT `Err`). + /// This way, it's hard to forget to commit. + pub fn rw_txn(&self, func: impl FnOnce(&Txn) -> anyhow::Result) -> anyhow::Result { + let txn = self.begin_rw_txn()?; + let result = func(&txn)?; + txn.commit()?; + Ok(result) + } +} + +pub struct Txn<'txn, K: TransactionKind> { + pub mdbx_txn: Transaction<'txn, K, WriteMap>, +} + +impl<'txn, K: TransactionKind> Txn<'txn, K> {} + +impl<'txn> Txn<'txn, RW> { + pub fn commit(self) -> anyhow::Result<()> { + // TODO bool here, find out what it means and maybe pass up + self.mdbx_txn.commit()?; + Ok(()) + } } diff --git a/src/lib.rs b/src/lib.rs index 941c1af..9d410d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ -pub(crate) mod database; -pub(crate) mod environment; -pub(crate) mod wrapper; +pub mod database; +pub mod environment; +pub mod wrapper; #[cfg(test)] mod tests { diff --git a/src/wrapper.rs b/src/wrapper.rs index 8630b2b..23d95af 100644 --- a/src/wrapper.rs +++ b/src/wrapper.rs @@ -2,7 +2,7 @@ use anyhow::anyhow; use serde::de::DeserializeOwned; use serde::Serialize; use std::marker::PhantomData; -use std::sync::Mutex; +use std::sync::{Arc, Mutex}; use zstd::bulk::{Compressor, Decompressor}; pub trait ByteWrapper { @@ -57,6 +57,18 @@ impl ByteWrapper for CompressorWrapper { } } +impl ByteWrapper for Arc { + type Item = T::Item; + + fn load_from_db_bytes(&self, bytes: &[u8]) -> anyhow::Result { + (&self as &T).load_from_db_bytes(bytes) + } + + fn dump_to_db_bytes(&self, item: &Self::Item) -> anyhow::Result> { + (&self as &T).dump_to_db_bytes(item) + } +} + pub trait ZeroCopyByteWrapper { fn as_byte_slice(&self) -> &[u8]; fn from_byte_slice(bytes: &[u8]) -> anyhow::Result<&Self>;