Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[db] Implement backup and restore for in-memory db #1324 #1325

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions agdb/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ pub type DbFileTransaction<'a> = Transaction<'a, FileStorage>;
pub type DbFileTransactionMut<'a> = TransactionMut<'a, FileStorage>;

/// The purely in-memory implementation of the database. It has no persistence but offers
/// unmatched performance
/// unmatched performance.
pub type DbMemory = DbImpl<MemoryStorage>;

/// A convenience alias for the [`Transaction`] type for the default [`DbMemory`].
Expand All @@ -235,7 +235,8 @@ impl<Store: StorageData> std::fmt::Debug for DbImpl<Store> {
}

impl<Store: StorageData> DbImpl<Store> {
/// Tries to create or load `filename` file as `Db` object.
/// Tries to create or load `filename` file as `Db` object. For in-memory storage
/// this will either load the data from file once (if present) or create an empty database.
pub fn new(filename: &str) -> Result<Self, DbError> {
match Self::try_new(filename) {
Ok(db) => Ok(db),
Expand All @@ -251,7 +252,9 @@ impl<Store: StorageData> DbImpl<Store> {
/// to `filename` path. Consider calling `optimize_storage()`
/// prior to this function to reduce the size of the storage
/// file. If speed is of the essence you may omit that operation
/// at expense of the file size.
/// at expense of the file size. For memory based storage this will
/// dump the internal buffer to the `filename` which can be used to
/// restore back the database by `DbMemory::new()`.
pub fn backup(&self, filename: &str) -> Result<(), DbError> {
self.storage.backup(filename)
}
Expand Down
11 changes: 10 additions & 1 deletion agdb/src/storage/memory_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ impl MemoryStorage {
}

impl StorageData for MemoryStorage {
fn backup(&self, name: &str) -> Result<(), DbError> {
std::fs::write(name, &self.buffer)?;
Ok(())
}

fn copy(&self, name: &str) -> Result<Self, DbError> {
Ok(Self {
buffer: self.buffer.clone(),
Expand All @@ -40,7 +45,11 @@ impl StorageData for MemoryStorage {

fn new(name: &str) -> Result<Self, DbError> {
Ok(Self {
buffer: vec![],
buffer: if let Ok(true) = std::fs::exists(name) {
std::fs::read(name)?
} else {
vec![]
},
name: name.to_string(),
})
}
Expand Down
27 changes: 27 additions & 0 deletions agdb/tests/db_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,33 @@ fn hot_backup() {
t1.join().unwrap();
}

#[test]
fn memory_backup() {
let test_file = TestFile::new();

{
let mut db = DbMemory::new("memdb").unwrap();
db.exec_mut(QueryBuilder::insert().nodes().count(1).query())
.unwrap();
db.backup(test_file.file_name()).unwrap();
assert!(std::fs::exists(test_file.file_name()).unwrap());
db.exec_mut(QueryBuilder::insert().nodes().count(1).query())
.unwrap();
}

let db = DbMemory::new(test_file.file_name()).unwrap();
assert_eq!(
db.exec(QueryBuilder::select().node_count().query())
.unwrap()
.elements[0]
.values[0]
.value
.to_u64()
.unwrap(),
1
);
}

#[test]
fn filename() {
let test_file = TestFile::new();
Expand Down
Loading