Introduce transactions

This commit is contained in:
Olivier 'reivilibre' 2022-03-24 19:17:23 +00:00
parent fdd82b2fef
commit b01fe7f892
3 changed files with 53 additions and 5 deletions

View File

@ -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<Txn<RO>> {
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<Txn<RW>> {
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<R>(&self, func: impl FnOnce(&Txn<RW>) -> anyhow::Result<R>) -> anyhow::Result<R> {
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(())
}
}

View File

@ -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 {

View File

@ -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<T: ByteWrapper> ByteWrapper for CompressorWrapper<T> {
}
}
impl<T: ByteWrapper> ByteWrapper for Arc<T> {
type Item = T::Item;
fn load_from_db_bytes(&self, bytes: &[u8]) -> anyhow::Result<Self::Item> {
(&self as &T).load_from_db_bytes(bytes)
}
fn dump_to_db_bytes(&self, item: &Self::Item) -> anyhow::Result<Vec<u8>> {
(&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>;