aboutsummaryrefslogtreecommitdiff
path: root/src/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/db')
-rw-r--r--src/db/lib.rs114
-rw-r--r--src/db/sled_adapter.rs89
-rw-r--r--src/db/test.rs21
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());