btrbk: extents-diff: calculate exclusive size; add "exclusive" option

pull/358/head
Axel Burri 2019-08-07 14:43:08 +02:00
parent ea2ec1ceaa
commit afd6f80739
1 changed files with 82 additions and 36 deletions

110
btrbk
View File

@ -242,10 +242,10 @@ my %table_formats = (
raw => [ qw( host mount_source mount_subvol mount_point mount_subvolid id top_level cgen gen uuid parent_uuid received_uuid readonly path subvolume_path subvolume_rel_path ) ], raw => [ qw( host mount_source mount_subvol mount_point mount_subvolid id top_level cgen gen uuid parent_uuid received_uuid readonly path subvolume_path subvolume_rel_path ) ],
}, },
extent_diff => { table => [ qw( total diff subvol ) ], extent_diff => { table => [ qw( total diff -set subvol ) ],
long => [ qw( total diff subvol cgen gen ) ], long => [ qw( total diff exclusive -set subvol cgen gen ) ],
raw => [ qw( total diff subvol cgen gen ) ], raw => [ qw( total diff subvol cgen gen ) ],
RALIGN => { total=>1, diff=>1, cgen=>1, gen=>1 }, RALIGN => { total=>1, diff=>1, exclusive=>1, set=>1, cgen=>1, gen=>1 },
}, },
); );
@ -5397,8 +5397,17 @@ MAIN:
$action_extents_diff = 1; $action_extents_diff = 1;
$fallback_default_config = 1; $fallback_default_config = 1;
$args_expected_min = 1; $args_expected_min = 1;
$subvol_args_init = "restrict_same_fs deny_root_subvol"; $subvol_args_init = "restrict_same_fs";
@subvol_args = @ARGV; my $excl;
foreach(@ARGV) {
# subvol_arg... "exclusive" filter_arg...
if($_ eq "exclusive") {
$excl = 1;
} else {
push @subvol_args, $_;
push @filter_args, $_ if($excl);
}
}
} }
elsif ($command eq "origin") { elsif ($command eq "origin") {
$action_origin = 1; $action_origin = 1;
@ -5650,7 +5659,6 @@ MAIN:
# resolve related subvolumes # resolve related subvolumes
my @resolved_vol; my @resolved_vol;
$extents_diff_related = 1 if(scalar(@subvol_args) == 1); # single argument: implicit --related
if($extents_diff_related) { if($extents_diff_related) {
# add all related subvolumes # add all related subvolumes
foreach my $svol (@subvol_args) { foreach my $svol (@subvol_args) {
@ -5678,46 +5686,84 @@ MAIN:
exit 1; exit 1;
}; };
my $prev_vol; my $prev_data;
# sort descending by gen: crawl descending, but display ascending (unshift) # sort descending by gen: crawl descending, but display ascending (unshift)
foreach (sort { ($b->{node}{readonly} ? $b->{node}{cgen} : $b->{node}{gen}) <=> foreach my $vol (sort { ($b->{node}{readonly} ? $b->{node}{cgen} : $b->{node}{gen}) <=>
($a->{node}{readonly} ? $a->{node}{cgen} : $a->{node}{gen}) } ($a->{node}{readonly} ? $a->{node}{cgen} : $a->{node}{gen}) }
@resolved_vol) { @resolved_vol) {
next if($prev_vol && ($prev_vol->{node}{id} == $_->{node}{id})); # skip duplicates next if($prev_data && ($prev_data->{_vinfo}{node}{id} == $vol->{node}{id})); # skip duplicates
# read extents map # read extents map
if($_->{EXTENTMAP} = read_extentmap_cache($_)) { if($vol->{EXTENTMAP} = read_extentmap_cache($vol)) {
INFO "Using cached extents map for: $_->{PRINT}"; INFO "Using cached extents map for: $vol->{PRINT}";
} else { } else {
$_->{EXTENTMAP} = filefrag_extentmap($_); $vol->{EXTENTMAP} = filefrag_extentmap($vol);
write_extentmap_cache($_); write_extentmap_cache($vol);
} }
next unless($_->{EXTENTMAP}); next unless($vol->{EXTENTMAP});
if($prev_vol) { if($prev_data) {
my $diff_map = extentmap_diff($prev_vol->{EXTENTMAP}, $_->{EXTENTMAP}); my $diff_map = extentmap_diff($prev_data->{_vinfo}{EXTENTMAP}, $vol->{EXTENTMAP});
$prev_data->{diff} = print_size(extentmap_size($diff_map));
}
$prev_data = {
total => print_size(extentmap_size($vol->{EXTENTMAP})),
cgen => $vol->{node}{cgen},
gen => $vol->{node}{gen},
subvol => $vol->{PRINT},
_vinfo => $vol,
};
unshift @data, $prev_data;
}
unshift @data, { my @universe_set = map $_->{_vinfo}{EXTENTMAP}, @data;
total => print_size(extentmap_size($prev_vol->{EXTENTMAP})), unless(scalar(@universe_set)) {
diff => print_size(extentmap_size($diff_map)), ERROR "No extent map data, exiting";
cgen => $prev_vol->{node}{cgen}, exit -1;
gen => $prev_vol->{node}{gen}, }
subvol => $prev_vol->{PRINT},
my @summary;
INFO "Calculating union of " . scalar(@data) . " subvolumes";
push @summary, {
a => "Union (" . scalar(@data) . " subvolumes):",
b => print_size(extentmap_size(extentmap_merge(@universe_set)))
}; };
$prev_vol->{EXTENTMAP} = undef; # release memory # calculate "exclusive" column only if needed
if(grep /^exclusive$/, @{$table_formats{extent_diff}{$output_format // "table"}}) {
INFO "Calculating exclusive extents for " . scalar(@data) . " subvolumes";
foreach my $d (@data) {
my $vol = $d->{_vinfo};
DEBUG "Calculating exclusive for: $vol->{PRINT}";
my @others = grep { $_ != $vol->{EXTENTMAP} } @universe_set;
$d->{exclusive} = print_size(extentmap_size(extentmap_diff($vol->{EXTENTMAP}, extentmap_merge(@others)))),
} }
$prev_vol = $_;
} }
unshift @data, {
total => print_size(extentmap_size($prev_vol->{EXTENTMAP})),
cgen => $prev_vol->{node}{cgen},
gen => $prev_vol->{node}{gen},
subvol => $prev_vol->{PRINT},
};
INFO "Printing extents map difference (relative complement): (blocks \ blocks_on_prev_line) * blocksize"; if(scalar(@filter_vf)) {
print_formatted("extent_diff", \@data); my @excl;
my @others;
foreach(@data) {
if(vinfo_match(\@filter_vf, $_->{_vinfo})) {
$_->{set} = "X";
push @excl, $_->{_vinfo}{EXTENTMAP};
} else {
$_->{set} = "A";
push @others, $_->{_vinfo}{EXTENTMAP};
}
}
INFO "Calculating exclusive extents for " . scalar(@excl) . "/" . scalar(@data) . " subvolumes";
push @summary, {
a => "Exclusive data ( X \\ A ):",
b => print_size(extentmap_size(extentmap_diff(extentmap_merge(@excl), extentmap_merge(@others)))),
};
}
INFO "Printing extents map difference (relative complement): (blocks \\ blocks-on-prev-line) * blocksize";
print_formatted("extent_diff", \@data, paragraph => 1);
print_formatted({ table => [ qw( a b ) ], RALIGN => { b=>1 } },
\@summary, output_format => "table", no_header => 1);
exit 0; exit 0;
} }