From 83ae4720fa6f23a9617f03d78d34cd4edb31c97a Mon Sep 17 00:00:00 2001 From: Thomas Schoebel-Theuer Date: Thu, 11 Feb 2016 20:56:22 +0100 Subject: [PATCH] marsadm: reimplement buggy primitive macros The old version was complicated and error prone, due to historic development. Now the structure should be much simpler. --- userspace/marsadm | 174 +++++++++++++++++++++++++--------------------- 1 file changed, 95 insertions(+), 79 deletions(-) diff --git a/userspace/marsadm b/userspace/marsadm index c659a037..8e762537 100755 --- a/userspace/marsadm +++ b/userspace/marsadm @@ -719,6 +719,84 @@ sub compare_replaylinks { ################################################################## +sub get_amount { + my ($resdir, $host, $direction, $only_files) = @_; + my $level = 0; + my $firstpos = 0; + my $logpos = 0; + my $oldpos = 0; + my $sum = 0; + for (;;) { + my $val0 = 0; + my $ok = 0; + if (!$level) { + my $replay_path = sprintf("%s/replay-%s", $resdir, $host); + my $replay_link = get_link($replay_path, 1); + return (0, 0, 0, 0) if !$replay_link; + return (0, 0, 0, 0) if $replay_link !~ m:log-([0-9]+)-[^,]+,([0-9]+),([0-9]+):; + $firstpos = int($1); + $logpos = $firstpos; + if ($direction < 0) { + $sum = $2; + } else { + $val0 = $2; + $sum = $3; + } + } + if ($level > 0 || $direction > 0) { + my $file = sprintf("%s/log-%09d-%s", $resdir, $logpos, $host); + my @stat = stat($file); + my $val = 0; + if (@stat) { + $val = $stat[7]; + $ok = 1; + } else { + my $glob = sprintf("%s/log-%09d-*", $resdir, $logpos); + foreach $file (glob($glob)) { + my @tstat = stat($file); + if (@tstat && $tstat[7] > $val) { + @stat = @tstat; + $val = $stat[7]; + $ok = 1; + } + } + } + if (!$only_files) { + my $glob = sprintf("%s/version-%09d-*", $resdir, $logpos); + foreach $file (glob($glob)) { + my $vers_link = get_link($file, 1); + if ($vers_link && $vers_link =~ m;,([0-9]+):;) { + my $nval = $1; + $val = $nval if $nval > $val; + $ok = 1; + } + } + } + return ($sum, $firstpos, $oldpos, $level) unless $ok; + if ($level > 0) { + $sum += $val; + } else { + # the logfile may be bigger than the replay pos/length + my $new_sum = $val - $val0; + $sum = $new_sum if $new_sum > $sum; + $sum = 0 if $sum < 0; + } + } + $oldpos = $logpos; + if ($direction > 0) { + $logpos++; + } elsif ($direction < 0) { + $logpos--; + return ($sum, $firstpos, $oldpos, $level) if $logpos < 1; + } else { + return ($sum, $firstpos, $oldpos, $level); + } + $level++; + } +} + +################################################################## + # versionlink path handling routines my %visited_pos; @@ -3119,89 +3197,27 @@ sub eval_fn { my $lnk = $$env{"resdir"} . "/syncstatus-" . $$env{"host"}; return get_link($lnk, 1); } - if (/^(fetch|replay|work|syncpos)[-_]?(size|pos|lognr|basenr|_internal_)$/) { + if (/^(replay|work)[-_]?(pos|lognr|basenr)$/) { my $what = $1; my $op = $2; - my $sum = 0; - my $pos; - # work-* spans both the replay and fetch ranges - if ($what eq "work") { - $what = ($op eq "size") ? "fetch" : "replay"; - } - my ($min, $max, $inter_sum) = (0, 0, 0); - if ($op eq "size" || ($what eq "fetch" && $op =~ /nr$/)) { - if ($what eq "replay") { # same as fetch-pos - return eval_fn($env, "fetch-pos", ""); - } - - my $primary = _get_designated_primary($$env{"res"}); - $primary = $host if $primary eq "(none)"; - my $replay_base_nr = eval_fn($env, "replay-basenr", ""); - - my $replay = get_link($$env{"resdir"} . "/replay-$primary", 1); - ($pos, my $nr, my $from, $sum) = _parse_pos($$env{"resdir"}, $replay); - my $base_nr = $nr; - $pos = _get_prev_pos($$env{"resdir"}, $nr, $primary); - if ($pos) { - (my $plus, $base_nr) = _mark_path_backward($$env{"resdir"}, $pos, $primary, $replay_base_nr, $host); - $sum += $plus; - } - - ($min, $max) = get_minmax_versions($$env{"res"}, "-$primary"); - my $check_pos = get_link($$env{"resdir"} . "/version-$max-$primary", 1); - $check_pos =~ s{^.*(log-[^:]*):.*$}{$1}; - my ($test_pos, $test_nr, $test_from, $test_sum) = _parse_pos($$env{"resdir"}, $check_pos); - $test_pos = _get_prev_pos($$env{"resdir"}, $test_nr, $primary); - my $test_base_nr = $base_nr; - if ($test_pos) { - (my $test_plus, $test_base_nr) = _mark_path_backward($$env{"resdir"}, $test_pos, $primary, $replay_base_nr, $host); - $test_sum += $test_plus; - } - if ($test_sum > $sum) { # take the maximum - ($pos, $nr, $from, $sum, $base_nr) = ($test_pos, $test_nr, $test_from, $test_sum, $test_base_nr); - } - return $nr if $op eq "lognr"; - return $base_nr if $op eq "basenr"; - return $sum; - } elsif ($what eq "fetch") { # fetch-pos - (my $stop_nr, my $stop_sum, $sum) = eval_fn($env, "replay-_internal_", ""); - $sum -= $stop_sum; - $sum = 0 if $sum < 0; - # mark all path elements reachable by the designated primary - %visited_pos = (); - eval_fn($env, "fetch-size", ""); - foreach my $file (sort(glob($$env{"resdir"} . "/log-*"))) { - $file =~ m:/log-([0-9]+)-(.*): or ldie "bad path '$file'\n"; - my $nr = $1; - my $from = $2; - if ($nr < $stop_nr || !_is_visited($nr, $from)) { - next; - } - my @stat = stat($file); - $sum += $stat[7]; - } - return $sum; - } elsif ($what =~ m/replay|syncpos/) { - my $replay = get_link($$env{"resdir"} . "/$what-" . $$env{"host"}, $what eq "syncpos" ? 2 : 1); - return 0 unless $replay; - my ($p, $nr, $from, $len) = _parse_pos($$env{"resdir"}, $replay); - return $nr if $op eq "lognr"; - $min = $nr; - $sum = $len; - $inter_sum = $sum; - $pos = _get_prev_pos($$env{"resdir"}, $nr, $$env{"host"}); - } else { - ldie "unknown combination '$what' '$op'\n"; - } - if ($pos) { - my ($plus, $base_nr) = _mark_path_backward($$env{"resdir"}, $pos, $$env{"host"}, 1); - return $base_nr if $op eq "basenr"; - $sum += $plus; - } - return $min if $op eq "basenr"; - return (make_numeric($min), make_numeric($inter_sum), make_numeric($sum)) if $op eq "_internal_"; + my ($sum, $firstpos, $logpos, $level) = get_amount($$env{"resdir"}, $$env{"host"}, -1, 0); + return $firstpos if $op eq "lognr"; + return $logpos if $op eq "basenr"; return $sum; } + if (/^(replay[-_]?size)|(fetch[-_]?pos)$/) { + my ($sum0) = get_amount($$env{"resdir"}, $$env{"host"}, -1, 0); + my ($sum, $firstpos, $logpos, $level) = get_amount($$env{"resdir"}, $$env{"host"}, 1, 1); + return $sum0 + $sum; + } + if (/^(fetch|work)[-_]?(size|lognr)$/) { + my $what = $1; + my $op = $2; + my ($sum0) = get_amount($$env{"resdir"}, $$env{"host"}, -1, 0); + my ($sum, $firstpos, $logpos, $level) = get_amount($$env{"resdir"}, $$env{"host"}, 1, 0); + return $logpos if $op eq "lognr"; + return $sum0 + $sum; + } if (/^(sync|fetch|replay|work)[-_]?(rest|(?:almost[-_]?|threshold[-_]?)?reached|percent|permille|vector)$/) { my $what = $1; my $op = $2;