Compare commits

..

No commits in common. "586957b4b7261b43e7820d7193516153201b4954" and "615698df7d2d3867fd3d9cbdf8d8849a9de358bf" have entirely different histories.

5 changed files with 28 additions and 17 deletions

View file

@ -5,7 +5,7 @@ weight = 40
Garage is meant to work on old, second-hand hardware. Garage is meant to work on old, second-hand hardware.
In particular, this makes it likely that some of your drives will fail, and some manual intervention will be needed. In particular, this makes it likely that some of your drives will fail, and some manual intervention will be needed.
Fear not! Garage is fully equipped to handle drive failures, in most common cases. Fear not! For Garage is fully equipped to handle drive failures, in most common cases.
## A note on availability of Garage ## A note on availability of Garage
@ -61,7 +61,7 @@ garage repair -a --yes blocks
This will re-synchronize blocks of data that are missing to the new HDD, reading them from copies located on other nodes. This will re-synchronize blocks of data that are missing to the new HDD, reading them from copies located on other nodes.
You can check on the advancement of this process by doing the following command: You can check on the advancement of this process by doing the following command:
```bash ```bash
garage stats -a garage stats -a

View file

@ -211,12 +211,16 @@ impl Tree {
/// Returns the old value if there was one /// Returns the old value if there was one
#[inline] #[inline]
pub fn insert<T: AsRef<[u8]>, U: AsRef<[u8]>>(&self, key: T, value: U) -> Result<()> { 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())
} }
/// Returns the old value if there was one /// Returns the old value if there was one
#[inline] #[inline]
pub fn remove<T: AsRef<[u8]>>(&self, key: T) -> Result<()> { 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())
} }
/// Clears all values from the tree /// Clears all values from the tree
@ -335,8 +339,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<()>; fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>>;
fn remove(&self, tree: usize, key: &[u8]) -> Result<()>; fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>>;
fn clear(&self, tree: usize) -> Result<()>; fn clear(&self, tree: usize) -> Result<()>;
fn iter(&self, tree: usize) -> Result<ValueIter<'_>>; fn iter(&self, tree: usize) -> Result<ValueIter<'_>>;

View file

@ -132,20 +132,22 @@ impl IDb for LmdbDb {
Ok(tree.len(&tx)?.try_into().unwrap()) Ok(tree.len(&tx)?.try_into().unwrap())
} }
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> { 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);
tree.put(&mut tx, key, value)?; tree.put(&mut tx, key, value)?;
tx.commit()?; tx.commit()?;
Ok(()) Ok(old_val)
} }
fn remove(&self, tree: usize, key: &[u8]) -> Result<()> { fn remove(&self, tree: usize, key: &[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);
tree.delete(&mut tx, key)?; tree.delete(&mut tx, key)?;
tx.commit()?; tx.commit()?;
Ok(()) Ok(old_val)
} }
fn clear(&self, tree: usize) -> Result<()> { fn clear(&self, tree: usize) -> Result<()> {

View file

@ -169,7 +169,7 @@ impl IDb for SqliteDb {
} }
} }
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> { 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 db = self.db.get()?; let db = self.db.get()?;
let lock = self.write_lock.lock(); let lock = self.write_lock.lock();
@ -184,18 +184,23 @@ impl IDb for SqliteDb {
assert_eq!(n, 1); assert_eq!(n, 1);
drop(lock); drop(lock);
Ok(()) Ok(old_val)
} }
fn remove(&self, tree: usize, key: &[u8]) -> Result<()> { fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>> {
let tree = self.get_tree(tree)?; let tree = self.get_tree(tree)?;
let db = self.db.get()?; let db = self.db.get()?;
let lock = self.write_lock.lock(); let lock = self.write_lock.lock();
let n = db.execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![key])?; let old_val = self.internal_get(&db, &tree, key)?;
if old_val.is_some() {
let n = db.execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![key])?;
assert_eq!(n, 1);
}
drop(lock); drop(lock);
Ok(()) Ok(old_val)
} }
fn clear(&self, tree: usize) -> Result<()> { fn clear(&self, tree: usize) -> Result<()> {

View file

@ -12,7 +12,7 @@ fn test_suite(db: Db) {
// ---- test simple insert/delete ---- // ---- test simple insert/delete ----
assert!(tree.insert(ka, va).is_ok()); assert!(tree.insert(ka, va).unwrap().is_none());
assert_eq!(tree.get(ka).unwrap().unwrap(), va); assert_eq!(tree.get(ka).unwrap().unwrap(), va);
assert_eq!(tree.len().unwrap(), 1); assert_eq!(tree.len().unwrap(), 1);
@ -50,7 +50,7 @@ fn test_suite(db: Db) {
assert!(iter.next().is_none()); assert!(iter.next().is_none());
drop(iter); drop(iter);
assert!(tree.insert(kb, vc).is_ok()); 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();