btrbk: get_latest_common(): use all brothers (snapshots with same parent) as candidates (older first, then newer) instead of only older; as last resort, use subvolumes in snapshot_dir matching btrbk file name scheme as candidates

pull/88/head
Axel Burri 2016-04-05 23:37:08 +02:00
parent 46e3aae857
commit bfb556757d
1 changed files with 42 additions and 34 deletions

76
btrbk
View File

@ -1773,36 +1773,48 @@ sub get_latest_common($$$;$)
my $sroot = shift || die;
my $svol = shift // die;
my $droot = shift || die;
my $threshold_gen = shift; # skip all snapshot children with generation (cgen) >= $threshold_gen
my $snapshot_dir = shift; # if not set, skip search for btrbk basename (set to empty string to enable at current dir)
my $sroot_subvol_list = vinfo_subvol_list($sroot);
my $debug_src = $svol->{URL};
$debug_src .= "#" . $threshold_gen if($threshold_gen);
TRACE "get_latest_common: resolving latest common for subvolume: $svol->{PATH} (sroot=$sroot->{PRINT}, droot=$droot->{PRINT})";
TRACE "get_latest_common: resolving latest common for subvolume: $svol->{PATH} (sroot=$sroot->{PRINT}, droot=$droot->{PRINT}, snapdir=\"" . ($snapshot_dir // '<undef>') . "\")";
my @candidate;
if($svol->{node}{readonly}) {
my $sroot_subvol_list = vinfo_subvol_list($sroot);
if($svol->{node}{received_uuid} ne '-') {
if($svol->{node}{parent_uuid} ne '-') {
@candidate = grep { $_->{node}{uuid} eq $svol->{node}{parent_uuid} } @$sroot_subvol_list;
TRACE "get_latest_common: subvolume is a read-only receive target and has parents, add " . scalar(@candidate) . " parent candidates";
}
else {
TRACE "get_latest_common: subvolume is a read-only receive target without parent_uuid";
}
if($svol->{node}{parent_uuid} ne '-') {
# add readonly parent
@candidate = grep { $_->{node}{readonly} && ($_->{node}{uuid} eq $svol->{node}{parent_uuid}) } @$sroot_subvol_list;
die "multiple parents for $svol->{node}{parent_uuid}" if(scalar(@candidate) > 1);
TRACE "get_latest_common: subvolume has a read-only parent, add parent candidate" if(scalar(@candidate) > 0);
# add snapshots with same parent_uuid
my @brothers = grep { $_->{node}{readonly} && ($_->{node}{parent_uuid} eq $svol->{node}{parent_uuid}) } @$sroot_subvol_list;
my @brothers_older = grep { $_->{node}{cgen} <= $svol->{node}{cgen} } @brothers;
my @brothers_newer = grep { $_->{node}{cgen} > $svol->{node}{cgen} } @brothers;
push @candidate, sort { $b->{node}{cgen} <=> $a->{node}{cgen} } @brothers_older; # older first, descending by cgen
push @candidate, sort { $a->{node}{cgen} <=> $b->{node}{cgen} } @brothers_newer; # then newer, ascending by cgen
TRACE "get_latest_common: subvolume has brothers (same parent_uuid), add " . scalar(@brothers_older) . " older and " . scalar(@brothers_newer) . " newer (by cgen) candidates";
}
if(defined($snapshot_dir) && defined($svol->{btrbk_basename})) {
# add subvolumes in same directory matching btrbk file name scheme
my @naming_match = grep { $_->{node}{readonly} && defined($_->{btrbk_basename}) && ($_->{SUBVOL_DIR} eq $snapshot_dir) && ($_->{btrbk_basename} eq $svol->{btrbk_basename}) } @$sroot_subvol_list;
my @naming_match_older = grep { cmp_date($_->{btrbk_date}, $svol->{btrbk_date}) < 0 } @naming_match;
my @naming_match_newer = grep { cmp_date($_->{btrbk_date}, $svol->{btrbk_date}) > 0 } @naming_match;
push @candidate, sort { cmp_date($b->{btrbk_date}, $a->{btrbk_date}) } @naming_match_older;
push @candidate, sort { cmp_date($a->{btrbk_date}, $b->{btrbk_date}) } @naming_match_newer;
TRACE "get_latest_common: subvolume has btrbk naming scheme, add " . scalar(@naming_match_older) . " older and " . scalar(@naming_match_newer) . " newer (by file suffix) candidates with scheme: $sroot->{PRINT}/$snapshot_dir/$svol->{btrbk_basename}.*";
}
# add all subvolumes in same directory matching btrbk file name scheme
my @naming_match = grep { $_->{node}{readonly} && $_->{btrbk_direct_leaf} && ($_->{btrbk_basename} eq $svol->{btrbk_basename}) } @$sroot_subvol_list;
my @naming_match_older = grep { cmp_date($_->{btrbk_date}, $svol->{btrbk_date}) < 0 } @naming_match;
my @naming_match_newer = grep { cmp_date($_->{btrbk_date}, $svol->{btrbk_date}) > 0 } @naming_match;
push @candidate, sort { cmp_date($b->{btrbk_date}, $a->{btrbk_date}) } @naming_match_older;
push @candidate, sort { cmp_date($a->{btrbk_date}, $b->{btrbk_date}) } @naming_match_newer;
TRACE "get_latest_common: subvolume is a receive target, add " . scalar(@naming_match_older) . " older and " . scalar(@naming_match_newer) . " newer candidates with btrbk naming scheme: $sroot->{PRINT}/$svol->{btrbk_basename}.*";
die if($threshold_gen);
}
else {
else
{
@candidate = sort { $b->{node}{cgen} <=> $a->{node}{cgen} } get_snapshot_children($sroot, $svol);
TRACE "get_latest_common: subvolume is read-write, add " . scalar(@candidate) . " snapshot children, sorted by cgen: $svol->{PATH}";
if(defined($snapshot_dir)) {
# add subvolumes in same directory matching btrbk file name scheme
my @naming_match = grep { $_->{node}{readonly} && defined($_->{btrbk_basename}) && ($_->{SUBVOL_DIR} eq $snapshot_dir) && ($_->{btrbk_basename} eq $svol->{NAME}) } @$sroot_subvol_list;
push @candidate, sort { cmp_date($b->{btrbk_date}, $a->{btrbk_date}) } @naming_match;
TRACE "get_latest_common: snapshot_dir is set, add " . scalar(@naming_match) . " candidates with scheme: $sroot->{PRINT}/$snapshot_dir/$svol->{NAME}.*";
}
}
@ -1816,25 +1828,21 @@ sub get_latest_common($$$;$)
}
foreach my $child (@candidate) {
TRACE "get_latest_common: checking candidate: $child->{PRINT}";
if($threshold_gen && ($child->{node}{cgen} >= $threshold_gen)) {
TRACE "get_latest_common: skipped candidate gen=$child->{node}{cgen} >= $threshold_gen";
if($child->{node}{id} == $svol->{node}{id}) {
TRACE "get_latest_common: skip self: $child->{PRINT}";
next;
}
if(my $received_subvol = $receive_target_present{$child->{node}{uuid}}) {
# subvolume has been previously received
DEBUG("Latest common subvolumes for: $debug_src: src=$child->{PRINT} target=$received_subvol->{PRINT} (previously received)");
DEBUG("Latest common subvolumes for: $svol->{PRINT}: src=$child->{PRINT} target=$received_subvol->{PRINT} (previously received)");
return ($child, $received_subvol);
}
foreach (get_receive_targets($droot, $child)) {
DEBUG("Latest common subvolumes for: $debug_src: src=$child->{PRINT} target=$_->{PRINT}");
DEBUG("Latest common subvolumes for: $svol->{PRINT}: src=$child->{PRINT} target=$_->{PRINT}");
return ($child, $_);
}
TRACE "get_latest_common: no matching target found for candidate: $child->{PRINT}";
}
DEBUG("No common subvolumes of \"$debug_src\" found in src=\"$sroot->{PRINT}/\", target=\"$droot->{PRINT}/\"");
DEBUG("No common subvolumes of \"$svol->{PRINT}\" found in src=\"$sroot->{PRINT}/\", target=\"$droot->{PRINT}/\"");
return (undef, undef);
}
@ -4097,7 +4105,7 @@ MAIN:
foreach my $child (sort { $a->{node}{cgen} <=> $b->{node}{cgen} } @resume)
{
INFO "Resuming subvolume backup (send-receive) for: $child->{PRINT}";
my ($latest_common_src, $latest_common_target) = get_latest_common($sroot, $svol, $droot, $child->{node}{cgen});
my ($latest_common_src, $latest_common_target) = get_latest_common($sroot, $child, $droot, $snapdir);
if(macro_send_receive(source => $child,
target => $droot,
parent => $latest_common_src, # this is <undef> if no common found
@ -4129,7 +4137,7 @@ MAIN:
# finally receive the previously created snapshot
INFO "Creating subvolume backup (send-receive) for: $svol->{PRINT}";
my ($latest_common_src, $latest_common_target) = get_latest_common($sroot, $svol, $droot);
my ($latest_common_src, $latest_common_target) = get_latest_common($sroot, $svol, $droot, $snapdir);
macro_send_receive(source => $svol->{SNAPSHOT_CREATED},
target => $droot,
parent => $latest_common_src, # this is <undef> if no common found