mirror of https://github.com/digint/btrbk
btrbk: fix get_related_subvolume_nodes: add all parents and orphaned siblings
Old implementation was missing last readonly parent in chain, as well as orphaned siblings. Also sort all by cgen, not by distance, then cgen. Also skip self.pull/274/head
parent
20c390893a
commit
95e25eb2d1
80
btrbk
80
btrbk
|
@ -3031,57 +3031,78 @@ sub get_best_correlated_target($$;@)
|
||||||
|
|
||||||
sub _push_related_children
|
sub _push_related_children
|
||||||
{
|
{
|
||||||
my $node = shift;
|
my $node = shift; # can be undef, siblings are considered related even if parent is gone
|
||||||
|
my $uuid = shift;
|
||||||
|
my $parent_uuid_hash = shift;
|
||||||
my $related = shift;
|
my $related = shift;
|
||||||
my $prune = shift;
|
my $prune = shift;
|
||||||
my $distance = shift // 0;
|
my $distance = shift;
|
||||||
my $cgen_ref = shift;
|
|
||||||
|
|
||||||
if($distance >= 256) {
|
if($distance >= 256) {
|
||||||
WARN "Maximum distance reached, aborting related subvolume search";
|
WARN "Maximum distance reached, aborting related subvolume search";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return if(defined($prune) && ($node->{id} == $prune->{id}));
|
if($node) {
|
||||||
|
if($distance == 0) {
|
||||||
my $children = $node->{TREE_ROOT}{PARENT_UUID_HASH}->{$node->{uuid}} // [];
|
# hacky, we want to skip ourself, and $node=$vol->{node} if distance=0
|
||||||
my @readonly = grep { $_->{readonly} } @$children;
|
TRACE "related_nodes: d=$distance uuid=$uuid : related self: " . _fs_path($node);
|
||||||
TRACE "related_nodes: add " . scalar(@readonly) . " readonly children of uuid=$node->{uuid} (distance=$distance)" if(scalar(@readonly));
|
} elsif($node->{readonly}) {
|
||||||
|
TRACE "related_nodes: d=$distance uuid=$uuid : push related readonly: " . _fs_path($node);
|
||||||
# sort by absolute cgen delta, favor older
|
push @$related, $node;
|
||||||
push @$related, sort { (abs($cgen_ref - $a->{cgen}) <=> abs($cgen_ref - $b->{cgen})) ||
|
} else {
|
||||||
($a->{cgen} <=> $b->{cgen})
|
TRACE "related_nodes: d=$distance uuid=$uuid : related not readonly: " . _fs_path($node);
|
||||||
} @readonly;
|
|
||||||
|
|
||||||
# recurse into all child subvolumes
|
|
||||||
foreach(@$children) {
|
|
||||||
_push_related_children($_, $related, $prune, $distance + 1, $cgen_ref);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
TRACE "related_nodes: d=$distance uuid=$uuid : missing (deleted)";
|
||||||
|
}
|
||||||
|
|
||||||
|
# recurse into all child subvolumes (even if parent is missing -> siblings)
|
||||||
|
my $children = $parent_uuid_hash->{$uuid} // [];
|
||||||
|
foreach(@$children) {
|
||||||
|
if(defined($prune) && ($_->{id} == $prune->{id})) {
|
||||||
|
TRACE "related_nodes: d=$distance uuid=$uuid : pruning processed uuid=$_->{uuid}";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
TRACE "related_nodes: d=$distance uuid=$uuid : processing child uuid=$_->{uuid}";
|
||||||
|
_push_related_children($_, $_->{uuid}, $parent_uuid_hash, $related, $prune, $distance + 1);
|
||||||
|
}
|
||||||
|
TRACE "related_nodes: d=$distance uuid=$uuid : processed " . (scalar @$children) . " children";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# returns subvolume nodes related to $vol (by parent_uuid relationship),
|
# returns all related readonly nodes (by parent_uuid relationship),
|
||||||
# sorted by parent/child distance and cgen delta.
|
# sort by absolute cgen delta, favor older
|
||||||
sub get_related_subvolume_nodes($)
|
sub get_related_subvolume_nodes($)
|
||||||
{
|
{
|
||||||
my $vol = shift // die;
|
my $vol = shift // die;
|
||||||
my $cgen_ref = $vol->{node}{readonly} ? $vol->{node}{cgen} : $vol->{node}{gen};
|
|
||||||
TRACE "related_nodes: resolving related subvolumes of: $vol->{PATH}";
|
TRACE "related_nodes: resolving related subvolumes of: $vol->{PATH}";
|
||||||
|
|
||||||
# iterate parent chain
|
# iterate parent chain
|
||||||
my @related_nodes;
|
my @related_nodes;
|
||||||
my $uuid_hash = $vol->{node}{TREE_ROOT}{UUID_HASH};
|
my $uuid_hash = $vol->{node}{TREE_ROOT}{UUID_HASH};
|
||||||
my $parent_it = $vol->{node};
|
my $parent_uuid_hash = $vol->{node}{TREE_ROOT}{PARENT_UUID_HASH};
|
||||||
my $last_parent;
|
my $node = $vol->{node};
|
||||||
|
my $uuid = $node->{uuid};
|
||||||
|
my $last_node;
|
||||||
my $distance = 0;
|
my $distance = 0;
|
||||||
while($parent_it && ($distance <= 256)) {
|
while($distance < 256) {
|
||||||
_push_related_children($parent_it, \@related_nodes, $last_parent, $distance + 1, $cgen_ref);
|
_push_related_children($node, $uuid, $parent_uuid_hash, \@related_nodes, $last_node, $distance);
|
||||||
$last_parent = $parent_it;
|
last unless $node;
|
||||||
$parent_it = $uuid_hash->{$parent_it->{parent_uuid}};
|
$uuid = $node->{parent_uuid};
|
||||||
$distance++;
|
if($uuid eq "-") {
|
||||||
TRACE "related_nodes: found parent uuid=$parent_it->{uuid} (distance=$distance)" if($parent_it);
|
TRACE "related_nodes: d=$distance uuid=$node->{uuid} : no parent_uuid";
|
||||||
|
last;
|
||||||
}
|
}
|
||||||
|
$last_node = $node;
|
||||||
|
$node = $uuid_hash->{$uuid};
|
||||||
|
TRACE "related_nodes: d=$distance uuid=$last_node->{uuid} : processing parent uuid=$uuid";
|
||||||
|
$distance++;
|
||||||
|
}
|
||||||
|
WARN "Maximum distance reached, related subvolume search aborted" if($distance >= 256);
|
||||||
TRACE "related_nodes: found total=" . scalar(@related_nodes) . " related readonly subvolumes";
|
TRACE "related_nodes: found total=" . scalar(@related_nodes) . " related readonly subvolumes";
|
||||||
return \@related_nodes;
|
my @sorted = sort { (abs($cgen_ref - $a->{cgen}) <=> abs($cgen_ref - $b->{cgen})) ||
|
||||||
|
($a->{cgen} <=> $b->{cgen}) } @related_nodes;
|
||||||
|
return \@sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3116,7 +3137,6 @@ sub get_best_parent($$$;@)
|
||||||
# filter candidates
|
# filter candidates
|
||||||
my @candidate; # candidates for parent, ordered by "best suited"
|
my @candidate; # candidates for parent, ordered by "best suited"
|
||||||
foreach (@$all_related_nodes) {
|
foreach (@$all_related_nodes) {
|
||||||
next if($_->{id} == $svol->{node}{id}); # skip self
|
|
||||||
my $vinfo = vinfo_resolved($_, $resolve_sroot);
|
my $vinfo = vinfo_resolved($_, $resolve_sroot);
|
||||||
if((not $vinfo) && $source_fallback_all_mountpoints) { # related node is not under $resolve_sroot
|
if((not $vinfo) && $source_fallback_all_mountpoints) { # related node is not under $resolve_sroot
|
||||||
$vinfo = vinfo_resolved_all_mountpoints($_, $svol);
|
$vinfo = vinfo_resolved_all_mountpoints($_, $svol);
|
||||||
|
|
Loading…
Reference in New Issue