aboutsummaryrefslogtreecommitdiff
path: root/src/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/db')
-rw-r--r--src/db/Cargo.toml13
-rw-r--r--src/db/bin/convert.rs69
-rw-r--r--src/db/counted_tree_hack.rs6
-rw-r--r--src/db/lib.rs78
-rw-r--r--src/db/lmdb_adapter.rs10
-rw-r--r--src/db/sled_adapter.rs20
-rw-r--r--src/db/sqlite_adapter.rs10
-rw-r--r--src/db/test.rs8
8 files changed, 75 insertions, 139 deletions
diff --git a/src/db/Cargo.toml b/src/db/Cargo.toml
index 67a4fd5e..67af4a7c 100644
--- a/src/db/Cargo.toml
+++ b/src/db/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "garage_db"
-version = "0.8.2"
+version = "0.9.0"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
@@ -11,29 +11,24 @@ readme = "../../README.md"
[lib]
path = "lib.rs"
-[[bin]]
-name = "convert"
-path = "bin/convert.rs"
-required-features = ["cli"]
-
[dependencies]
err-derive = "0.3"
hexdump = "0.1"
tracing = "0.1"
heed = { version = "0.11", default-features = false, features = ["lmdb"], optional = true }
-rusqlite = { version = "0.28", optional = true }
+rusqlite = { version = "0.29", optional = true }
sled = { version = "0.34", optional = true }
# cli deps
clap = { version = "4.1", optional = true, features = ["derive", "env"] }
-pretty_env_logger = { version = "0.4", optional = true }
+pretty_env_logger = { version = "0.5", optional = true }
[dev-dependencies]
mktemp = "0.5"
[features]
-default = [ "sled" ]
+default = [ "sled", "lmdb", "sqlite" ]
bundled-libs = [ "rusqlite?/bundled" ]
cli = ["clap", "pretty_env_logger"]
lmdb = [ "heed" ]
diff --git a/src/db/bin/convert.rs b/src/db/bin/convert.rs
deleted file mode 100644
index bbde2048..00000000
--- a/src/db/bin/convert.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-use std::path::PathBuf;
-
-use garage_db::*;
-
-use clap::Parser;
-
-/// K2V command line interface
-#[derive(Parser, Debug)]
-#[clap(author, version, about, long_about = None)]
-struct Args {
- /// Input DB path
- #[clap(short = 'i')]
- input_path: PathBuf,
- /// Input DB engine
- #[clap(short = 'a')]
- input_engine: String,
-
- /// Output DB path
- #[clap(short = 'o')]
- output_path: PathBuf,
- /// Output DB engine
- #[clap(short = 'b')]
- output_engine: String,
-}
-
-fn main() {
- let args = Args::parse();
- pretty_env_logger::init();
-
- match do_conversion(args) {
- Ok(()) => println!("Success!"),
- Err(e) => eprintln!("Error: {}", e),
- }
-}
-
-fn do_conversion(args: Args) -> Result<()> {
- let input = open_db(args.input_path, args.input_engine)?;
- let output = open_db(args.output_path, args.output_engine)?;
- output.import(&input)?;
- Ok(())
-}
-
-fn open_db(path: PathBuf, engine: String) -> Result<Db> {
- match engine.as_str() {
- "sled" => {
- let db = sled_adapter::sled::Config::default().path(&path).open()?;
- Ok(sled_adapter::SledDb::init(db))
- }
- "sqlite" | "sqlite3" | "rusqlite" => {
- let db = sqlite_adapter::rusqlite::Connection::open(&path)?;
- Ok(sqlite_adapter::SqliteDb::init(db))
- }
- "lmdb" | "heed" => {
- std::fs::create_dir_all(&path).map_err(|e| {
- Error(format!("Unable to create LMDB data directory: {}", e).into())
- })?;
-
- let map_size = lmdb_adapter::recommended_map_size();
-
- let db = lmdb_adapter::heed::EnvOpenOptions::new()
- .max_dbs(100)
- .map_size(map_size)
- .open(&path)
- .unwrap();
- Ok(lmdb_adapter::LmdbDb::init(db))
- }
- e => Err(Error(format!("Invalid DB engine: {}", e).into())),
- }
-}
diff --git a/src/db/counted_tree_hack.rs b/src/db/counted_tree_hack.rs
index bbe943a2..a4ce12e0 100644
--- a/src/db/counted_tree_hack.rs
+++ b/src/db/counted_tree_hack.rs
@@ -85,7 +85,7 @@ impl CountedTree {
let old_some = expected_old.is_some();
let new_some = new.is_some();
- let tx_res = self.0.tree.db().transaction(|mut tx| {
+ let tx_res = self.0.tree.db().transaction(|tx| {
let old_val = tx.get(&self.0.tree, &key)?;
let is_same = match (&old_val, &expected_old) {
(None, None) => true,
@@ -101,9 +101,9 @@ impl CountedTree {
tx.remove(&self.0.tree, &key)?;
}
}
- tx.commit(())
+ Ok(())
} else {
- tx.abort(())
+ Err(TxError::Abort(()))
}
});
diff --git a/src/db/lib.rs b/src/db/lib.rs
index 11cae4e3..fe44b01e 100644
--- a/src/db/lib.rs
+++ b/src/db/lib.rs
@@ -2,9 +2,6 @@
#[cfg(feature = "sqlite")]
extern crate tracing;
-#[cfg(not(any(feature = "lmdb", feature = "sled", feature = "sqlite")))]
-compile_error!("Must activate the Cargo feature for at least one DB engine: lmdb, sled or sqlite.");
-
#[cfg(feature = "lmdb")]
pub mod lmdb_adapter;
#[cfg(feature = "sled")]
@@ -25,10 +22,15 @@ use std::sync::Arc;
use err_derive::Error;
+pub(crate) type OnCommit = Vec<Box<dyn FnOnce()>>;
+
#[derive(Clone)]
pub struct Db(pub(crate) Arc<dyn IDb>);
-pub struct Transaction<'a>(&'a mut dyn ITx);
+pub struct Transaction<'a> {
+ tx: &'a mut dyn ITx,
+ on_commit: OnCommit,
+}
#[derive(Clone)]
pub struct Tree(Arc<dyn IDb>, usize);
@@ -88,7 +90,7 @@ impl Db {
pub fn transaction<R, E, F>(&self, fun: F) -> TxResult<R, E>
where
- F: Fn(Transaction<'_>) -> TxResult<R, E>,
+ F: Fn(&mut Transaction<'_>) -> TxResult<R, E>,
{
let f = TxFn {
function: fun,
@@ -101,14 +103,17 @@ impl Db {
.expect("Transaction did not store result");
match tx_res {
- Ok(()) => {
- assert!(matches!(ret, Ok(_)));
- ret
- }
- Err(TxError::Abort(())) => {
- assert!(matches!(ret, Err(TxError::Abort(_))));
- ret
- }
+ Ok(on_commit) => match ret {
+ Ok(value) => {
+ on_commit.into_iter().for_each(|f| f());
+ Ok(value)
+ }
+ _ => unreachable!(),
+ },
+ Err(TxError::Abort(())) => match ret {
+ Err(TxError::Abort(e)) => Err(TxError::Abort(e)),
+ _ => unreachable!(),
+ },
Err(TxError::Db(e2)) => match ret {
// Ok was stored -> the error occured when finalizing
// transaction
@@ -142,7 +147,7 @@ impl Db {
let ex_tree = other.open_tree(&name)?;
- let tx_res = self.transaction(|mut tx| {
+ let tx_res = self.transaction(|tx| {
let mut i = 0;
for item in ex_tree.iter().map_err(TxError::Abort)? {
let (k, v) = item.map_err(TxError::Abort)?;
@@ -152,7 +157,7 @@ impl Db {
println!("{}: imported {}", name, i);
}
}
- tx.commit(i)
+ Ok(i)
});
let total = match tx_res {
Err(TxError::Db(e)) => return Err(e),
@@ -252,11 +257,11 @@ impl Tree {
impl<'a> Transaction<'a> {
#[inline]
pub fn get<T: AsRef<[u8]>>(&self, tree: &Tree, key: T) -> TxOpResult<Option<Value>> {
- self.0.get(tree.1, key.as_ref())
+ self.tx.get(tree.1, key.as_ref())
}
#[inline]
pub fn len(&self, tree: &Tree) -> TxOpResult<usize> {
- self.0.len(tree.1)
+ self.tx.len(tree.1)
}
/// Returns the old value if there was one
@@ -267,21 +272,21 @@ impl<'a> Transaction<'a> {
key: T,
value: U,
) -> TxOpResult<Option<Value>> {
- self.0.insert(tree.1, key.as_ref(), value.as_ref())
+ self.tx.insert(tree.1, key.as_ref(), value.as_ref())
}
/// Returns the old value if there was one
#[inline]
pub fn remove<T: AsRef<[u8]>>(&mut self, tree: &Tree, key: T) -> TxOpResult<Option<Value>> {
- self.0.remove(tree.1, key.as_ref())
+ self.tx.remove(tree.1, key.as_ref())
}
#[inline]
pub fn iter(&self, tree: &Tree) -> TxOpResult<TxValueIter<'_>> {
- self.0.iter(tree.1)
+ self.tx.iter(tree.1)
}
#[inline]
pub fn iter_rev(&self, tree: &Tree) -> TxOpResult<TxValueIter<'_>> {
- self.0.iter_rev(tree.1)
+ self.tx.iter_rev(tree.1)
}
#[inline]
@@ -292,7 +297,7 @@ impl<'a> Transaction<'a> {
{
let sb = range.start_bound();
let eb = range.end_bound();
- self.0.range(tree.1, get_bound(sb), get_bound(eb))
+ self.tx.range(tree.1, get_bound(sb), get_bound(eb))
}
#[inline]
pub fn range_rev<K, R>(&self, tree: &Tree, range: R) -> TxOpResult<TxValueIter<'_>>
@@ -302,19 +307,12 @@ impl<'a> Transaction<'a> {
{
let sb = range.start_bound();
let eb = range.end_bound();
- self.0.range_rev(tree.1, get_bound(sb), get_bound(eb))
+ self.tx.range_rev(tree.1, get_bound(sb), get_bound(eb))
}
- // ----
-
#[inline]
- pub fn abort<R, E>(self, e: E) -> TxResult<R, E> {
- Err(TxError::Abort(e))
- }
-
- #[inline]
- pub fn commit<R, E>(self, r: R) -> TxResult<R, E> {
- Ok(r)
+ pub fn on_commit<F: FnOnce() + 'static>(&mut self, f: F) {
+ self.on_commit.push(Box::new(f));
}
}
@@ -351,7 +349,7 @@ pub(crate) trait IDb: Send + Sync {
high: Bound<&'r [u8]>,
) -> Result<ValueIter<'_>>;
- fn transaction(&self, f: &dyn ITxFn) -> TxResult<(), ()>;
+ fn transaction(&self, f: &dyn ITxFn) -> TxResult<OnCommit, ()>;
}
pub(crate) trait ITx {
@@ -383,14 +381,14 @@ pub(crate) trait ITxFn {
}
pub(crate) enum TxFnResult {
- Ok,
+ Ok(OnCommit),
Abort,
DbErr,
}
struct TxFn<F, R, E>
where
- F: Fn(Transaction<'_>) -> TxResult<R, E>,
+ F: Fn(&mut Transaction<'_>) -> TxResult<R, E>,
{
function: F,
result: Cell<Option<TxResult<R, E>>>,
@@ -398,12 +396,16 @@ where
impl<F, R, E> ITxFn for TxFn<F, R, E>
where
- F: Fn(Transaction<'_>) -> TxResult<R, E>,
+ F: Fn(&mut Transaction<'_>) -> TxResult<R, E>,
{
fn try_on(&self, tx: &mut dyn ITx) -> TxFnResult {
- let res = (self.function)(Transaction(tx));
+ let mut tx = Transaction {
+ tx,
+ on_commit: vec![],
+ };
+ let res = (self.function)(&mut tx);
let res2 = match &res {
- Ok(_) => TxFnResult::Ok,
+ Ok(_) => TxFnResult::Ok(tx.on_commit),
Err(TxError::Abort(_)) => TxFnResult::Abort,
Err(TxError::Db(_)) => TxFnResult::DbErr,
};
diff --git a/src/db/lmdb_adapter.rs b/src/db/lmdb_adapter.rs
index ecbc3b81..59fa132d 100644
--- a/src/db/lmdb_adapter.rs
+++ b/src/db/lmdb_adapter.rs
@@ -9,8 +9,8 @@ use heed::types::ByteSlice;
use heed::{BytesDecode, Env, RoTxn, RwTxn, UntypedDatabase as Database};
use crate::{
- Db, Error, IDb, ITx, ITxFn, Result, TxError, TxFnResult, TxOpError, TxOpResult, TxResult,
- TxValueIter, Value, ValueIter,
+ Db, Error, IDb, ITx, ITxFn, OnCommit, Result, TxError, TxFnResult, TxOpError, TxOpResult,
+ TxResult, TxValueIter, Value, ValueIter,
};
pub use heed;
@@ -186,7 +186,7 @@ impl IDb for LmdbDb {
// ----
- fn transaction(&self, f: &dyn ITxFn) -> TxResult<(), ()> {
+ fn transaction(&self, f: &dyn ITxFn) -> TxResult<OnCommit, ()> {
let trees = self.trees.read().unwrap();
let mut tx = LmdbTx {
trees: &trees.0[..],
@@ -199,9 +199,9 @@ impl IDb for LmdbDb {
let res = f.try_on(&mut tx);
match res {
- TxFnResult::Ok => {
+ TxFnResult::Ok(on_commit) => {
tx.tx.commit().map_err(Error::from).map_err(TxError::Db)?;
- Ok(())
+ Ok(on_commit)
}
TxFnResult::Abort => {
tx.tx.abort().map_err(Error::from).map_err(TxError::Db)?;
diff --git a/src/db/sled_adapter.rs b/src/db/sled_adapter.rs
index cf61867d..84f2001b 100644
--- a/src/db/sled_adapter.rs
+++ b/src/db/sled_adapter.rs
@@ -10,8 +10,8 @@ use sled::transaction::{
};
use crate::{
- Db, Error, IDb, ITx, ITxFn, Result, TxError, TxFnResult, TxOpError, TxOpResult, TxResult,
- TxValueIter, Value, ValueIter,
+ Db, Error, IDb, ITx, ITxFn, OnCommit, Result, TxError, TxFnResult, TxOpError, TxOpResult,
+ TxResult, TxValueIter, Value, ValueIter,
};
pub use sled;
@@ -38,7 +38,15 @@ pub struct SledDb {
}
impl SledDb {
+ #[deprecated(
+ since = "0.9.0",
+ note = "The Sled database is now deprecated and will be removed in Garage v1.0. Please migrate to LMDB or Sqlite as soon as possible."
+ )]
pub fn init(db: sled::Db) -> Db {
+ tracing::warn!("-------------------- IMPORTANT WARNING !!! ----------------------");
+ tracing::warn!("The Sled database is now deprecated and will be removed in Garage v1.0.");
+ tracing::warn!("Please migrate to LMDB or Sqlite as soon as possible.");
+ tracing::warn!("-----------------------------------------------------------------------");
let s = Self {
db,
trees: RwLock::new((Vec::new(), HashMap::new())),
@@ -158,7 +166,7 @@ impl IDb for SledDb {
// ----
- fn transaction(&self, f: &dyn ITxFn) -> TxResult<(), ()> {
+ fn transaction(&self, f: &dyn ITxFn) -> TxResult<OnCommit, ()> {
let trees = self.trees.read().unwrap();
let res = trees.0.transaction(|txtrees| {
let mut tx = SledTx {
@@ -166,9 +174,9 @@ impl IDb for SledDb {
err: Cell::new(None),
};
match f.try_on(&mut tx) {
- TxFnResult::Ok => {
+ TxFnResult::Ok(on_commit) => {
assert!(tx.err.into_inner().is_none());
- Ok(())
+ Ok(on_commit)
}
TxFnResult::Abort => {
assert!(tx.err.into_inner().is_none());
@@ -181,7 +189,7 @@ impl IDb for SledDb {
}
});
match res {
- Ok(()) => Ok(()),
+ Ok(on_commit) => Ok(on_commit),
Err(TransactionError::Abort(())) => Err(TxError::Abort(())),
Err(TransactionError::Storage(s)) => Err(TxError::Db(s.into())),
}
diff --git a/src/db/sqlite_adapter.rs b/src/db/sqlite_adapter.rs
index 63b4506e..9f967c66 100644
--- a/src/db/sqlite_adapter.rs
+++ b/src/db/sqlite_adapter.rs
@@ -9,8 +9,8 @@ use std::sync::{Arc, Mutex, MutexGuard};
use rusqlite::{params, Connection, Rows, Statement, Transaction};
use crate::{
- Db, Error, IDb, ITx, ITxFn, Result, TxError, TxFnResult, TxOpError, TxOpResult, TxResult,
- TxValueIter, Value, ValueIter,
+ Db, Error, IDb, ITx, ITxFn, OnCommit, Result, TxError, TxFnResult, TxOpError, TxOpResult,
+ TxResult, TxValueIter, Value, ValueIter,
};
pub use rusqlite;
@@ -261,7 +261,7 @@ impl IDb for SqliteDb {
// ----
- fn transaction(&self, f: &dyn ITxFn) -> TxResult<(), ()> {
+ fn transaction(&self, f: &dyn ITxFn) -> TxResult<OnCommit, ()> {
trace!("transaction: lock db");
let mut this = self.0.lock().unwrap();
trace!("transaction: lock acquired");
@@ -277,9 +277,9 @@ impl IDb for SqliteDb {
trees: &this_mut_ref.trees,
};
let res = match f.try_on(&mut tx) {
- TxFnResult::Ok => {
+ TxFnResult::Ok(on_commit) => {
tx.tx.commit().map_err(Error::from).map_err(TxError::Db)?;
- Ok(())
+ Ok(on_commit)
}
TxFnResult::Abort => {
tx.tx.rollback().map_err(Error::from).map_err(TxError::Db)?;
diff --git a/src/db/test.rs b/src/db/test.rs
index 40e6c41e..cd99eafa 100644
--- a/src/db/test.rs
+++ b/src/db/test.rs
@@ -13,26 +13,26 @@ fn test_suite(db: Db) {
assert!(tree.insert(ka, va).unwrap().is_none());
assert_eq!(tree.get(ka).unwrap().unwrap(), va);
- let res = db.transaction::<_, (), _>(|mut tx| {
+ let res = db.transaction::<_, (), _>(|tx| {
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), va);
assert_eq!(tx.insert(&tree, ka, vb).unwrap().unwrap(), va);
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vb);
- tx.commit(12)
+ Ok(12)
});
assert!(matches!(res, Ok(12)));
assert_eq!(tree.get(ka).unwrap().unwrap(), vb);
- let res = db.transaction::<(), _, _>(|mut tx| {
+ let res = db.transaction::<(), _, _>(|tx| {
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vb);
assert_eq!(tx.insert(&tree, ka, vc).unwrap().unwrap(), vb);
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vc);
- tx.abort(42)
+ Err(TxError::Abort(42))
});
assert!(matches!(res, Err(TxError::Abort(42))));
assert_eq!(tree.get(ka).unwrap().unwrap(), vb);