btrbk: replace url_cache by spec_cache

pull/235/head
Axel Burri 2018-02-14 22:09:45 +01:00
parent 0ea0430c43
commit e9374b3b1d
1 changed files with 38 additions and 92 deletions

130
btrbk
View File

@ -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},