diff --git a/src/database/abstraction.rs b/src/database/abstraction.rs index ea5fd424..ffcf476d 100644 --- a/src/database/abstraction.rs +++ b/src/database/abstraction.rs @@ -49,9 +49,9 @@ pub trait KeyValueDatabaseEngine: Send + Sync { } pub trait KvExport { - fn start_index(&mut self, name: &str) -> Result<()>; + fn start_tree(&mut self, name: &str) -> Result<()>; fn key_value(&mut self, key: &[u8], value: &[u8]) -> Result<()>; - fn end_index(&mut self, name: &str) -> Result<()>; + fn end_tree(&mut self, name: &str) -> Result<()>; } pub trait KvTree: Send + Sync { diff --git a/src/database/abstraction/heed.rs b/src/database/abstraction/heed.rs index 8f577020..ff843d97 100644 --- a/src/database/abstraction/heed.rs +++ b/src/database/abstraction/heed.rs @@ -9,7 +9,7 @@ use std::{ sync::{Arc, Mutex}, }; -use super::{KeyValueDatabaseEngine, KvTree}; +use super::{KeyValueDatabaseEngine, KvExport, KvTree}; type TupleOfBytes = (Vec, Vec); @@ -66,6 +66,20 @@ impl KeyValueDatabaseEngine for Arc { self.env.force_sync().map_err(convert_error)?; Ok(()) } + + fn export(&self, exporter: &mut Box) -> Result<()> { + // Heed do not support snapshots + let trees: Vec = unimplemented!("heed has no way lo list trees"); + for tree_name in &trees { + exporter.start_tree(tree_name)?; + let tree = self.open_tree(tree_name)?; + for (key, value) in tree.iter() { + exporter.key_value(&key, &value)?; + } + exporter.end_tree(&tree_name)?; + } + Ok(()) + } } impl EngineTree { diff --git a/src/database/abstraction/persy.rs b/src/database/abstraction/persy.rs index 563607a7..99cbc061 100644 --- a/src/database/abstraction/persy.rs +++ b/src/database/abstraction/persy.rs @@ -50,14 +50,14 @@ impl KeyValueDatabaseEngine for Arc { let snapshot = self.persy.snapshot()?; let indexes = snapshot.list_indexes()?; for (index, _) in indexes { - exporter.start_index(&index)?; + exporter.start_tree(&index)?; let data = snapshot.range::(&index, ..)?; for (key, values) in data { for value in values { exporter.key_value(&key, &value)?; } } - exporter.end_index(&index)?; + exporter.end_tree(&index)?; } Ok(()) } diff --git a/src/database/abstraction/rocksdb.rs b/src/database/abstraction/rocksdb.rs index a7afae5b..84ccf109 100644 --- a/src/database/abstraction/rocksdb.rs +++ b/src/database/abstraction/rocksdb.rs @@ -131,21 +131,21 @@ impl KeyValueDatabaseEngine for Arc { fn export(&self, exporter: &mut Box) -> Result<()> { let snapshot = self.rocks.snapshot(); - let indexes = rocksdb::DBWithThreadMode::::list_cf( + let column_familes = rocksdb::DBWithThreadMode::::list_cf( &rocksdb::Options::default(), &self.database_path, ) .unwrap(); - for index in indexes { - if let Some(handle) = self.rocks.cf_handle(&index) { - exporter.start_index(&index)?; + for column_family in column_familes { + if let Some(handle) = self.rocks.cf_handle(&column_family) { + exporter.start_tree(&column_family)?; let data = snapshot.iterator_cf(&handle, rocksdb::IteratorMode::Start); for ele in data { if let Ok((key, value)) = ele { exporter.key_value(&key, &value)?; } } - exporter.end_index(&index)?; + exporter.end_tree(&column_family)?; } } Ok(()) diff --git a/src/database/abstraction/sled.rs b/src/database/abstraction/sled.rs index 87defc57..454a4b83 100644 --- a/src/database/abstraction/sled.rs +++ b/src/database/abstraction/sled.rs @@ -27,6 +27,20 @@ impl DatabaseEngine for Engine { fn flush(self: &Arc) -> Result<()> { Ok(()) // noop } + + fn export(&self, exporter: &mut Box) -> Result<()> { + // Sled do not support snapshots + let indexes = self.0.tree_names(); + for index in &indexes { + exporter.start_index(index)?; + let tree = Arc::new(SledEngineTree(self.0.open_tree(name)?)); + for (key, value) in tree.iter() { + exporter.key_value(&key, &value)?; + } + exporter.end_index(&index)?; + } + Ok(()) + } } impl Tree for SledEngineTree { diff --git a/src/database/abstraction/sqlite.rs b/src/database/abstraction/sqlite.rs index b448c3b6..35d07dfe 100644 --- a/src/database/abstraction/sqlite.rs +++ b/src/database/abstraction/sqlite.rs @@ -1,4 +1,4 @@ -use super::{watchers::Watchers, KeyValueDatabaseEngine, KvTree}; +use super::{watchers::Watchers, KeyValueDatabaseEngine, KvExport, KvTree}; use crate::{database::Config, Result}; use parking_lot::{Mutex, MutexGuard}; use rusqlite::{Connection, DatabaseName::Main, OptionalExtension}; @@ -78,6 +78,14 @@ impl Engine { .pragma_update(Some(Main), "wal_checkpoint", "RESTART")?; Ok(()) } + + pub fn open_tree_impl(self: &Arc, name: &str) -> Arc { + Arc::new(SqliteTable { + engine: Arc::clone(self), + name: name.to_owned(), + watchers: Watchers::default(), + }) + } } impl KeyValueDatabaseEngine for Arc { @@ -108,11 +116,7 @@ impl KeyValueDatabaseEngine for Arc { fn open_tree(&self, name: &str) -> Result> { self.write_lock().execute(&format!("CREATE TABLE IF NOT EXISTS {name} ( \"key\" BLOB PRIMARY KEY, \"value\" BLOB NOT NULL )"), [])?; - Ok(Arc::new(SqliteTable { - engine: Arc::clone(self), - name: name.to_owned(), - watchers: Watchers::default(), - })) + Ok(self.open_tree_impl(name)) } fn flush(&self) -> Result<()> { @@ -123,6 +127,27 @@ impl KeyValueDatabaseEngine for Arc { fn cleanup(&self) -> Result<()> { self.flush_wal() } + + fn export(&self, exporter: &mut Box) -> Result<()> { + // TODO: rusqlite do not support snapshot yet, change this when they are supported + let tables: Vec = { + let guard = self.read_lock(); + guard + .prepare("SELECT name FROM sqlite_master WHERE type='table'")? + .query_map([], |row| row.get(0))? + .map(|r| r.unwrap()) + .collect() + }; + for table in &tables { + exporter.start_tree(table)?; + let tree = self.open_tree_impl(table); + for (key, value) in tree.iter() { + exporter.key_value(&key, &value)?; + } + exporter.end_tree(&table)?; + } + Ok(()) + } } pub struct SqliteTable {