db abstraction: make .insert() and .remove() return the old value
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing

This commit is contained in:
Alex 2022-06-07 17:05:17 +02:00
parent a9e79f848b
commit a3a01141ec
Signed by: lx
GPG key ID: 0E496D15096376BE
6 changed files with 127 additions and 91 deletions

View file

@ -51,36 +51,26 @@ impl CountedTree {
// ---- writing functions ---- // ---- writing functions ----
pub fn insert<K, V>(&self, key: K, value: V) -> Result<bool> pub fn insert<K, V>(&self, key: K, value: V) -> Result<Option<Value>>
where where
K: AsRef<[u8]>, K: AsRef<[u8]>,
V: AsRef<[u8]>, V: AsRef<[u8]>,
{ {
let inserted = self.0.tree.insert(key, value)?; let old_val = self.0.tree.insert(key, value)?;
if inserted { if old_val.is_none() {
self.0.len.fetch_add(1, Ordering::Relaxed); self.0.len.fetch_add(1, Ordering::Relaxed);
} }
Ok(inserted) Ok(old_val)
} }
pub fn remove<K: AsRef<[u8]>>(&self, key: K) -> Result<bool> { pub fn remove<K: AsRef<[u8]>>(&self, key: K) -> Result<Option<Value>> {
let removed = self.0.tree.remove(key)?; let old_val = self.0.tree.remove(key)?;
if removed { if old_val.is_some() {
self.0.len.fetch_sub(1, Ordering::Relaxed); self.0.len.fetch_sub(1, Ordering::Relaxed);
} }
Ok(removed) Ok(old_val)
} }
/*
pub fn pop_min(&self) -> Result<Option<(Value, Value)>> {
let res = self.0.tree.pop_min();
if let Ok(Some(_)) = &res {
self.0.len.fetch_sub(1, Ordering::Relaxed);
};
res
}
*/
pub fn compare_and_swap<K, OV, NV>( pub fn compare_and_swap<K, OV, NV>(
&self, &self,
key: K, key: K,

View file

@ -166,15 +166,18 @@ impl Tree {
.transpose() .transpose()
} }
/// True if item didn't exist before, false if item already existed /// Returns the old value if there was one
/// and was replaced.
#[inline] #[inline]
pub fn insert<T: AsRef<[u8]>, U: AsRef<[u8]>>(&self, key: T, value: U) -> Result<bool> { pub fn insert<T: AsRef<[u8]>, U: AsRef<[u8]>>(
&self,
key: T,
value: U,
) -> Result<Option<Value>> {
self.0.insert(self.1, key.as_ref(), value.as_ref()) self.0.insert(self.1, key.as_ref(), value.as_ref())
} }
/// True if item was removed, false if item already didn't exist /// Returns the old value if there was one
#[inline] #[inline]
pub fn remove<T: AsRef<[u8]>>(&self, key: T) -> Result<bool> { pub fn remove<T: AsRef<[u8]>>(&self, key: T) -> Result<Option<Value>> {
self.0.remove(self.1, key.as_ref()) self.0.remove(self.1, key.as_ref())
} }
@ -220,20 +223,19 @@ impl<'a> Transaction<'a> {
self.0.len(tree.1) self.0.len(tree.1)
} }
/// True if item didn't exist before, false if item already existed /// Returns the old value if there was one
/// and was replaced.
#[inline] #[inline]
pub fn insert<T: AsRef<[u8]>, U: AsRef<[u8]>>( pub fn insert<T: AsRef<[u8]>, U: AsRef<[u8]>>(
&mut self, &mut self,
tree: &Tree, tree: &Tree,
key: T, key: T,
value: U, value: U,
) -> Result<bool> { ) -> Result<Option<Value>> {
self.0.insert(tree.1, key.as_ref(), value.as_ref()) self.0.insert(tree.1, key.as_ref(), value.as_ref())
} }
/// True if item was removed, false if item already didn't exist /// Returns the old value if there was one
#[inline] #[inline]
pub fn remove<T: AsRef<[u8]>>(&mut self, tree: &Tree, key: T) -> Result<bool> { pub fn remove<T: AsRef<[u8]>>(&mut self, tree: &Tree, key: T) -> Result<Option<Value>> {
self.0.remove(tree.1, key.as_ref()) self.0.remove(tree.1, key.as_ref())
} }
@ -289,8 +291,8 @@ pub(crate) trait IDb: Send + Sync {
fn get(&self, tree: usize, key: &[u8]) -> Result<Option<Value>>; fn get(&self, tree: usize, key: &[u8]) -> Result<Option<Value>>;
fn len(&self, tree: usize) -> Result<usize>; fn len(&self, tree: usize) -> Result<usize>;
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<bool>; fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>>;
fn remove(&self, tree: usize, key: &[u8]) -> Result<bool>; fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>>;
fn iter(&self, tree: usize) -> Result<ValueIter<'_>>; fn iter(&self, tree: usize) -> Result<ValueIter<'_>>;
fn iter_rev(&self, tree: usize) -> Result<ValueIter<'_>>; fn iter_rev(&self, tree: usize) -> Result<ValueIter<'_>>;
@ -315,8 +317,8 @@ pub(crate) trait ITx {
fn get(&self, tree: usize, key: &[u8]) -> Result<Option<Value>>; fn get(&self, tree: usize, key: &[u8]) -> Result<Option<Value>>;
fn len(&self, tree: usize) -> Result<usize>; fn len(&self, tree: usize) -> Result<usize>;
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> Result<bool>; fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>>;
fn remove(&mut self, tree: usize, key: &[u8]) -> Result<bool>; fn remove(&mut self, tree: usize, key: &[u8]) -> Result<Option<Value>>;
fn iter(&self, tree: usize) -> Result<ValueIter<'_>>; fn iter(&self, tree: usize) -> Result<ValueIter<'_>>;
fn iter_rev(&self, tree: usize) -> Result<ValueIter<'_>>; fn iter_rev(&self, tree: usize) -> Result<ValueIter<'_>>;

View file

@ -108,27 +108,28 @@ impl IDb for LmdbDb {
} }
} }
fn remove(&self, tree: usize, key: &[u8]) -> Result<bool> {
let tree = self.get_tree(tree)?;
let mut tx = self.db.write_txn()?;
let deleted = tree.delete(&mut tx, key)?;
tx.commit()?;
Ok(deleted)
}
fn len(&self, tree: usize) -> Result<usize> { fn len(&self, tree: usize) -> Result<usize> {
let tree = self.get_tree(tree)?; let tree = self.get_tree(tree)?;
let tx = self.db.read_txn()?; let tx = self.db.read_txn()?;
Ok(tree.len(&tx)?.try_into().unwrap()) Ok(tree.len(&tx)?.try_into().unwrap())
} }
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<bool> { fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>> {
let tree = self.get_tree(tree)?; let tree = self.get_tree(tree)?;
let mut tx = self.db.write_txn()?; let mut tx = self.db.write_txn()?;
let old_val = tree.get(&tx, key)?.map(Vec::from); let old_val = tree.get(&tx, key)?.map(Vec::from);
tree.put(&mut tx, key, value)?; tree.put(&mut tx, key, value)?;
tx.commit()?; tx.commit()?;
Ok(old_val.is_none()) Ok(old_val)
}
fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>> {
let tree = self.get_tree(tree)?;
let mut tx = self.db.write_txn()?;
let old_val = tree.get(&tx, key)?.map(Vec::from);
tree.delete(&mut tx, key)?;
tx.commit()?;
Ok(old_val)
} }
fn iter(&self, tree: usize) -> Result<ValueIter<'_>> { fn iter(&self, tree: usize) -> Result<ValueIter<'_>> {
@ -222,16 +223,17 @@ impl<'a, 'db> ITx for LmdbTx<'a, 'db> {
unimplemented!(".len() in transaction not supported with LMDB backend") unimplemented!(".len() in transaction not supported with LMDB backend")
} }
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> Result<bool> { fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>> {
let tree = *self.get_tree(tree)?; let tree = *self.get_tree(tree)?;
let old_val = tree.get(&self.tx, key)?.map(Vec::from); let old_val = tree.get(&self.tx, key)?.map(Vec::from);
tree.put(&mut self.tx, key, value)?; tree.put(&mut self.tx, key, value)?;
Ok(old_val.is_none()) Ok(old_val)
} }
fn remove(&mut self, tree: usize, key: &[u8]) -> Result<bool> { fn remove(&mut self, tree: usize, key: &[u8]) -> Result<Option<Value>> {
let tree = *self.get_tree(tree)?; let tree = *self.get_tree(tree)?;
let deleted = tree.delete(&mut self.tx, key)?; let old_val = tree.get(&self.tx, key)?.map(Vec::from);
Ok(deleted) tree.delete(&mut self.tx, key)?;
Ok(old_val)
} }
fn iter(&self, _tree: usize) -> Result<ValueIter<'_>> { fn iter(&self, _tree: usize) -> Result<ValueIter<'_>> {

View file

@ -83,20 +83,21 @@ impl IDb for SledDb {
Ok(val.map(|x| x.to_vec())) Ok(val.map(|x| x.to_vec()))
} }
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> { fn len(&self, tree: usize) -> Result<usize> {
let tree = self.get_tree(tree)?; let tree = self.get_tree(tree)?;
Ok(tree.len()) Ok(tree.len())
} }
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<bool> { fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>> {
let tree = self.get_tree(tree)?; let tree = self.get_tree(tree)?;
let old_val = tree.insert(key, value)?; let old_val = tree.insert(key, value)?;
Ok(old_val.is_none()) Ok(old_val.map(|x| x.to_vec()))
}
fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>> {
let tree = self.get_tree(tree)?;
let old_val = tree.remove(key)?;
Ok(old_val.map(|x| x.to_vec()))
} }
fn iter(&self, tree: usize) -> Result<ValueIter<'_>> { fn iter(&self, tree: usize) -> Result<ValueIter<'_>> {
@ -206,14 +207,15 @@ impl<'a> ITx for SledTx<'a> {
unimplemented!(".len() in transaction not supported with Sled backend") unimplemented!(".len() in transaction not supported with Sled backend")
} }
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> Result<bool> { fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>> {
let tree = self.get_tree(tree)?; let tree = self.get_tree(tree)?;
let old_val = self.save_error(tree.insert(key, value))?; let old_val = self.save_error(tree.insert(key, value))?;
Ok(old_val.is_none()) Ok(old_val.map(|x| x.to_vec()))
} }
fn remove(&mut self, tree: usize, key: &[u8]) -> Result<bool> { fn remove(&mut self, tree: usize, key: &[u8]) -> Result<Option<Value>> {
let tree = self.get_tree(tree)?; let tree = self.get_tree(tree)?;
Ok(self.save_error(tree.remove(key))?.is_some()) let old_val = self.save_error(tree.remove(key))?;
Ok(old_val.map(|x| x.to_vec()))
} }
fn iter(&self, _tree: usize) -> Result<ValueIter<'_>> { fn iter(&self, _tree: usize) -> Result<ValueIter<'_>> {

View file

@ -125,18 +125,6 @@ impl IDb for SqliteDb {
this.internal_get(tree, key) this.internal_get(tree, key)
} }
fn remove(&self, tree: usize, key: &[u8]) -> Result<bool> {
trace!("remove {}: lock db", tree);
let this = self.0.lock().unwrap();
trace!("remove {}: lock acquired", tree);
let tree = this.get_tree(tree)?;
let res = this
.db
.execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![key])?;
Ok(res > 0)
}
fn len(&self, tree: usize) -> Result<usize> { fn len(&self, tree: usize) -> Result<usize> {
trace!("len {}: lock db", tree); trace!("len {}: lock db", tree);
let this = self.0.lock().unwrap(); let this = self.0.lock().unwrap();
@ -151,18 +139,50 @@ impl IDb for SqliteDb {
} }
} }
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<bool> { fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>> {
trace!("insert {}: lock db", tree); trace!("insert {}: lock db", tree);
let this = self.0.lock().unwrap(); let this = self.0.lock().unwrap();
trace!("insert {}: lock acquired", tree); trace!("insert {}: lock acquired", tree);
let tree = this.get_tree(tree)?; let tree = this.get_tree(tree)?;
let old_val = this.internal_get(tree, key)?; let old_val = this.internal_get(tree, key)?;
this.db.execute(
&format!("INSERT OR REPLACE INTO {} (k, v) VALUES (?1, ?2)", tree), match &old_val {
Some(_) => {
let n = this.db.execute(
&format!("UPDATE {} SET v = ?2 WHERE k = ?1", tree),
params![key, value], params![key, value],
)?; )?;
Ok(old_val.is_none()) assert_eq!(n, 1);
}
None => {
let n = this.db.execute(
&format!("INSERT INTO {} (k, v) VALUES (?1, ?2)", tree),
params![key, value],
)?;
assert_eq!(n, 1);
}
}
Ok(old_val)
}
fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>> {
trace!("remove {}: lock db", tree);
let this = self.0.lock().unwrap();
trace!("remove {}: lock acquired", tree);
let tree = this.get_tree(tree)?;
let old_val = this.internal_get(tree, key)?;
if old_val.is_some() {
let n = this
.db
.execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![key])?;
assert_eq!(n, 1);
}
Ok(old_val)
} }
fn iter(&self, tree: usize) -> Result<ValueIter<'_>> { fn iter(&self, tree: usize) -> Result<ValueIter<'_>> {
@ -308,21 +328,41 @@ impl<'a> ITx for SqliteTx<'a> {
} }
} }
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> Result<bool> { fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>> {
let tree = self.get_tree(tree)?; let tree = self.get_tree(tree)?;
let old_val = self.internal_get(tree, key)?; let old_val = self.internal_get(tree, key)?;
self.tx.execute(
&format!("INSERT OR REPLACE INTO {} (k, v) VALUES (?1, ?2)", tree), match &old_val {
Some(_) => {
let n = self.tx.execute(
&format!("UPDATE {} SET v = ?2 WHERE k = ?1", tree),
params![key, value], params![key, value],
)?; )?;
Ok(old_val.is_none()) assert_eq!(n, 1);
} }
fn remove(&mut self, tree: usize, key: &[u8]) -> Result<bool> { None => {
let n = self.tx.execute(
&format!("INSERT INTO {} (k, v) VALUES (?1, ?2)", tree),
params![key, value],
)?;
assert_eq!(n, 1);
}
}
Ok(old_val)
}
fn remove(&mut self, tree: usize, key: &[u8]) -> Result<Option<Value>> {
let tree = self.get_tree(tree)?; let tree = self.get_tree(tree)?;
let res = self let old_val = self.internal_get(tree, key)?;
if old_val.is_some() {
let n = self
.tx .tx
.execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![key])?; .execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![key])?;
Ok(res > 0) assert_eq!(n, 1);
}
Ok(old_val)
} }
fn iter(&self, _tree: usize) -> Result<ValueIter<'_>> { fn iter(&self, _tree: usize) -> Result<ValueIter<'_>> {

View file

@ -14,13 +14,13 @@ fn test_suite(db: Db) {
let vb: &[u8] = &b"plip"[..]; let vb: &[u8] = &b"plip"[..];
let vc: &[u8] = &b"plup"[..]; let vc: &[u8] = &b"plup"[..];
tree.insert(ka, va).unwrap(); assert!(tree.insert(ka, va).unwrap().is_none());
assert_eq!(tree.get(ka).unwrap().unwrap(), va); assert_eq!(tree.get(ka).unwrap().unwrap(), va);
let res = db.transaction::<_, (), _>(|mut tx| { let res = db.transaction::<_, (), _>(|mut tx| {
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), va); assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), va);
tx.insert(&tree, ka, vb).unwrap(); assert_eq!(tx.insert(&tree, ka, vb).unwrap().unwrap(), va);
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vb); assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vb);
@ -32,7 +32,7 @@ fn test_suite(db: Db) {
let res = db.transaction::<(), _, _>(|mut tx| { let res = db.transaction::<(), _, _>(|mut tx| {
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vb); assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vb);
tx.insert(&tree, ka, vc).unwrap(); assert_eq!(tx.insert(&tree, ka, vc).unwrap().unwrap(), vb);
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vc); assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vc);
@ -47,7 +47,7 @@ fn test_suite(db: Db) {
assert!(iter.next().is_none()); assert!(iter.next().is_none());
drop(iter); drop(iter);
tree.insert(kb, vc).unwrap(); assert!(tree.insert(kb, vc).unwrap().is_none());
assert_eq!(tree.get(kb).unwrap().unwrap(), vc); assert_eq!(tree.get(kb).unwrap().unwrap(), vc);
let mut iter = tree.iter().unwrap(); let mut iter = tree.iter().unwrap();