mirror of https://github.com/digint/btrbk
btrbk: replace url_cache by spec_cache
parent
0ea0430c43
commit
e9374b3b1d
130
btrbk
130
btrbk
|
@ -254,9 +254,9 @@ my %raw_info_sort = (
|
||||||
# kdf_* (generated by kdf_backend)
|
# kdf_* (generated by kdf_backend)
|
||||||
);
|
);
|
||||||
|
|
||||||
my %url_cache; # map URL to btr_tree node
|
|
||||||
my %raw_url_cache; # map URL to (fake) btr_tree node
|
my %raw_url_cache; # map URL to (fake) btr_tree node
|
||||||
my %mountpoint_cache;# map HOST to btrfs mount points
|
my %mountpoint_cache;# map HOST to btrfs mount points
|
||||||
|
my %spec_cache; # map HOST:fs_spec (aka device) to btr_tree node
|
||||||
my %uuid_cache; # map UUID to btr_tree node
|
my %uuid_cache; # map UUID to btr_tree node
|
||||||
my %realpath_cache; # map URL to realpath (symlink target)
|
my %realpath_cache; # map URL to realpath (symlink target)
|
||||||
|
|
||||||
|
@ -370,9 +370,6 @@ sub SUBVOL_LIST {
|
||||||
my $vol = shift; my $t = shift // "SUBVOL_LIST"; my $svl = vinfo_subvol_list($vol);
|
my $vol = shift; my $t = shift // "SUBVOL_LIST"; my $svl = vinfo_subvol_list($vol);
|
||||||
print STDERR "$t:\n " . join("\n ", map { "$vol->{PRINT}/./$_->{SUBVOL_PATH}\t$_->{node}{id}" } @$svl) . "\n";
|
print STDERR "$t:\n " . join("\n ", map { "$vol->{PRINT}/./$_->{SUBVOL_PATH}\t$_->{node}{id}" } @$svl) . "\n";
|
||||||
}
|
}
|
||||||
sub URL_CACHE {
|
|
||||||
print STDERR "URL_CACHE:\n" . join("\n", (sort keys %url_cache)) . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub ABORTED($;$)
|
sub ABORTED($;$)
|
||||||
|
@ -2061,17 +2058,22 @@ sub btr_tree($$$$)
|
||||||
my $spec = shift || die; # aka device
|
my $spec = shift || die; # aka device
|
||||||
my $mountpoints = shift || die; # all known mountpoints for this filesystem: arrayref of { file, subvolid }
|
my $mountpoints = shift || die; # all known mountpoints for this filesystem: arrayref of { file, subvolid }
|
||||||
die unless($vol_root_id >= 5);
|
die unless($vol_root_id >= 5);
|
||||||
# NOTE: we need an ID (provided by btrfs_subvolume_show()) in order
|
|
||||||
# to determine the anchor to our root path (since the subvolume path
|
|
||||||
# output of "btrfs subvolume list" is ambigous, and the uuid of the
|
|
||||||
# btrfs root node cannot be resolved).
|
|
||||||
|
|
||||||
# man btrfs-subvolume:
|
# return parsed tree from %spec_cache if present
|
||||||
# Also every btrfs filesystem has a default subvolume as its initially
|
my $vol_host_spec = ($vol->{HOST} // "localhost") . ':' . $spec;
|
||||||
# top-level subvolume, whose subvolume id is 5(FS_TREE).
|
my $cached_tree = $spec_cache{$vol_host_spec};
|
||||||
my %tree = ( id => 5,
|
TRACE "spec_cache " . ($cached_tree ? "HIT" : "MISS") . ": $vol_host_spec";
|
||||||
|
if($cached_tree) {
|
||||||
|
TRACE "btr_tree: returning cached tree at id=$vol_root_id";
|
||||||
|
my $node = $cached_tree->{ID_HASH}{$vol_root_id};
|
||||||
|
ERROR "Unknown subvolid=$vol_root_id in btrfs tree of $vol_host_spec" unless($node);
|
||||||
|
return $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
# assemble subvolume tree
|
||||||
|
my %tree = ( id => 5, # top-level subvolume id is always 5 (by btrfs spec)
|
||||||
is_root => 1,
|
is_root => 1,
|
||||||
spec => $spec,
|
host_spec => $vol_host_spec, # unique identifier, e.g. "localhost:/dev/sda1"
|
||||||
MOUNTPOINTS => $mountpoints, # { file, spec, node }
|
MOUNTPOINTS => $mountpoints, # { file, spec, node }
|
||||||
SUBTREE => []
|
SUBTREE => []
|
||||||
);
|
);
|
||||||
|
@ -2156,6 +2158,7 @@ sub btr_tree($$$$)
|
||||||
TRACE "btr_tree: returning tree at id=$vol_root->{id}";
|
TRACE "btr_tree: returning tree at id=$vol_root->{id}";
|
||||||
VINFO($vol_root, "node") if($loglevel >=4);
|
VINFO($vol_root, "node") if($loglevel >=4);
|
||||||
|
|
||||||
|
$spec_cache{$vol_host_spec} = \%tree;
|
||||||
return $vol_root;
|
return $vol_root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2227,26 +2230,6 @@ sub _is_child_of
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub _fill_url_cache
|
|
||||||
{
|
|
||||||
my $node = shift;
|
|
||||||
my $abs_path = shift;
|
|
||||||
my $node_subdir = shift;
|
|
||||||
TRACE "_fill_url_cache: $abs_path" . ($node_subdir ? " (subdir=$node_subdir)" : "");
|
|
||||||
|
|
||||||
# traverse tree from given node and update tree cache
|
|
||||||
$url_cache{$abs_path} = $node unless(defined($node_subdir));
|
|
||||||
foreach(@{$node->{SUBTREE}}) {
|
|
||||||
my $rel_path = $_->{REL_PATH};
|
|
||||||
if(defined($node_subdir)) {
|
|
||||||
next unless($rel_path =~ s/^\Q$node_subdir\E\///);
|
|
||||||
}
|
|
||||||
_fill_url_cache($_, $abs_path . '/' . $rel_path, undef);
|
|
||||||
}
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub _get_longest_match
|
sub _get_longest_match
|
||||||
{
|
{
|
||||||
my $node = shift;
|
my $node = shift;
|
||||||
|
@ -2264,20 +2247,6 @@ sub _get_longest_match
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# reverse path lookup
|
|
||||||
sub get_cached_url_by_uuid($)
|
|
||||||
{
|
|
||||||
my $uuid = shift;
|
|
||||||
my @result;
|
|
||||||
while(my ($url, $node) = each(%url_cache)) {
|
|
||||||
next if($node->{is_root});
|
|
||||||
next unless($node->{uuid} eq $uuid);
|
|
||||||
push @result, $url;
|
|
||||||
}
|
|
||||||
return @result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub vinfo($;$)
|
sub vinfo($;$)
|
||||||
{
|
{
|
||||||
my $url = shift // die;
|
my $url = shift // die;
|
||||||
|
@ -2455,51 +2424,32 @@ sub vinfo_init_root($;@)
|
||||||
{
|
{
|
||||||
my $vol = shift || die;
|
my $vol = shift || die;
|
||||||
my %opts = @_;
|
my %opts = @_;
|
||||||
my $tree_root;
|
|
||||||
|
|
||||||
# use cached info if present
|
# resolve btrfs tree from mount point
|
||||||
$tree_root = $url_cache{$vol->{URL}};
|
my ($mnt_path, $real_path, $subvolid, $spec, $spec_mounts) = btrfs_mountpoint($vol);
|
||||||
TRACE "url_cache " . ($tree_root ? "HIT" : "MISS") . ": URL=$vol->{URL}";
|
return undef unless($mnt_path && $real_path && $subvolid);
|
||||||
unless($tree_root) {
|
|
||||||
if(my $real_path = $realpath_cache{$vol->{URL}}) {
|
|
||||||
my $real_url = $vol->{URL_PREFIX} . $real_path;
|
|
||||||
$tree_root = $url_cache{$real_url};
|
|
||||||
TRACE "url_cache " . ($tree_root ? "HIT" : "MISS") . ": REAL_URL=$real_url";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unless($tree_root) {
|
# read btrfs tree for the mount point
|
||||||
# btrfs tree is not yet cached, read it from mount point
|
my $mnt_vol = vinfo($vol->{URL_PREFIX} . $mnt_path, $vol->{CONFIG});
|
||||||
my ($mnt_path, $real_path, $subvolid, $spec, $spec_mounts) = btrfs_mountpoint($vol);
|
my $mnt_tree_root = btr_tree($mnt_vol, $subvolid, $spec, $spec_mounts);
|
||||||
return undef unless($mnt_path && $real_path && $subvolid);
|
return undef unless($mnt_tree_root);
|
||||||
my $mnt_tree_root = $url_cache{$vol->{URL_PREFIX} . $mnt_path};
|
|
||||||
unless($mnt_tree_root) {
|
|
||||||
# read btrfs tree for the mount point
|
|
||||||
my $mnt_vol = vinfo($vol->{URL_PREFIX} . $mnt_path, $vol->{CONFIG});
|
|
||||||
$mnt_tree_root = btr_tree($mnt_vol, $subvolid, $spec, $spec_mounts);
|
|
||||||
_fill_url_cache($mnt_tree_root, $mnt_vol->{URL});
|
|
||||||
}
|
|
||||||
|
|
||||||
# find longest match in tree
|
# find longest match in btrfs tree
|
||||||
my $ret = _get_longest_match($mnt_tree_root, $mnt_path, $real_path) // die;
|
my $ret = _get_longest_match($mnt_tree_root, $mnt_path, $real_path) // die;
|
||||||
$tree_root = $ret->{node};
|
my $tree_root = $ret->{node};
|
||||||
|
|
||||||
# set NODE_SUBDIR if $vol->{PATH} points to a regular (non-subvolume) directory.
|
|
||||||
# in other words, "PATH=<path_to_subvolume>/NODE_SUBDIR"
|
|
||||||
my $node_subdir = $real_path;
|
|
||||||
die unless($node_subdir =~ s/^\Q$ret->{path}\E//); # NOTE: $ret->{path} has trailing slash!
|
|
||||||
$node_subdir =~ s/\/+$//;
|
|
||||||
$vol->{NODE_SUBDIR} = $node_subdir if($node_subdir ne '');
|
|
||||||
|
|
||||||
$vol->{MOUNTPOINT} = $mnt_path;
|
|
||||||
$vol->{MOUNTPOINT_NODE} = $mnt_tree_root;
|
|
||||||
|
|
||||||
_fill_url_cache($tree_root, $vol->{URL}, $vol->{NODE_SUBDIR});
|
|
||||||
}
|
|
||||||
return undef unless($tree_root);
|
return undef unless($tree_root);
|
||||||
|
|
||||||
|
# set NODE_SUBDIR if $vol->{PATH} points to a regular (non-subvolume) directory.
|
||||||
|
# in other words, "PATH=<path_to_subvolume>/NODE_SUBDIR"
|
||||||
|
my $node_subdir = $real_path;
|
||||||
|
die unless($node_subdir =~ s/^\Q$ret->{path}\E//); # NOTE: $ret->{path} has trailing slash!
|
||||||
|
$node_subdir =~ s/\/+$//;
|
||||||
|
$vol->{NODE_SUBDIR} = $node_subdir if($node_subdir ne '');
|
||||||
$vol->{node} = $tree_root;
|
$vol->{node} = $tree_root;
|
||||||
|
|
||||||
|
$vol->{MOUNTPOINT} = $mnt_path;
|
||||||
|
$vol->{MOUNTPOINT_NODE} = $mnt_tree_root;
|
||||||
|
|
||||||
return $tree_root;
|
return $tree_root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2523,6 +2473,7 @@ sub vinfo_init_raw_root($;@)
|
||||||
# create fake btr_tree
|
# create fake btr_tree
|
||||||
$tree_root = { id => 5,
|
$tree_root = { id => 5,
|
||||||
is_root => 1,
|
is_root => 1,
|
||||||
|
host_spec => 'raw_tree@' . $droot->{URL}, # for completeness (this is never used)
|
||||||
GEN_MAX => 1,
|
GEN_MAX => 1,
|
||||||
SUBTREE => [],
|
SUBTREE => [],
|
||||||
UUID_HASH => {},
|
UUID_HASH => {},
|
||||||
|
@ -2749,7 +2700,6 @@ sub vinfo_inject_child($$$;$)
|
||||||
return undef unless(add_btrbk_filename_info($node, $raw_info));
|
return undef unless(add_btrbk_filename_info($node, $raw_info));
|
||||||
|
|
||||||
$vinfo_child->{node} = $node;
|
$vinfo_child->{node} = $node;
|
||||||
$url_cache{$vinfo_child->{URL}} = $node;
|
|
||||||
TRACE "vinfo_inject_child: injected child id=$node->{id} to $vinfo->{PRINT}";
|
TRACE "vinfo_inject_child: injected child id=$node->{id} to $vinfo->{PRINT}";
|
||||||
return $vinfo_child;
|
return $vinfo_child;
|
||||||
}
|
}
|
||||||
|
@ -4280,13 +4230,9 @@ sub _origin_tree
|
||||||
# cache a bit, this might be large
|
# cache a bit, this might be large
|
||||||
$nodelist //= [ (sort { $a->{REL_PATH} cmp $b->{REL_PATH} } values %uuid_cache) ];
|
$nodelist //= [ (sort { $a->{REL_PATH} cmp $b->{REL_PATH} } values %uuid_cache) ];
|
||||||
|
|
||||||
my @url = get_cached_url_by_uuid($uuid);
|
|
||||||
my $out_path;
|
my $out_path;
|
||||||
if(scalar @url) {
|
$out_path = _fs_path($node);
|
||||||
$out_path = join(" === ", sort map { vinfo($_)->{PRINT} } @url);
|
|
||||||
} else {
|
|
||||||
$out_path = _fs_path($node);
|
|
||||||
}
|
|
||||||
my $prefix_spaces = ' ' x (($depth * 4) - ($prefix ? 4 : 0));
|
my $prefix_spaces = ' ' x (($depth * 4) - ($prefix ? 4 : 0));
|
||||||
push(@$lines, { tree => "${prefix_spaces}${prefix}$out_path",
|
push(@$lines, { tree => "${prefix_spaces}${prefix}$out_path",
|
||||||
uuid => $node->{uuid},
|
uuid => $node->{uuid},
|
||||||
|
|
Loading…
Reference in New Issue