2020-07-02 16:20:45 +02:00
use crate ::Data ;
use crate ::error ::Error ;
2020-07-28 14:41:49 +02:00
use crate ::helpers ::compression ;
2020-07-02 16:20:45 +02:00
use log ::error ;
2020-07-28 14:41:49 +02:00
use std ::fs ::create_dir_all ;
2020-07-02 16:20:45 +02:00
use std ::path ::Path ;
use std ::thread ;
use std ::time ::{ Duration } ;
use tempfile ::TempDir ;
pub fn load_snapshot (
db_path : & str ,
snapshot_path : & Path ,
ignore_snapshot_if_db_exists : bool ,
ignore_missing_snapshot : bool
) -> Result < ( ) , Error > {
let db_path = Path ::new ( db_path ) ;
if ! db_path . exists ( ) & & snapshot_path . exists ( ) {
2020-07-28 14:41:49 +02:00
compression ::from_tar_gz ( snapshot_path , db_path )
2020-07-02 16:20:45 +02:00
} else if db_path . exists ( ) & & ! ignore_snapshot_if_db_exists {
Err ( Error ::Internal ( format! ( " database already exists at {:?} " , db_path ) ) )
} else if ! snapshot_path . exists ( ) & & ! ignore_missing_snapshot {
Err ( Error ::Internal ( format! ( " snapshot doesn't exist at {:?} " , snapshot_path ) ) )
} else {
Ok ( ( ) )
}
}
pub fn create_snapshot ( data : & Data , snapshot_path : & Path ) -> Result < ( ) , Error > {
let tmp_dir = TempDir ::new ( ) ? ;
data . db . copy_and_compact_to_path ( tmp_dir . path ( ) ) ? ;
2020-07-28 14:41:49 +02:00
compression ::to_tar_gz ( tmp_dir . path ( ) , snapshot_path ) . or_else ( | e | Err ( Error ::Internal ( format! ( " something went wrong during snapshot compression: {} " , e ) ) ) )
2020-07-02 16:20:45 +02:00
}
pub fn schedule_snapshot ( data : Data , snapshot_dir : & Path , time_gap_s : u64 ) -> Result < ( ) , Error > {
if snapshot_dir . file_name ( ) . is_none ( ) {
return Err ( Error ::Internal ( " invalid snapshot file path " . to_string ( ) ) ) ;
}
let db_name = Path ::new ( & data . db_path ) . file_name ( ) . ok_or_else ( | | Error ::Internal ( " invalid database name " . to_string ( ) ) ) ? ;
create_dir_all ( snapshot_dir ) ? ;
let snapshot_path = snapshot_dir . join ( format! ( " {} .tar.gz " , db_name . to_str ( ) . unwrap_or ( " data.ms " ) ) ) ;
thread ::spawn ( move | | loop {
thread ::sleep ( Duration ::from_secs ( time_gap_s ) ) ;
if let Err ( e ) = create_snapshot ( & data , & snapshot_path ) {
error! ( " Unsuccessful snapshot creation: {} " , e ) ;
}
} ) ;
Ok ( ( ) )
}
#[ cfg(test) ]
mod tests {
use super ::* ;
use std ::io ::prelude ::* ;
use std ::fs ;
#[ test ]
fn test_pack_unpack ( ) {
let tempdir = TempDir ::new ( ) . unwrap ( ) ;
let test_dir = tempdir . path ( ) ;
let src_dir = test_dir . join ( " src " ) ;
let dest_dir = test_dir . join ( " complex/destination/path/ " ) ;
let archive_path = test_dir . join ( " archive.tar.gz " ) ;
let file_1_relative = Path ::new ( " file1.txt " ) ;
let subfolder_relative = Path ::new ( " subfolder/ " ) ;
let file_2_relative = Path ::new ( " subfolder/file2.txt " ) ;
create_dir_all ( src_dir . join ( subfolder_relative ) ) . unwrap ( ) ;
2020-07-28 14:41:49 +02:00
fs ::File ::create ( src_dir . join ( file_1_relative ) ) . unwrap ( ) . write_all ( b " Hello_file_1 " ) . unwrap ( ) ;
fs ::File ::create ( src_dir . join ( file_2_relative ) ) . unwrap ( ) . write_all ( b " Hello_file_2 " ) . unwrap ( ) ;
2020-07-02 16:20:45 +02:00
2020-07-28 14:41:49 +02:00
assert! ( compression ::to_tar_gz ( & src_dir , & archive_path ) . is_ok ( ) ) ;
2020-07-02 16:20:45 +02:00
assert! ( archive_path . exists ( ) ) ;
assert! ( load_snapshot ( & dest_dir . to_str ( ) . unwrap ( ) , & archive_path , false , false ) . is_ok ( ) ) ;
assert! ( dest_dir . exists ( ) ) ;
assert! ( dest_dir . join ( file_1_relative ) . exists ( ) ) ;
assert! ( dest_dir . join ( subfolder_relative ) . exists ( ) ) ;
assert! ( dest_dir . join ( file_2_relative ) . exists ( ) ) ;
let contents = fs ::read_to_string ( dest_dir . join ( file_1_relative ) ) . unwrap ( ) ;
assert_eq! ( contents , " Hello_file_1 " ) ;
let contents = fs ::read_to_string ( dest_dir . join ( file_2_relative ) ) . unwrap ( ) ;
assert_eq! ( contents , " Hello_file_2 " ) ;
}
}