mirror of https://github.com/digint/btrbk
btrbk: simplify btr_tree: SUBTREE is now list instead of hash; add TREE_ROOT pointer to every node; cleanup
parent
97caced09d
commit
1b45db3c59
116
btrbk
116
btrbk
|
@ -542,7 +542,6 @@ sub vinfo_init_root($)
|
||||||
my $subvol_list = vinfo_subvol_list($vol, fill_cache => 1);
|
my $subvol_list = vinfo_subvol_list($vol, fill_cache => 1);
|
||||||
|
|
||||||
TRACE "vinfo_init_root: created vinfo root: $vol->{PRINT}";
|
TRACE "vinfo_init_root: created vinfo root: $vol->{PRINT}";
|
||||||
# VINFO($vol);
|
|
||||||
return $subvol_list;
|
return $subvol_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1620,22 +1619,6 @@ sub btrfs_send_to_file($$$$;@)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub _btr_tree_fill_cache
|
|
||||||
{
|
|
||||||
my $node = shift;
|
|
||||||
my $abs_path = shift;
|
|
||||||
|
|
||||||
# traverse tree and update tree cache
|
|
||||||
#TRACE "_btr_tree_fill_cache: $abs_path";
|
|
||||||
|
|
||||||
$url_cache{$abs_path} = $node;
|
|
||||||
foreach(values %{$node->{SUBTREE}}) {
|
|
||||||
_btr_tree_fill_cache($_, $abs_path . '/' . $_->{REL_PATH});
|
|
||||||
}
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub btr_tree($)
|
sub btr_tree($)
|
||||||
{
|
{
|
||||||
my $vol = shift;
|
my $vol = shift;
|
||||||
|
@ -1665,34 +1648,36 @@ sub btr_tree($)
|
||||||
# top-level subvolume, whose subvolume id is 5(FS_TREE).
|
# top-level subvolume, whose subvolume id is 5(FS_TREE).
|
||||||
my %tree = ( id => 5,
|
my %tree = ( id => 5,
|
||||||
is_root => 1,
|
is_root => 1,
|
||||||
SUBTREE => {}
|
SUBTREE => []
|
||||||
);
|
);
|
||||||
my %id = ( 5 => \%tree );
|
my %id = ( 5 => \%tree );
|
||||||
|
|
||||||
my $subvol_list = btrfs_subvolume_list($vol);
|
$tree{TREE_ROOT} = \%tree;
|
||||||
return undef unless(ref($subvol_list) eq "ARRAY");
|
|
||||||
|
my $node_list = btrfs_subvolume_list($vol);
|
||||||
|
return undef unless(ref($node_list) eq "ARRAY");
|
||||||
|
|
||||||
TRACE "btr_tree: processing subvolume list of: $vol->{PRINT}";
|
TRACE "btr_tree: processing subvolume list of: $vol->{PRINT}";
|
||||||
|
|
||||||
foreach my $node (@$subvol_list)
|
foreach my $node (@$node_list)
|
||||||
{
|
{
|
||||||
$node->{SUBTREE} //= {};
|
die if exists($id{$node->{id}});
|
||||||
|
$node->{SUBTREE} //= [];
|
||||||
$id{$node->{id}} = $node;
|
$id{$node->{id}} = $node;
|
||||||
$uuid_cache{$node->{uuid}} = $node;
|
$uuid_cache{$node->{uuid}} = $node;
|
||||||
}
|
}
|
||||||
|
|
||||||
# note: it is possible that id < top_level, e.g. after restoring
|
# note: it is possible that id < top_level, e.g. after restoring
|
||||||
my $vol_root;
|
my $vol_root;
|
||||||
foreach my $node (@$subvol_list)
|
foreach my $node (@$node_list)
|
||||||
{
|
{
|
||||||
# set SUBTREE / TOP_LEVEL node
|
# set SUBTREE / TOP_LEVEL node
|
||||||
die unless exists($id{$node->{top_level}});
|
die unless exists($id{$node->{top_level}});
|
||||||
my $top_level = $id{$node->{top_level}};
|
my $top_level = $id{$node->{top_level}};
|
||||||
|
|
||||||
die if exists($top_level->{SUBTREE}->{$node->{id}});
|
push(@{$top_level->{SUBTREE}}, $node);
|
||||||
$top_level->{SUBTREE}->{$node->{id}} = $node;
|
|
||||||
$node->{TOP_LEVEL} = $top_level;
|
$node->{TOP_LEVEL} = $top_level;
|
||||||
|
$node->{TREE_ROOT} = \%tree;
|
||||||
|
|
||||||
# "path" always starts with set REL_PATH
|
# "path" always starts with set REL_PATH
|
||||||
my $rel_path = $node->{path};
|
my $rel_path = $node->{path};
|
||||||
|
@ -1721,6 +1706,21 @@ sub btr_tree($)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub _btr_tree_fill_url_cache
|
||||||
|
{
|
||||||
|
my $node = shift;
|
||||||
|
my $abs_path = shift;
|
||||||
|
# TRACE "_btr_tree_fill_url_cache: $abs_path";
|
||||||
|
|
||||||
|
# traverse tree from given node and update tree cache
|
||||||
|
$url_cache{$abs_path} = $node;
|
||||||
|
foreach(@{$node->{SUBTREE}}) {
|
||||||
|
_btr_tree_fill_url_cache($_, $abs_path . '/' . $_->{REL_PATH});
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sub _vinfo_subtree_list
|
sub _vinfo_subtree_list
|
||||||
{
|
{
|
||||||
my $tree = shift;
|
my $tree = shift;
|
||||||
|
@ -1728,7 +1728,7 @@ sub _vinfo_subtree_list
|
||||||
my $list = shift // [];
|
my $list = shift // [];
|
||||||
my $path_prefix = shift // "";
|
my $path_prefix = shift // "";
|
||||||
|
|
||||||
foreach(values %{$tree->{SUBTREE}}) {
|
foreach(@{$tree->{SUBTREE}}) {
|
||||||
my $path = $path_prefix . $_->{REL_PATH};
|
my $path = $path_prefix . $_->{REL_PATH};
|
||||||
my $vinfo = vinfo_child($vinfo_parent, $path);
|
my $vinfo = vinfo_child($vinfo_parent, $path);
|
||||||
vinfo_set_detail($vinfo, $_);
|
vinfo_set_detail($vinfo, $_);
|
||||||
|
@ -1757,7 +1757,7 @@ sub vinfo_subvol_list($;@)
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
TRACE "vinfo_subvol_list: fill_cache: btrfs_tree: cache MISS: $_";
|
TRACE "vinfo_subvol_list: fill_cache: btrfs_tree: cache MISS: $_";
|
||||||
_btr_tree_fill_cache($tree_root, $_);
|
_btr_tree_fill_url_cache($tree_root, $_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1780,22 +1780,13 @@ sub get_cached_url_by_uuid($)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub __get_by_id($$)
|
sub vinfo_subvol($$;$)
|
||||||
{
|
{
|
||||||
my $subvol_list = shift;
|
my $vol = shift || die;
|
||||||
my $id = shift;
|
my $filter_value = shift // die;
|
||||||
my @ret = grep { $_->{id} == $id } @$subvol_list;
|
my $filter_key = shift || 'SUBVOL_PATH';
|
||||||
return undef unless(scalar @ret);
|
my $subvol_list = vinfo_subvol_list($vol);
|
||||||
die unless(scalar(@ret) == 1);
|
|
||||||
return $ret[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub __get_by_key_eq($$$)
|
|
||||||
{
|
|
||||||
my $subvol_list = shift;
|
|
||||||
my $filter_key = shift;
|
|
||||||
my $filter_value = shift;
|
|
||||||
my @ret = grep { $_->{$filter_key} eq $filter_value } @$subvol_list;
|
my @ret = grep { $_->{$filter_key} eq $filter_value } @$subvol_list;
|
||||||
return undef unless(scalar @ret);
|
return undef unless(scalar @ret);
|
||||||
die unless(scalar(@ret) == 1);
|
die unless(scalar(@ret) == 1);
|
||||||
|
@ -1803,29 +1794,15 @@ sub __get_by_key_eq($$$)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# returns list of uuids for ALL subvolumes in the btrfs filesystem of $vol
|
sub vinfo_subvol_by_id($$)
|
||||||
sub vinfo_fs_list($)
|
|
||||||
{
|
{
|
||||||
my $vol = shift || die;
|
my $vol = shift;
|
||||||
my $tree_root = btr_tree($vol);
|
my $id = shift;
|
||||||
return undef unless($tree_root);
|
|
||||||
|
|
||||||
$tree_root = $tree_root->{TOP_LEVEL} while($tree_root->{TOP_LEVEL});
|
|
||||||
my $list = _subtree_list($tree_root);
|
|
||||||
my %ret = map { $_->{node}->{uuid} => $_->{node} } @$list;
|
|
||||||
return \%ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub vinfo_subvol($$)
|
|
||||||
{
|
|
||||||
my $vol = shift || die;
|
|
||||||
my $rel_path = shift // die;
|
|
||||||
my %opts = @_;
|
|
||||||
|
|
||||||
my $subvol_list = vinfo_subvol_list($vol);
|
my $subvol_list = vinfo_subvol_list($vol);
|
||||||
my $vinfo = __get_by_key_eq($subvol_list, 'SUBVOL_PATH', $rel_path);
|
my @ret = grep { $_->{id} == $id } @$subvol_list;
|
||||||
return $vinfo;
|
return undef unless(scalar @ret);
|
||||||
|
die unless(scalar(@ret) == 1);
|
||||||
|
return $ret[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2700,9 +2677,9 @@ MAIN:
|
||||||
unless(vinfo_init_root($target_vol)) { ERROR "Failed to fetch subvolume detail for '$target_vol->{PRINT}'" . ($err ? ": $err" : ""); exit 1; }
|
unless(vinfo_init_root($target_vol)) { ERROR "Failed to fetch subvolume detail for '$target_vol->{PRINT}'" . ($err ? ": $err" : ""); exit 1; }
|
||||||
unless($target_vol->{cgen}) { ERROR "Subvolume at \"$target_url\" does not provide cgen"; exit 1; }
|
unless($target_vol->{cgen}) { ERROR "Subvolume at \"$target_url\" does not provide cgen"; exit 1; }
|
||||||
|
|
||||||
my $uuid_list = vinfo_fs_list($src_vol);
|
unless($uuid_cache{$src_vol->{uuid}} && $uuid_cache{$target_vol->{uuid}} &&
|
||||||
unless($uuid_list->{$target_vol->{uuid}}) {
|
$uuid_cache{$src_vol->{uuid}}->{TREE_ROOT} eq $uuid_cache{$target_vol->{uuid}}->{TREE_ROOT}) {
|
||||||
ERROR "Target subvolume is not on the same btrfs filesystem!";
|
ERROR "Subvolumes are is not on the same btrfs filesystem!";
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3055,15 +3032,12 @@ MAIN:
|
||||||
DEBUG "Missing \"$rel_path\" in btrfs subtree of \"$sroot->{PRINT}\", resolving details";
|
DEBUG "Missing \"$rel_path\" in btrfs subtree of \"$sroot->{PRINT}\", resolving details";
|
||||||
# configured subvolume is not present in btrfs subvolume list.
|
# configured subvolume is not present in btrfs subvolume list.
|
||||||
# try to read subvolume detail, as configured subvolume could be a symlink.
|
# try to read subvolume detail, as configured subvolume could be a symlink.
|
||||||
my $subvol_list = vinfo_init_root($svol);
|
unless(vinfo_init_root($svol)) {
|
||||||
unless($subvol_list) {
|
|
||||||
ABORTED($sroot, "Failed to fetch subvolume detail" . ($err ? ": $err" : ""));
|
ABORTED($sroot, "Failed to fetch subvolume detail" . ($err ? ": $err" : ""));
|
||||||
WARN "Skipping volume \"$sroot->{PRINT}\": $abrt";
|
WARN "Skipping volume \"$sroot->{PRINT}\": $abrt";
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
$subvol_list = vinfo_subvol_list($sroot);
|
if(vinfo_subvol_by_id($sroot, $svol->{id})) {
|
||||||
my $vinfo = __get_by_id($subvol_list, $svol->{id});
|
|
||||||
if($vinfo) {
|
|
||||||
DEBUG "Found id=$svol->{id} in btrfs subtree of: $sroot->{PRINT}";
|
DEBUG "Found id=$svol->{id} in btrfs subtree of: $sroot->{PRINT}";
|
||||||
# NOTE: detail is already set by vinfo_init_root()
|
# NOTE: detail is already set by vinfo_init_root()
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue