summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Pritz <bluewind@xinu.at>2016-08-08 16:45:30 +0200
committerFlorian Pritz <bluewind@xinu.at>2016-08-08 16:45:30 +0200
commit40f3f1d3308a43a1e98e31a93f8c47042da87f1f (patch)
tree4df9c52453caafdd95011962e9dea557a4705763
parent489f2eefcdfd5f5f6acf6628404aa5aa9c44beee (diff)
downloadbin-40f3f1d3308a43a1e98e31a93f8c47042da87f1f.tar.gz
bin-40f3f1d3308a43a1e98e31a93f8c47042da87f1f.tar.xz
borg-restore.pl: WIP
Signed-off-by: Florian Pritz <bluewind@xinu.at>
-rwxr-xr-xborg-restore.pl98
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: $!";
}