mirror of https://github.com/schoebel/mars
marsadm: fix transitive closure for log_purge_res()
This commit is contained in:
parent
2ec9800d54
commit
0d5349b2ca
|
@ -550,20 +550,32 @@ sub get_minmax_replays {
|
|||
|
||||
my %visited_pos;
|
||||
|
||||
sub _visit {
|
||||
my ($nr, $peer) = @_;
|
||||
$nr =~ s:^0*::;
|
||||
my $visit = "$nr,$peer";
|
||||
$visited_pos{$visit} = 1;
|
||||
}
|
||||
|
||||
sub _is_visited {
|
||||
my ($nr, $peer) = @_;
|
||||
$nr =~ s:^0*::;
|
||||
my $visit = "$nr,$peer";
|
||||
return $visited_pos{$visit};
|
||||
}
|
||||
|
||||
sub _parse_pos {
|
||||
my ($pos, $do_remember) = @_;
|
||||
$pos =~ m/((?:log|version)-([0-9]+)-([^,]+)(?:,([0-9]+))?)/ or ldie "cannot parse '$pos'\n";
|
||||
if ($do_remember) {
|
||||
my $visit = "$2,$3";
|
||||
$visited_pos{$visit} = 1;
|
||||
}
|
||||
$pos =~ m/((?:log|version)-([0-9]+)-([^,]+)(?:,([0-9]+))?)/ or lwarn "cannot parse position info '$pos'\n";
|
||||
_visit($2, $3) if $do_remember;
|
||||
return ($1, int($2), $3, defined($4) ? int($4) : -1);
|
||||
}
|
||||
|
||||
sub _get_prev_pos {
|
||||
my ($basedir, $nr, $host) = @_;
|
||||
my $path = sprintf("$basedir/version-%09d-$host", $nr);
|
||||
my $vers = get_link($path, 1);
|
||||
my ($basedir, $nr, $peer, $do_remember) = @_;
|
||||
my $path = sprintf("$basedir/version-%09d-$peer", $nr);
|
||||
my $vers = get_link($path, 2);
|
||||
_parse_pos($path, 1) if $do_remember && defined($vers) && $vers;
|
||||
$vers =~ s/^.*://;
|
||||
return $vers;
|
||||
}
|
||||
|
@ -647,30 +659,39 @@ sub detect_splitbrain {
|
|||
}
|
||||
|
||||
sub _mark_path_backward {
|
||||
my ($basedir, $pos) = @_;
|
||||
my ($basedir, $pos, $peer, $skip_last) = @_;
|
||||
my $sum = 0;
|
||||
for (;;) {
|
||||
my ($p, $nr, $from, $len) = _parse_pos($pos, 1);
|
||||
$pos = _get_prev_pos($basedir, $nr, $from);
|
||||
_visit($nr, $peer);
|
||||
$pos = _get_prev_pos($basedir, $nr, $peer, 1);
|
||||
last if !$pos;
|
||||
# optionally don't count the last versionlink, pointing into nirvana
|
||||
if (defined($skip_last) && $skip_last && $nr > 1) {
|
||||
my ($p, $nr, $from, $len) = _parse_pos($pos, 0);
|
||||
last if !$p;
|
||||
my $next = _get_prev_pos($basedir, $nr, $peer, 1);
|
||||
last if !$next;
|
||||
}
|
||||
$sum += $len;
|
||||
}
|
||||
return $sum;
|
||||
}
|
||||
|
||||
sub _mark_path_forward {
|
||||
my ($basedir, $pos) = @_;
|
||||
my ($basedir, $pos, $peer) = @_;
|
||||
my @list = ($pos);
|
||||
while (@list) {
|
||||
my %next_list;
|
||||
foreach $pos (@list) {
|
||||
my ($p, $nr, $from, $len) = _parse_pos($pos, 1);
|
||||
my $next = sprintf("$basedir/version-%09d-*", $nr + 1);
|
||||
my @candidates = glob($next);
|
||||
foreach my $cand (@candidates) {
|
||||
my $vers = get_link($cand, 1);
|
||||
$vers =~ s/^.*://;
|
||||
my ($cp, $cnr, $cfrom, $clen) = _parse_pos($vers, 0);
|
||||
if (int($cnr) == int($nr) && $cfrom eq $from && $clen == $len) {
|
||||
$next_list{$cand} = 1;
|
||||
}
|
||||
my $cand = sprintf("$basedir/version-%09d-$peer", $nr + 1);
|
||||
my $vers = get_link($cand, 2);
|
||||
next unless defined($vers) && $vers ne "";
|
||||
$vers =~ s/^.*://;
|
||||
my ($cp, $cnr, $cfrom, $clen) = _parse_pos($vers, 0);
|
||||
if (int($cnr) == int($nr) && $cfrom eq $from && $clen == $len) {
|
||||
$next_list{$cand} = 1;
|
||||
}
|
||||
}
|
||||
@list = keys(%next_list);
|
||||
|
@ -684,20 +705,82 @@ sub _mark_path_transitive {
|
|||
|
||||
sub log_purge_res {
|
||||
my ($cmd, $res) = @_;
|
||||
lwarn "DANGEROUS OPERATION: $cmd on resource '$res'\n";
|
||||
my %start_logs;
|
||||
my $start_count = 0;
|
||||
my $basedir = "$mars/resource-$res";
|
||||
my @files = glob("$basedir/{log,version}-*");
|
||||
foreach my $replay (glob("$basedir/replay-*")) {
|
||||
foreach my $data (glob("$basedir/{data,replay}-*")) {
|
||||
$data =~ m:/(data|replay)-(.+):;
|
||||
my $peer = $2;
|
||||
my $replay = "$basedir/replay-$peer";
|
||||
my $target = get_link($replay, 1);
|
||||
_mark_path_transitive($basedir, $target);
|
||||
lprint "found replay link '$replay' -> '$target'\n";
|
||||
$target =~ s/,.*//;
|
||||
$start_logs{$target}++;
|
||||
$start_count++;
|
||||
_mark_path_transitive($basedir, $target, $peer);
|
||||
}
|
||||
foreach my $file (@files) {
|
||||
$file =~ m:/((log|version)-([0-9]+)-([^,]+)): or ldie "bad path '$file'\n";
|
||||
next if (!$force && $4 ne $host);
|
||||
my $visit = "$3,$4";
|
||||
lprint "checking '$1'\n";
|
||||
next if $visited_pos{$visit};
|
||||
if (!$start_count) {
|
||||
ldie "Resource contains no valid information - refusing to delete everything for safety reasons\n";
|
||||
}
|
||||
my %logs;
|
||||
foreach my $file (glob("$basedir/version-*")) {
|
||||
$file =~ m:/(version-([0-9]+)-([^,]+)): or ldie "bad path '$file'\n";
|
||||
my $cand = $1;
|
||||
my $nr = $2;
|
||||
my $from = $3;
|
||||
lprint "checking '$cand'\n";
|
||||
my $vers = get_link($file, 1);
|
||||
$vers =~ m/(log-[0-9]+-[^,:]+)/;
|
||||
my $log = $1;
|
||||
lprint " corresponding logfile is '$log'\n";
|
||||
$logs{$log}++;
|
||||
if (_is_visited($nr, $from)) {
|
||||
lprint " ok '$cand'\n";
|
||||
next;
|
||||
}
|
||||
if (!$force && $from ne $host) {
|
||||
lprint " skipping foreign object '$cand'\n";
|
||||
next;
|
||||
}
|
||||
lwarn "deleting foreign object from peer '$from' because you said --force\n" if $from ne $host;
|
||||
_create_delete($file);
|
||||
}
|
||||
foreach my $file (glob("$basedir/log-*")) {
|
||||
$file =~ m:/(log-[0-9]+-(.*)): or ldie "bad path '$file'\n";
|
||||
my $log = $1;
|
||||
my $from = $2;
|
||||
lprint "checking '$log'\n";
|
||||
if ($logs{$log}) {
|
||||
lprint " ok '$log'\n";
|
||||
$logs{$log} = -1;
|
||||
next;
|
||||
}
|
||||
if ($start_logs{$log}) {
|
||||
lprint " ok start '$log'\n";
|
||||
$logs{$log} = -1;
|
||||
next;
|
||||
}
|
||||
if (!$force && $from ne $host) {
|
||||
lprint " skipping foreign object '$log'\n";
|
||||
next;
|
||||
}
|
||||
lwarn "deleting foreign object from peer '$from' because you said --force\n" if $from ne $host;
|
||||
_create_delete($file);
|
||||
}
|
||||
my $count = 0;
|
||||
foreach my $log (sort(keys(%logs))) {
|
||||
my $nr = $logs{$log};
|
||||
next if $nr < 0 || -e "$basedir/$log";
|
||||
lprint_stderr "info: logfile '$log' is referenced ($nr), but not present.\n";
|
||||
$count++;
|
||||
}
|
||||
if ($count) {
|
||||
lprint_stderr " Unreferenced logfiles are not necessarily bad.\n";
|
||||
lprint_stderr " They can regularly appear after 'leave-resource',\n";
|
||||
lprint_stderr " or 'invalidate', or after emergency mode,\n";
|
||||
lprint_stderr " or after similar operations.\n";
|
||||
}
|
||||
finish_links();
|
||||
_wait_delete();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue