diff options
author | Florian Pritz <bluewind@xinu.at> | 2016-08-08 16:45:30 +0200 |
---|---|---|
committer | Florian Pritz <bluewind@xinu.at> | 2016-08-08 16:45:30 +0200 |
commit | 40f3f1d3308a43a1e98e31a93f8c47042da87f1f (patch) | |
tree | 4df9c52453caafdd95011962e9dea557a4705763 /borg-restore.pl | |
parent | 489f2eefcdfd5f5f6acf6628404aa5aa9c44beee (diff) | |
download | bin-40f3f1d3308a43a1e98e31a93f8c47042da87f1f.tar.gz bin-40f3f1d3308a43a1e98e31a93f8c47042da87f1f.tar.xz |
borg-restore.pl: WIP
Signed-off-by: Florian Pritz <bluewind@xinu.at>
Diffstat (limited to 'borg-restore.pl')
-rwxr-xr-x | borg-restore.pl | 98 |
1 files changed, 68 insertions, 30 deletions
diff --git a/borg-restore.pl b/borg-restore.pl index dd76dee..84486f2 100755 --- a/borg-restore.pl +++ b/borg-restore.pl @@ -34,20 +34,21 @@ use autodie; use Cwd qw(abs_path); use Data::Dumper; use DateTime; +use DB_File; +use Devel::Size qw(total_size); use File::Basename; +use File::Copy; use File::Path qw(mkpath); use File::Slurp; use Getopt::Long; use IO::Compress::Gzip qw($GzipError); use IPC::Run qw(run start); -use Pod::Usage; -use DB_File; -use MLDBM qw(GDBM_File Storable); -use Time::HiRes; -use Devel::Size qw(total_size); -use Storable; use List::MoreUtils qw(firstidx); use List::Util qw(any all); +use MLDBM qw(GDBM_File Storable); +use Pod::Usage; +use Storable; +use Time::HiRes; my %opts; my $cache_path_base = "/home/flo/.cache/borg-restore.pl"; @@ -76,7 +77,7 @@ sub borg_list { } } - splice @archives, 4; + splice @archives, 10; #splice @archives, 1, 1; return \@archives; @@ -92,20 +93,22 @@ sub find_archives { my $modtimes = $db{$path}; untie %db; - my $last_modtime; + my %seen_modtime; my @ret; + debug(sprintf("Found %d archive(s) with the following times for %s", @$modtimes+0, $path)); + debug(Dumper(@$modtimes)); + debug("Building archive list"); for my $archive (@$archives) { my $modtime = $$modtimes[get_archive_index($archive, $archives)]; - if (defined($modtime) && (!defined($last_modtime) || $modtime > $last_modtime)) { + if (defined($modtime) && (!$seen_modtime{$modtime}++)) { push @ret, { modification_time => $modtime, archive => $archive, }; - $last_modtime = $modtime; } } @@ -113,6 +116,8 @@ sub find_archives { printf "\e[0;91mWarning:\e[0m Path '%s' not found in any archive.\n", $path; } + @ret = sort { $a->{modification_time} cmp $b->{modification_time} } @ret; + return \@ret; } @@ -225,6 +230,7 @@ sub handle_removed_archives { my $archives = shift; my $previous_archives = shift; my $borg_archives = shift; + my $db_path = shift; my $start = Time::HiRes::gettimeofday(); @@ -247,8 +253,9 @@ sub handle_removed_archives { } clean_db($db); - compact_db(); + compact_db($db_path); + save_database($archives, 1); my $end = Time::HiRes::gettimeofday(); debug(sprintf("Removing archives finished after: %.5fs", $end - $start)); } @@ -274,9 +281,9 @@ sub handle_added_archives { my $db = shift; my $archives = shift; my $borg_archives = shift; + my $db_path = shift; my $add_archives = get_missing_items($archives, $borg_archives); - push @$archives, @$add_archives; for my $archive (@$add_archives) { my $start = Time::HiRes::gettimeofday(); @@ -285,11 +292,8 @@ sub handle_added_archives { debug(sprintf("Adding archive %s at index %d", $archive, $archive_index)); - # FIXME: remove /dev/null redirect my $proc = start [qw(borg list --list-format), '{isomtime} {path}{NEWLINE}', "::".$archive], ">pipe", \*OUT; - #my $counter = 20; while (<OUT>) { - #close OUT if $counter--<0; # roll our own parsing of timestamps for speed since we will be parsing # a huge number of lines here # example timestamp: "Wed, 2016-01-27 10:31:59" @@ -300,23 +304,50 @@ sub handle_added_archives { } } $proc->finish() or die "borg list returned $?"; - #$proc->finish(); - - #say "Total size lookup table: ", total_size($lookuptable); - #say "Total size output hash: ", total_size(\%output); save_node($db, $archive_index, undef, $lookuptable); - compact_db(); + push @$archives, $archive; + + compact_db($db_path); + save_database($archives, 1); + my $end = Time::HiRes::gettimeofday(); debug(sprintf("Adding archive finished after: %.5fs", $end - $start)); - #print Dumper($db); + } +} + +sub save_database { + my $archives = shift; + my $keep_temp_db = shift; + + my $db_path = get_cache_path('archives.db'); + my $db_path_tmp = get_cache_path('archives.db.tmp'); + my $archive_cache = get_cache_path('archive_list'); + my $archive_cache_tmp = get_cache_path('archive_list.tmp'); + + debug("Saving temporary database to permanent location"); + + store $archives, $archive_cache_tmp or die "Failed to save archive list to cache: $!"; + + unlink($archive_cache); + unlink($db_path); + + # FIXME this doesn't work because the opened database will later be overwritten + # either copy or reopen db + move($archive_cache_tmp, $archive_cache); + move($db_path_tmp, $db_path); + + if ($keep_temp_db) { + cp($db_path, $db_path_tmp); } } sub build_archive_cache { my $borg_archives = borg_list(); my $db_path = get_cache_path('archives.db'); + my $db_path_tmp = get_cache_path('archives.db.tmp'); my $archive_cache = get_cache_path('archive_list'); + my $archive_cache_tmp = get_cache_path('archive_list.tmp'); my $previous_archives = []; my $archives = []; @@ -332,20 +363,26 @@ sub build_archive_cache { # ensure the cache directory exists mkpath(get_cache_dir(), {mode => 0700}); - # TODO when the database is updated, create a temporary copy, create a copy - # of the settings database and then rename both. - # TODO save database to real location each time an archive has been added or removed + if (-f $db_path) { + # TODO run this only when the database will actually be changed? + debug("Creating temporary database copy"); + cp($db_path, $db_path_tmp) or die "Failed to create temproary database copy: $!"; + } + my %db; - tie %db, 'MLDBM', $db_path, O_RDWR|O_CREAT, 0600 or die "Failed to open db file: $!"; + tie %db, 'MLDBM', $db_path_tmp, O_RDWR|O_CREAT, 0600 or die "Failed to open db file: $!"; - handle_removed_archives(\%db, $archives, $previous_archives, $borg_archives); - handle_added_archives(\%db, $archives, $borg_archives); + handle_removed_archives(\%db, $archives, $previous_archives, $borg_archives, $db_path_tmp); + handle_added_archives(\%db, $archives, $borg_archives, $db_path_tmp); print Dumper(0+keys %db, $db{"home/flo/TODO"}); untie %db; - store $archives, $archive_cache or die "Failed to save archive list to cache: $!"; - # TODO rename temp caches here + unlink($db_path_tmp); +} + +sub cp { + run([qw(cp -p), @_]); } sub save_node { @@ -401,7 +438,8 @@ sub clean_db { } sub compact_db { - my $db_path = get_cache_path("archives.db"); + my $db_path = shift; + run([qw(echo reorganize)], "|", ["gdbmtool", $db_path]) or die "Failed to reorganize database: $!"; } |