diff options
Diffstat (limited to 'src/db')
-rw-r--r-- | src/db/lib.rs | 114 | ||||
-rw-r--r-- | src/db/sled_adapter.rs | 89 | ||||
-rw-r--r-- | src/db/test.rs | 21 |
3 files changed, 162 insertions, 62 deletions
diff --git a/src/db/lib.rs b/src/db/lib.rs index 4e400a1d..75c6ffa2 100644 --- a/src/db/lib.rs +++ b/src/db/lib.rs @@ -3,26 +3,31 @@ pub mod sled_adapter; #[cfg(test)] pub mod test; +use core::ops::{Bound, RangeBounds}; + use std::borrow::Cow; use std::sync::Arc; use arc_swap::ArcSwapOption; +use err_derive::Error; #[derive(Clone)] pub struct Db(pub(crate) Arc<dyn IDb>); -#[derive(Clone)] +#[derive(Clone, Copy)] pub struct Transaction<'a>(pub(crate) &'a dyn ITx<'a>); #[derive(Clone)] pub struct Tree(pub(crate) Arc<dyn IDb>, pub(crate) usize); pub type Value<'a> = Cow<'a, [u8]>; -pub type ValueIter<'a> = Box<dyn std::iter::Iterator<Item = Result<(Value<'a>, Value<'a>)>> + 'a>; +pub type ValueIter<'a> = + Box<dyn std::iter::Iterator<Item = Result<(Value<'a>, Value<'a>)>> + Send + Sync + 'a>; // ---- -#[derive(Debug)] +#[derive(Debug, Error)] +#[error(display = "{}", _0)] pub struct Error(Cow<'static, str>); pub type Result<T> = std::result::Result<T, Error>; @@ -43,14 +48,14 @@ impl<E> From<Error> for TxError<E> { // ---- impl Db { - pub fn tree<S: AsRef<str>>(&self, name: S) -> Result<Tree> { - let tree_id = self.0.tree(name.as_ref())?; + pub fn open_tree<S: AsRef<str>>(&self, name: S) -> Result<Tree> { + let tree_id = self.0.open_tree(name.as_ref())?; Ok(Tree(self.0.clone(), tree_id)) } pub fn transaction<R, E, F>(&self, fun: F) -> TxResult<R, E> where - F: Fn(Transaction<'_>) -> TxResult<R, E> + Send + Sync, + F: Fn(Transaction<'_>) -> TxResult<R, E>, R: Send + Sync, E: Send + Sync, { @@ -83,20 +88,50 @@ impl Db { } impl Tree { + pub fn db(&self) -> Db { + Db(self.0.clone()) + } + pub fn get<'a, T: AsRef<[u8]>>(&'a self, key: T) -> Result<Option<Value<'a>>> { self.0.get(self.1, key.as_ref()) } - pub fn put<T: AsRef<[u8]>, U: AsRef<[u8]>>(&self, key: T, value: U) -> Result<()> { - self.0.put(self.1, key.as_ref(), value.as_ref()) + pub fn len(&self) -> Result<usize> { + self.0.len(self.1) + } + + pub fn insert<T: AsRef<[u8]>, U: AsRef<[u8]>>(&self, key: T, value: U) -> Result<()> { + self.0.insert(self.1, key.as_ref(), value.as_ref()) } - pub fn iter<'a>(&'a self, reverse: bool) -> Result<ValueIter<'a>> { - self.0.range(self.1, None, reverse) + pub fn remove<'a, T: AsRef<[u8]>>(&'a self, key: T) -> Result<bool> { + self.0.remove(self.1, key.as_ref()) } - pub fn range<'a, T: AsRef<[u8]>>(&'a self, start: T, reverse: bool) -> Result<ValueIter<'a>> { - self.0.range(self.1, Some(start.as_ref()), reverse) + pub fn iter<'a>(&'a self) -> Result<ValueIter<'a>> { + self.0.iter(self.1) + } + pub fn iter_rev<'a>(&'a self) -> Result<ValueIter<'a>> { + self.0.iter_rev(self.1) + } + + pub fn range<'a, K, R>(&'a self, range: R) -> Result<ValueIter<'a>> + where + K: AsRef<[u8]>, + R: RangeBounds<K>, + { + let sb = range.start_bound(); + let eb = range.end_bound(); + self.0.range(self.1, get_bound(sb), get_bound(eb)) + } + pub fn range_rev<'a, K, R>(&'a self, range: R) -> Result<ValueIter<'a>> + where + K: AsRef<[u8]>, + R: RangeBounds<K>, + { + let sb = range.start_bound(); + let eb = range.end_bound(); + self.0.range_rev(self.1, get_bound(sb), get_bound(eb)) } } @@ -105,8 +140,17 @@ impl<'a> Transaction<'a> { self.0.get(tree.1, key.as_ref()) } - pub fn put<T: AsRef<[u8]>, U: AsRef<[u8]>>(&self, tree: &Tree, key: T, value: U) -> Result<()> { - self.0.put(tree.1, key.as_ref(), value.as_ref()) + pub fn insert<T: AsRef<[u8]>, U: AsRef<[u8]>>( + &self, + tree: &Tree, + key: T, + value: U, + ) -> Result<()> { + self.0.insert(tree.1, key.as_ref(), value.as_ref()) + } + + pub fn remove<T: AsRef<[u8]>>(&self, tree: &Tree, key: T) -> Result<bool> { + self.0.remove(tree.1, key.as_ref()) } #[must_use] @@ -131,15 +175,28 @@ impl<'a> Transaction<'a> { // ---- Internal interfaces pub(crate) trait IDb: Send + Sync { - fn tree(&self, name: &str) -> Result<usize>; + fn open_tree(&self, name: &str) -> Result<usize>; fn get<'a>(&'a self, tree: usize, key: &[u8]) -> Result<Option<Value<'a>>>; - fn put(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()>; - fn range<'a>( + fn len(&self, tree: usize) -> Result<usize>; + + fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()>; + fn remove(&self, tree: usize, key: &[u8]) -> Result<bool>; + + fn iter<'a>(&'a self, tree: usize) -> Result<ValueIter<'a>>; + fn iter_rev<'a>(&'a self, tree: usize) -> Result<ValueIter<'a>>; + + fn range<'a, 'r>( + &'a self, + tree: usize, + low: Bound<&'r [u8]>, + high: Bound<&'r [u8]>, + ) -> Result<ValueIter<'a>>; + fn range_rev<'a, 'r>( &'a self, tree: usize, - start: Option<&[u8]>, - reverse: bool, + low: Bound<&'r [u8]>, + high: Bound<&'r [u8]>, ) -> Result<ValueIter<'a>>; fn transaction(&self, f: &dyn ITxFn) -> TxResult<(), ()>; @@ -147,10 +204,11 @@ pub(crate) trait IDb: Send + Sync { pub(crate) trait ITx<'a> { fn get(&self, tree: usize, key: &[u8]) -> Result<Option<Value<'a>>>; - fn put(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()>; + fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()>; + fn remove(&self, tree: usize, key: &[u8]) -> Result<bool>; } -pub(crate) trait ITxFn: Send + Sync { +pub(crate) trait ITxFn { fn try_on<'a>(&'a self, tx: &'a dyn ITx<'a>) -> TxFnResult; } @@ -162,7 +220,7 @@ enum TxFnResult { struct TxFn<F, R, E> where - F: Fn(Transaction<'_>) -> TxResult<R, E> + Send + Sync, + F: Fn(Transaction<'_>) -> TxResult<R, E>, R: Send + Sync, E: Send + Sync, { @@ -172,7 +230,7 @@ where impl<F, R, E> ITxFn for TxFn<F, R, E> where - F: Fn(Transaction<'_>) -> TxResult<R, E> + Send + Sync, + F: Fn(Transaction<'_>) -> TxResult<R, E>, R: Send + Sync, E: Send + Sync, { @@ -187,3 +245,13 @@ where retval } } + +// ---- + +fn get_bound<K: AsRef<[u8]>>(b: Bound<&K>) -> Bound<&[u8]> { + match b { + Bound::Included(v) => Bound::Included(v.as_ref()), + Bound::Excluded(v) => Bound::Excluded(v.as_ref()), + Bound::Unbounded => Bound::Unbounded, + } +} diff --git a/src/db/sled_adapter.rs b/src/db/sled_adapter.rs index 6e375f03..b1da1c2b 100644 --- a/src/db/sled_adapter.rs +++ b/src/db/sled_adapter.rs @@ -1,3 +1,5 @@ +use core::ops::Bound; + use std::collections::HashMap; use std::sync::{Arc, RwLock}; @@ -42,7 +44,7 @@ impl SledDb { } impl IDb for SledDb { - fn tree(&self, name: &str) -> Result<usize> { + fn open_tree(&self, name: &str) -> Result<usize> { let mut trees = self.trees.write().unwrap(); if let Some(i) = trees.1.get(name) { Ok(*i) @@ -60,42 +62,63 @@ impl IDb for SledDb { Ok(tree.get(key)?.map(|v| v.to_vec().into())) } - fn put(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> { + fn remove(&self, tree: usize, key: &[u8]) -> Result<bool> { + let tree = self.get_tree(tree)?; + Ok(tree.remove(key)?.is_some()) + } + + fn len(&self, tree: usize) -> Result<usize> { + let tree = self.get_tree(tree)?; + Ok(tree.len()) + } + + fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> { let tree = self.get_tree(tree)?; tree.insert(key, value)?; Ok(()) } - fn range<'a>( + fn iter<'a>(&'a self, tree: usize) -> Result<ValueIter<'a>> { + let tree = self.get_tree(tree)?; + Ok(Box::new(tree.iter().map(|v| { + v.map(|(x, y)| (x.to_vec().into(), y.to_vec().into())) + .map_err(Into::into) + }))) + } + + fn iter_rev<'a>(&'a self, tree: usize) -> Result<ValueIter<'a>> { + let tree = self.get_tree(tree)?; + Ok(Box::new(tree.iter().rev().map(|v| { + v.map(|(x, y)| (x.to_vec().into(), y.to_vec().into())) + .map_err(Into::into) + }))) + } + + fn range<'a, 'r>( &'a self, tree: usize, - start: Option<&[u8]>, - reverse: bool, + low: Bound<&'r [u8]>, + high: Bound<&'r [u8]>, ) -> Result<ValueIter<'a>> { let tree = self.get_tree(tree)?; - if reverse { - match start { - Some(start) => Ok(Box::new(tree.range(..=start).rev().map(|v| { - v.map(|(x, y)| (x.to_vec().into(), y.to_vec().into())) - .map_err(Into::into) - }))), - None => Ok(Box::new(tree.iter().rev().map(|v| { - v.map(|(x, y)| (x.to_vec().into(), y.to_vec().into())) - .map_err(Into::into) - }))), - } - } else { - match start { - Some(start) => Ok(Box::new(tree.range(start..).map(|v| { - v.map(|(x, y)| (x.to_vec().into(), y.to_vec().into())) - .map_err(Into::into) - }))), - None => Ok(Box::new(tree.iter().map(|v| { - v.map(|(x, y)| (x.to_vec().into(), y.to_vec().into())) - .map_err(Into::into) - }))), - } - } + Ok(Box::new(tree.range::<&'r [u8], _>((low, high)).map(|v| { + v.map(|(x, y)| (x.to_vec().into(), y.to_vec().into())) + .map_err(Into::into) + }))) + } + fn range_rev<'a, 'r>( + &'a self, + tree: usize, + low: Bound<&'r [u8]>, + high: Bound<&'r [u8]>, + ) -> Result<ValueIter<'a>> { + let tree = self.get_tree(tree)?; + Ok(Box::new(tree.range::<&'r [u8], _>((low, high)).rev().map( + |v| { + v.map(|(x, y)| (x.to_vec().into(), y.to_vec().into())) + .map_err(Into::into) + }, + ))) } fn transaction(&self, f: &dyn ITxFn) -> TxResult<(), ()> { @@ -162,7 +185,7 @@ impl<'a> ITx<'a> for SledTx<'a> { Ok(tmp.map(|v| v.to_vec().into())) } - fn put(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> { + fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> { let tree = self .trees .get(tree) @@ -170,4 +193,12 @@ impl<'a> ITx<'a> for SledTx<'a> { self.save_error(tree.insert(key, value))?; Ok(()) } + + fn remove(&self, tree: usize, key: &[u8]) -> Result<bool> { + let tree = self + .trees + .get(tree) + .ok_or(Error("invalid tree id".into()))?; + Ok(self.save_error(tree.remove(key))?.is_some()) + } } diff --git a/src/db/test.rs b/src/db/test.rs index 7e389271..69e1d12c 100644 --- a/src/db/test.rs +++ b/src/db/test.rs @@ -3,21 +3,22 @@ use crate::*; use crate::sled_adapter::SledDb; fn test_suite(db: Db) -> Result<()> { - let tree = db.tree("tree")?; + let tree = db.open_tree("tree")?; let ka: &[u8] = &b"test"[..]; let kb: &[u8] = &b"zwello"[..]; + let kint: &[u8] = &b"tz"[..]; let va: &[u8] = &b"plop"[..]; let vb: &[u8] = &b"plip"[..]; let vc: &[u8] = &b"plup"[..]; - tree.put(ka, va)?; + tree.insert(ka, va)?; assert_eq!(tree.get(ka)?, Some(va.into())); let res = db.transaction::<_, (), _>(|tx| { assert_eq!(tx.get(&tree, ka)?, Some(va.into())); - tx.put(&tree, ka, vb)?; + tx.insert(&tree, ka, vb)?; assert_eq!(tx.get(&tree, ka)?, Some(vb.into())); @@ -29,7 +30,7 @@ fn test_suite(db: Db) -> Result<()> { let res = db.transaction::<(), _, _>(|tx| { assert_eq!(tx.get(&tree, ka)?, Some(vb.into())); - tx.put(&tree, ka, vc)?; + tx.insert(&tree, ka, vc)?; assert_eq!(tx.get(&tree, ka)?, Some(vc.into())); @@ -38,27 +39,27 @@ fn test_suite(db: Db) -> Result<()> { assert!(matches!(res, Err(TxError::Abort(42)))); assert_eq!(tree.get(ka)?, Some(vb.into())); - let mut iter = tree.iter(false)?; + let mut iter = tree.iter()?; assert_eq!(iter.next().unwrap().unwrap(), (ka.into(), vb.into())); assert!(iter.next().is_none()); - tree.put(kb, vc)?; + tree.insert(kb, vc)?; assert_eq!(tree.get(kb)?, Some(vc.into())); - let mut iter = tree.iter(false)?; + let mut iter = tree.iter()?; assert_eq!(iter.next().unwrap().unwrap(), (ka.into(), vb.into())); assert_eq!(iter.next().unwrap().unwrap(), (kb.into(), vc.into())); assert!(iter.next().is_none()); - let mut iter = tree.range("tz", false)?; + let mut iter = tree.range(kint..)?; assert_eq!(iter.next().unwrap().unwrap(), (kb.into(), vc.into())); assert!(iter.next().is_none()); - let mut iter = tree.range("tz", true)?; + let mut iter = tree.range_rev(..kint)?; assert_eq!(iter.next().unwrap().unwrap(), (ka.into(), vb.into())); assert!(iter.next().is_none()); - let mut iter = tree.iter(true)?; + let mut iter = tree.iter_rev()?; assert_eq!(iter.next().unwrap().unwrap(), (kb.into(), vc.into())); assert_eq!(iter.next().unwrap().unwrap(), (ka.into(), vb.into())); assert!(iter.next().is_none()); |