aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2022-06-02 15:25:24 +0200
committerAlex Auvolat <alex@adnab.me>2022-06-02 15:25:24 +0200
commit04901093e7315558bdc147d27adc3f56ec2c98a1 (patch)
treedf13d281a3bf6c44c1c4e6e1b9de89aa2f0b7cac
parentfd8d5c37f73d93a0cdfd8ab08f7447b0f6d3ce3e (diff)
downloadgarage-04901093e7315558bdc147d27adc3f56ec2c98a1.tar.gz
garage-04901093e7315558bdc147d27adc3f56ec2c98a1.zip
Implement iter() and range() on db
-rw-r--r--src/db/lib.rs15
-rw-r--r--src/db/sled_adapter.rs51
-rw-r--r--src/db/test.rs47
3 files changed, 98 insertions, 15 deletions
diff --git a/src/db/lib.rs b/src/db/lib.rs
index 0f23a9b4..4e400a1d 100644
--- a/src/db/lib.rs
+++ b/src/db/lib.rs
@@ -18,6 +18,7 @@ pub struct Transaction<'a>(pub(crate) &'a dyn ITx<'a>);
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>;
// ----
@@ -89,6 +90,14 @@ impl Tree {
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 iter<'a>(&'a self, reverse: bool) -> Result<ValueIter<'a>> {
+ self.0.range(self.1, None, reverse)
+ }
+
+ 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)
+ }
}
impl<'a> Transaction<'a> {
@@ -126,6 +135,12 @@ pub(crate) trait IDb: Send + Sync {
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>(
+ &'a self,
+ tree: usize,
+ start: Option<&[u8]>,
+ reverse: bool,
+ ) -> Result<ValueIter<'a>>;
fn transaction(&self, f: &dyn ITxFn) -> TxResult<(), ()>;
}
diff --git a/src/db/sled_adapter.rs b/src/db/sled_adapter.rs
index 617b4844..6e375f03 100644
--- a/src/db/sled_adapter.rs
+++ b/src/db/sled_adapter.rs
@@ -4,10 +4,11 @@ use std::sync::{Arc, RwLock};
use arc_swap::ArcSwapOption;
use sled::transaction::{
- ConflictableTransactionError, TransactionError, Transactional, TransactionalTree, UnabortableTransactionError
+ ConflictableTransactionError, TransactionError, Transactional, TransactionalTree,
+ UnabortableTransactionError,
};
-use crate::{Error, IDb, ITx, ITxFn, Result, TxError, TxFnResult, TxResult, Value, Db};
+use crate::{Db, Error, IDb, ITx, ITxFn, Result, TxError, TxFnResult, TxResult, Value, ValueIter};
impl From<sled::Error> for Error {
fn from(e: sled::Error) -> Error {
@@ -58,12 +59,45 @@ impl IDb for SledDb {
let tree = self.get_tree(tree)?;
Ok(tree.get(key)?.map(|v| v.to_vec().into()))
}
+
fn put(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> {
let tree = self.get_tree(tree)?;
tree.insert(key, value)?;
Ok(())
}
+ fn range<'a>(
+ &'a self,
+ tree: usize,
+ start: Option<&[u8]>,
+ reverse: bool,
+ ) -> 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)
+ }))),
+ }
+ }
+ }
+
fn transaction(&self, f: &dyn ITxFn) -> TxResult<(), ()> {
let trees = self.trees.read().unwrap();
let res = trees.0.transaction(|txtrees| {
@@ -76,7 +110,10 @@ impl IDb for SledDb {
assert!(tx.err.into_inner().is_none());
Ok(())
}
- TxFnResult::Abort => Err(ConflictableTransactionError::Abort(())),
+ TxFnResult::Abort => {
+ assert!(tx.err.into_inner().is_none());
+ Err(ConflictableTransactionError::Abort(()))
+ }
TxFnResult::Err => {
let err_arc = tx
.err
@@ -117,14 +154,18 @@ impl<'a> SledTx<'a> {
impl<'a> ITx<'a> for SledTx<'a> {
fn get(&self, tree: usize, key: &[u8]) -> Result<Option<Value<'a>>> {
- let tree = self.trees.get(tree)
+ let tree = self
+ .trees
+ .get(tree)
.ok_or(Error("invalid tree id".into()))?;
let tmp = self.save_error(tree.get(key))?;
Ok(tmp.map(|v| v.to_vec().into()))
}
fn put(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> {
- let tree = self.trees.get(tree)
+ let tree = self
+ .trees
+ .get(tree)
.ok_or(Error("invalid tree id".into()))?;
self.save_error(tree.insert(key, value))?;
Ok(())
diff --git a/src/db/test.rs b/src/db/test.rs
index f0e6c5de..7e389271 100644
--- a/src/db/test.rs
+++ b/src/db/test.rs
@@ -5,36 +5,63 @@ use crate::sled_adapter::SledDb;
fn test_suite(db: Db) -> Result<()> {
let tree = db.tree("tree")?;
+ let ka: &[u8] = &b"test"[..];
+ let kb: &[u8] = &b"zwello"[..];
let va: &[u8] = &b"plop"[..];
let vb: &[u8] = &b"plip"[..];
let vc: &[u8] = &b"plup"[..];
- tree.put(b"test", va)?;
- assert_eq!(tree.get(b"test")?, Some(va.into()));
+ tree.put(ka, va)?;
+ assert_eq!(tree.get(ka)?, Some(va.into()));
let res = db.transaction::<_, (), _>(|tx| {
- assert_eq!(tx.get(&tree, b"test")?, Some(va.into()));
+ assert_eq!(tx.get(&tree, ka)?, Some(va.into()));
- tx.put(&tree, b"test", vb)?;
+ tx.put(&tree, ka, vb)?;
- assert_eq!(tx.get(&tree, b"test")?, Some(vb.into()));
+ assert_eq!(tx.get(&tree, ka)?, Some(vb.into()));
tx.commit(12)
});
assert!(matches!(res, Ok(12)));
- assert_eq!(tree.get(b"test")?, Some(vb.into()));
+ assert_eq!(tree.get(ka)?, Some(vb.into()));
let res = db.transaction::<(), _, _>(|tx| {
- assert_eq!(tx.get(&tree, b"test")?, Some(vb.into()));
+ assert_eq!(tx.get(&tree, ka)?, Some(vb.into()));
- tx.put(&tree, b"test", vc)?;
+ tx.put(&tree, ka, vc)?;
- assert_eq!(tx.get(&tree, b"test")?, Some(vc.into()));
+ assert_eq!(tx.get(&tree, ka)?, Some(vc.into()));
tx.abort(42)
});
assert!(matches!(res, Err(TxError::Abort(42))));
- assert_eq!(tree.get(b"test")?, Some(vb.into()));
+ assert_eq!(tree.get(ka)?, Some(vb.into()));
+
+ let mut iter = tree.iter(false)?;
+ assert_eq!(iter.next().unwrap().unwrap(), (ka.into(), vb.into()));
+ assert!(iter.next().is_none());
+
+ tree.put(kb, vc)?;
+ assert_eq!(tree.get(kb)?, Some(vc.into()));
+
+ let mut iter = tree.iter(false)?;
+ 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)?;
+ assert_eq!(iter.next().unwrap().unwrap(), (kb.into(), vc.into()));
+ assert!(iter.next().is_none());
+
+ let mut iter = tree.range("tz", true)?;
+ assert_eq!(iter.next().unwrap().unwrap(), (ka.into(), vb.into()));
+ assert!(iter.next().is_none());
+
+ let mut iter = tree.iter(true)?;
+ 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());
Ok(())
}