btrbk: use symlink hash instead of REAL_URL

pull/73/head
Axel Burri 2016-03-14 15:55:57 +01:00
parent cab2a88843
commit 9a68ab6519
1 changed files with 56 additions and 65 deletions

121
btrbk
View File

@ -169,6 +169,7 @@ my %table_formats = (
my %url_cache; # map URL to btr_tree node
my %uuid_cache; # map UUID to btr_tree node
my %symlink; # map URL to REAL_URL (symlink target)
my $dryrun;
my $loglevel = 1;
@ -433,15 +434,17 @@ sub vinfo($;$)
NAME => $name,
PATH => $url,
PRINT => $url,
URL_PREFIX => "",
);
if($url =~ /^ssh:\/\/(\S+?)(\/\S+)$/) {
my ($host, $path) = ($1, $2);
%info = (
%info,
HOST => $host,
PATH => $path,
PRINT => "$host:$path",
HOST => $host,
PATH => $path,
PRINT => "$host:$path",
URL_PREFIX => "ssh://$host",
);
if($config) {
my $ssh_port = config_key($config, "ssh_port");
@ -506,6 +509,7 @@ sub vinfo_child($$;$)
SUBVOL_PATH => $rel_path,
);
foreach (qw( HOST
URL_PREFIX
RSH_TYPE
SSH_USER
SSH_IDENTITY
@ -525,19 +529,6 @@ sub vinfo_init_root($)
{
my $vol = shift;
my $detail = $url_cache{$vol->{URL}};
my $path_verified;
if($detail) {
TRACE "vinfo_init_root: cache HIT: $vol->{URL}";
$path_verified = 1; # all keys from url_cache are real_paths
}
else {
TRACE "vinfo_init_root: cache MISS: $vol->{URL}";
$detail = btrfs_subvolume_detail($vol);
}
return undef unless $detail;
vinfo_set_detail($vol, $detail, $path_verified);
# read the subvolume list, and update %url_cache
my $subvol_list = vinfo_subvol_list($vol, fill_cache => 1);
@ -546,11 +537,10 @@ sub vinfo_init_root($)
}
sub vinfo_set_detail($$;$)
sub vinfo_set_detail($$)
{
my $vol = shift || die;
my $detail = shift || die;
my $path_verified = shift;
my @vinfo_detail_keys = qw(id is_root gen cgen uuid parent_uuid received_uuid readonly node);
# TRACE "updating vinfo detail for: $vol->{PRINT}";
@ -569,21 +559,6 @@ sub vinfo_set_detail($$;$)
die if(defined($detail->{NAME}) && ($detail->{NAME} ne $vol->{NAME}));
die if(defined($detail->{SUBVOL_PATH}) && defined($vol->{SUBVOL_PATH}) && ($detail->{SUBVOL_PATH} ne $vol->{SUBVOL_PATH}));
# honor REAL_PATH from btrfs_subvolume_detail
if($detail->{REAL_PATH}) {
$vol->{REAL_PATH} = $detail->{REAL_PATH};
}
elsif($path_verified) {
$vol->{REAL_PATH} = $vol->{PATH};
}
if($vol->{REAL_PATH}) {
if($vol->{RSH_TYPE} && ($vol->{RSH_TYPE} eq "ssh")) {
$vol->{REAL_URL} = "ssh://$vol->{HOST}$vol->{REAL_PATH}";
} else {
$vol->{REAL_URL} = $vol->{REAL_PATH};
}
}
return $vol;
}
@ -1077,7 +1052,7 @@ sub btrfs_filesystem_usage($)
# returns hashref with keys: (name uuid parent_uuid id gen cgen top_level)
# for btrfs-progs >= 4.1, also returns key: "received_uuid"
sub btrfs_subvolume_detail($)
sub btrfs_subvolume_show($)
{
my $vol = shift || die;
my $path = $vol->{PATH} // die;
@ -1116,6 +1091,7 @@ sub btrfs_subvolume_detail($)
$real_path = $1;
DEBUG "Real path for subvolume \"$vol->{PRINT}\" is: $real_path" if($real_path ne $path);
return undef unless(check_file($real_path, { absolute => 1 }));
$symlink{$vol->{URL}} = $vol->{URL_PREFIX} . $real_path if($real_path ne $path);
}
else {
$real_path = $path;
@ -1619,17 +1595,14 @@ sub btrfs_send_to_file($$$$;@)
}
sub btr_tree($)
sub btr_tree($$)
{
my $vol = shift;
# NOTE: make sure to to have either $vol->{uuid} or $vol->{is_root}
# (provided by btrfs_subvolume_show()), or we cannot 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).
die unless($vol->{uuid} || $vol->{is_root});
return $uuid_cache{$vol->{uuid}} if($vol->{uuid} && $uuid_cache{$vol->{uuid}});
my $vol_root_id = shift || die;
# 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:
# Also every btrfs filesystem has a default subvolume as its initially
@ -1675,10 +1648,10 @@ sub btr_tree($)
$node->{REL_PATH} = $rel_path; # relative to {TOP_LEVEL}->{path}
$vol_root = $node if($vol->{id} == $node->{id});
$vol_root = $node if($vol_root_id == $node->{id});
}
unless($vol_root) {
if($vol->{is_root}) {
if($vol_root_id == 5) {
$vol_root = \%tree;
}
else {
@ -1734,37 +1707,55 @@ sub vinfo_subvol_list($;@)
my $vol = shift || die;
my %opts = @_;
my $tree_root;
my @fill_cache;
# return cached info if present
# use cached info if present
$tree_root = $url_cache{$vol->{URL}};
TRACE "vinfo_subvol_list: cache " . ($tree_root ? "HIT" : "MISS") . ": URL=$vol->{URL}";
unless($tree_root) {
if($vol->{REAL_URL}) {
$tree_root = $url_cache{$vol->{REAL_URL}};
TRACE "vinfo_subvol_list: cache " . ($tree_root ? "HIT" : "MISS") . ": REAL_URL=$vol->{REAL_URL}";
if(my $real_url = $symlink{$vol->{URL}}) {
$tree_root = $url_cache{$real_url};
TRACE "vinfo_subvol_list: cache " . ($tree_root ? "HIT" : "MISS") . ": REAL_URL=$real_url";
}
}
unless($tree_root) {
$tree_root = btr_tree($vol);
# url_cache miss, read the subvolume detail
my $detail = btrfs_subvolume_show($vol);
return undef unless $detail;
vinfo_set_detail($vol, $detail);
push @fill_cache, $symlink{$vol->{URL}} if($symlink{$vol->{URL}});
# check uuid_cache
if($detail->{uuid}) {
$tree_root = $uuid_cache{$detail->{uuid}};
TRACE "vinfo_subvol_list: cache " . ($tree_root ? "HIT" : "MISS") . ": UUID=$detail->{uuid}";
}
unless($tree_root) {
# cache miss, read the fresh tree
my $root_id = $detail->{is_root} ? 5 : $detail->{id};
$tree_root = btr_tree($vol, $root_id);
push @fill_cache, $vol->{URL};
}
}
return undef unless($tree_root);
$vol->{node} = $tree_root;
if($opts{fill_cache}) {
# force fill cache
die unless($vol->{REAL_URL});
foreach ($vol->{URL}, $vol->{REAL_URL}) {
if($url_cache{$_}) {
TRACE "vinfo_subvol_list: fill_cache: btrfs_tree: cache HIT: $_";
next;
}
TRACE "vinfo_subvol_list: fill_cache: btrfs_tree: cache MISS: $_";
_btr_tree_fill_url_cache($tree_root, $_);
# fill cache
foreach (@fill_cache) {
if($url_cache{$_}) {
TRACE "vinfo_subvol_list: fill_cache: btrfs_tree: cache HIT: $_";
next;
}
TRACE "vinfo_subvol_list: fill_cache: btrfs_tree: cache MISS: $_";
_btr_tree_fill_url_cache($tree_root, $_);
}
$vol->{node} = $tree_root;
# recurse into $tree_root, returns array of vinfo
return _vinfo_subtree_list($tree_root, $vol);
}
@ -1870,7 +1861,7 @@ sub macro_send_receive(@)
# make sure we know the source uuid
unless($source->{uuid}) {
DEBUG "Fetching uuid of new subvolume: $source->{PRINT}";
my $detail = btrfs_subvolume_detail($source);
my $detail = btrfs_subvolume_show($source);
die unless($detail->{uuid});
vinfo_set_detail($source, { uuid => $detail->{uuid} });
}
@ -3170,7 +3161,7 @@ MAIN:
# check for duplicate snapshot locations
my $snapdir = config_key($svol, "snapshot_dir", postfix => '/') // "";
my $snapshot_basename = config_key($svol, "snapshot_name") // die;
my $snapshot_target = "$sroot->{REAL_URL}/$snapdir$snapshot_basename";
my $snapshot_target = ($symlink{$sroot->{URL}} // $sroot->{URL}) . '/' . $snapdir . $snapshot_basename;
if(my $prev = $snapshot_check{$snapshot_target}) {
ERROR "Subvolume \"$prev\" and \"$svol->{PRINT}\" will create same snapshot: $snapshot_target";
ERROR "Please fix \"snapshot_name\" configuration options!";
@ -3180,7 +3171,7 @@ MAIN:
foreach my $droot (vinfo_subsection($svol, 'target')) {
# check for duplicate snapshot locations
my $snapshot_backup_target = "$droot->{REAL_URL}/$snapshot_basename";
my $snapshot_backup_target = ($symlink{$droot->{URL}} // $droot->{URL}) . '/' . $snapshot_basename;
if(my $prev = $backup_check{$snapshot_backup_target}) {
ERROR "Subvolume \"$prev\" and \"$svol->{PRINT}\" will create same backup target: $snapshot_target";
ERROR "Please fix \"snapshot_name\" or \"target\" configuration options!";