btrbk: added "snapshot_create onchange", which skips snapshot creation if the latest snapshot is up-to-date (i.e. has same generation as the source subvolume)

pull/30/head
Axel Burri 2015-05-25 14:38:32 +02:00
parent 27e150878c
commit 16355b848d
3 changed files with 58 additions and 16 deletions

View File

@ -1,3 +1,9 @@
btrbk-current
* Added "snapshot_create onchange", which skips snapshot creation if
the latest snapshot is up-to-date (i.e. has same generation as the
source subvolume)
btrbk-0.18.0 btrbk-0.18.0
* MIGRATION * MIGRATION

47
btrbk
View File

@ -47,7 +47,7 @@ use Date::Calc qw(Today Delta_Days Day_of_Week);
use Getopt::Std; use Getopt::Std;
use Data::Dumper; use Data::Dumper;
our $VERSION = "0.18.0"; our $VERSION = "0.19.0-dev";
our $AUTHOR = 'Axel Burri <axel@tty0.ch>'; our $AUTHOR = 'Axel Burri <axel@tty0.ch>';
our $PROJECT_HOME = '<http://www.digint.ch/btrbk/>'; our $PROJECT_HOME = '<http://www.digint.ch/btrbk/>';
@ -62,7 +62,7 @@ my %config_options = (
# NOTE: keys "volume", "subvolume" and "target" are hardcoded # NOTE: keys "volume", "subvolume" and "target" are hardcoded
snapshot_dir => { default => undef, accept_file => { relative => 1 } }, snapshot_dir => { default => undef, accept_file => { relative => 1 } },
snapshot_name => { default => undef, accept_file => { name_only => 1 }, context => [ "subvolume" ] }, snapshot_name => { default => undef, accept_file => { name_only => 1 }, context => [ "subvolume" ] },
snapshot_create => { default => "always", accept => [ "no", "always", "ondemand" ] }, snapshot_create => { default => "always", accept => [ "no", "always", "ondemand", "onchange" ] },
incremental => { default => "yes", accept => [ "yes", "no", "strict" ] }, incremental => { default => "yes", accept => [ "yes", "no", "strict" ] },
resume_missing => { default => "yes", accept => [ "yes", "no" ] }, resume_missing => { default => "yes", accept => [ "yes", "no" ] },
preserve_day_of_week => { default => "sunday", accept => [ (keys %day_of_week_map) ] }, preserve_day_of_week => { default => "sunday", accept => [ (keys %day_of_week_map) ] },
@ -1173,6 +1173,27 @@ sub get_latest_common($$$;$)
} }
sub get_latest_snapshot_child($$)
{
my $sroot = shift || die;
my $svol = shift // die;
my $latest = undef;
my $gen = -1;
foreach (get_snapshot_children($sroot, $svol)) {
if($_->{gen} > $gen) {
$latest = $_;
$gen = $_->{gen};
}
}
if($latest) {
DEBUG "Latest snapshot child for \"$svol->{PRINT}#$svol->{gen}\" is: $latest->{PRINT}#$latest->{gen}";
} else {
DEBUG "No latest snapshots found for: $svol->{PRINT}";
}
return $latest;
}
sub _origin_tree sub _origin_tree
{ {
my $prefix = shift; my $prefix = shift;
@ -1782,13 +1803,23 @@ MAIN:
my $snapshot_basename = config_key($config_subvol, "snapshot_name") // die; my $snapshot_basename = config_key($config_subvol, "snapshot_name") // die;
# check if we need to create a snapshot # check if we need to create a snapshot
my $snapshot_create = config_key($config_subvol, "snapshot_create") // "no"; my $snapshot_create = config_key($config_subvol, "snapshot_create");
if($snapshot_create eq "no") { if(not $snapshot_create) {
DEBUG "Snapshot creation disabled: snapshot_create=no"; DEBUG "Snapshot creation disabled (snapshot_create=no)";
next; next;
} }
if($snapshot_create eq "always") { elsif($snapshot_create eq "always") {
DEBUG "Snapshot creation enabled: snapshot_create=always"; DEBUG "Snapshot creation enabled (snapshot_create=always)";
}
elsif($snapshot_create eq "onchange") {
# check if latest snapshot is up-to-date with source subvolume (by generation)
my $latest = get_latest_snapshot_child($sroot, $svol);
if($latest && ($latest->{gen} == $svol->{gen})) {
INFO "Snapshot creation skipped: snapshot_create=onchange, snapshot is up-to-date: $latest->{PRINT}";
$config_subvol->{SNAPSHOT_UP_TO_DATE} = $latest;
next;
}
DEBUG "Snapshot creation enabled: snapshot_create=onchange, gen=$svol->{gen} > snapshot_gen=$latest->{gen}";
} }
elsif($snapshot_create eq "ondemand") { elsif($snapshot_create eq "ondemand") {
my $snapshot_needed = 0; my $snapshot_needed = 0;
@ -2106,6 +2137,7 @@ MAIN:
push @subvol_out, "!!! Subvolume \"$svol->{PRINT}\" aborted: $config_subvol->{ABORTED}"; push @subvol_out, "!!! Subvolume \"$svol->{PRINT}\" aborted: $config_subvol->{ABORTED}";
$err_count++ unless($config_subvol->{ABORTED_NOERR}); $err_count++ unless($config_subvol->{ABORTED_NOERR});
} }
push @subvol_out, "=== $config_subvol->{SNAPSHOT_UP_TO_DATE}->{PRINT}" if($config_subvol->{SNAPSHOT_UP_TO_DATE});
push @subvol_out, "+++ $config_subvol->{SNAPSHOT}->{PRINT}" if($config_subvol->{SNAPSHOT}); push @subvol_out, "+++ $config_subvol->{SNAPSHOT}->{PRINT}" if($config_subvol->{SNAPSHOT});
if($config_subvol->{SUBVOL_DELETED}) { if($config_subvol->{SUBVOL_DELETED}) {
push @subvol_out, "--- $_->{PRINT}" foreach(sort { $a->{PATH} cmp $b->{PATH} } @{$config_subvol->{SUBVOL_DELETED}}); push @subvol_out, "--- $_->{PRINT}" foreach(sort { $a->{PATH} cmp $b->{PATH} } @{$config_subvol->{SUBVOL_DELETED}});
@ -2146,6 +2178,7 @@ MAIN:
print " Date: " . localtime($start_time) . "\n"; print " Date: " . localtime($start_time) . "\n";
print " Config: $config->{SRC_FILE}\n"; print " Config: $config->{SRC_FILE}\n";
print "\nLegend:\n"; print "\nLegend:\n";
print " === up-to-date subvolume (source snapshot)\n";
print " +++ created subvolume (source snapshot)\n"; print " +++ created subvolume (source snapshot)\n";
print " --- deleted subvolume\n"; print " --- deleted subvolume\n";
print " *** received subvolume (non-incremental)\n"; print " *** received subvolume (non-incremental)\n";

View File

@ -55,15 +55,18 @@ will fail if it is not present.
backup). This option is only valid in the \fItarget\fR backup). This option is only valid in the \fItarget\fR
section. Defaults to \fI<subvolume-name>\fR. section. Defaults to \fI<subvolume-name>\fR.
.TP .TP
\fBsnapshot_create\fR always|ondemand|no \fBsnapshot_create\fR always|ondemand|onchange|no
If set to \[lq]ondemand\[rq], the snapshots are only created if the If set to \[lq]ondemand\[rq], snapshots are only created if the target
target subvolume is reachable (useful if you are tight on disk space subvolume is reachable (useful if you are tight on disk space and you
and you only need btrbk for backups to an external disk which is not only need btrbk for backups to an external disk which is not always
always connected). If set to \[lq]always\[rq], the snapshots are connected). If set to \[lq]onchange\[rq], snapshots are only created
always created, regardless of the target reachability. If set to if the source subvolume has changed since the last snapshot (more
\[lq]no\[rq], the snapshots are never created (useful in conjunction precisely: if the btrfs generation has been increased since the last
with the \fIresume_missing\fR option if another instance of btrbk is snapshot). If set to \[lq]always\[rq], snapshots are always
taking care of snapshot creation). Defaults to \[lq]always\[rq]. created. If set to \[lq]no\[rq], the snapshots are never created
(useful in conjunction with the \fIresume_missing\fR option if another
instance of btrbk is taking care of snapshot creation). Defaults to
\[lq]always\[rq].
.TP .TP
\fBincremental\fR yes|no|strict \fBincremental\fR yes|no|strict
If set, incremental backups are created. If set to \[lq]strict\[rq], If set, incremental backups are created. If set to \[lq]strict\[rq],