infrastructure:diskchecker
Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentesRévision précédente | |||
infrastructure:diskchecker [2018/09/10 11:54] – ronan | infrastructure:diskchecker [2019/01/10 15:18] (Version actuelle) – rguyader | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
====== Diskchecker.pl ====== | ====== Diskchecker.pl ====== | ||
+ | <code perl> | ||
+ | # | ||
+ | # | ||
+ | # Brad's el-ghetto do-our-storage-stacks-lie? | ||
+ | # | ||
+ | # https:// | ||
- | # | + | sub usage { |
- | # | + | die <<' |
- | # Brad's el-ghetto do-our-storage-stacks-lie? | + | |
- | # | + | |
- | # https:// | + | |
- | + | ||
- | sub usage { | + | |
- | | + | |
Usage: diskchecker.pl -s < | Usage: diskchecker.pl -s < | ||
- | diskchecker.pl -s < | + | diskchecker.pl -s < |
- | diskchecker.pl -l [port] | + | diskchecker.pl -l [port] |
END | END | ||
- | } | + | } |
- | + | ||
- | use strict; | + | use strict; |
- | use IO:: | + | use IO:: |
- | use IO:: | + | use IO:: |
- | use Getopt:: | + | use Getopt:: |
- | use Socket qw(IPPROTO_TCP TCP_NODELAY); | + | use Socket qw(IPPROTO_TCP TCP_NODELAY); |
- | + | ||
- | my $server; | + | my $server; |
- | my $listen; | + | my $listen; |
- | usage() unless GetOptions(' | + | usage() unless GetOptions(' |
- | | + | ' |
- | usage() unless $server || $listen; | + | usage() unless $server || $listen; |
- | usage() if | + | usage() if |
- | + | ||
- | # LISTEN MODE: | + | # LISTEN MODE: |
- | listen_mode($listen) if $listen; | + | listen_mode($listen) if $listen; |
- | + | ||
- | # CLIENT MODE: | + | # CLIENT MODE: |
- | my $LEN = 16 * 1024; # 16kB (same as InnoDB page) | + | my $LEN = 16 * 1024; # 16kB (same as InnoDB page) |
- | my $mode = shift; | + | my $mode = shift; |
- | usage() unless $mode =~ / | + | usage() unless $mode =~ / |
- | + | ||
- | my $file = shift or usage(); | + | my $file = shift or usage(); |
- | my $size; | + | my $size; |
- | if ($mode eq " | + | if ($mode eq " |
- | | + | $size = shift or usage(); |
- | } | + | } |
- | + | ||
- | $server .= ": | + | $server .= ": |
- | + | ||
- | my $sock = IO:: | + | my $sock = IO:: |
- | | + | or die " |
- | + | ||
- | setsockopt($sock, | + | setsockopt($sock, |
- | + | ||
- | create() if $mode eq " | + | create() if $mode eq " |
- | verify() if $mode eq " | + | verify() if $mode eq " |
- | exit 0; | + | exit 0; |
- | + | ||
- | sub verify { | + | sub verify { |
- | | + | sendmsg($sock, |
- | + | ||
- | | + | my $error_ct = 0; |
- | | + | my %error_ct; |
- | + | ||
- | | + | my $size = -s $file; |
- | | + | my $max_pages = int($size / $LEN); |
- | + | ||
- | | + | my $percent; |
- | | + | my $last_dump = 0; |
- | | + | my $show_percent = sub { |
printf " verifying: %.02f%%\n", | printf " verifying: %.02f%%\n", | ||
- | | + | }; |
- | + | ||
- | | + | open (F, $file) or die " |
- | + | ||
- | | + | while (< |
chomp; | chomp; | ||
my ($page, $good, $val, $ago) = split(/\t/, $_); | my ($page, $good, $val, $ago) = split(/\t/, $_); | ||
$percent = 100 * $page / ($max_pages || 1); | $percent = 100 * $page / ($max_pages || 1); | ||
- | | + | |
my $now = time; | my $now = time; | ||
if ($last_dump != $now) { | if ($last_dump != $now) { | ||
- | | + | $last_dump = $now; |
- | | + | $show_percent-> |
} | } | ||
- | | + | |
next unless $good; | next unless $good; | ||
- | | + | |
my $offset = $page * $LEN; | my $offset = $page * $LEN; | ||
sysseek F, $offset, 0; | sysseek F, $offset, 0; | ||
Ligne 89: | Ligne 89: | ||
my $tobe = sprintf(" | my $tobe = sprintf(" | ||
substr($tobe, | substr($tobe, | ||
- | | + | |
unless ($buf eq $tobe) { | unless ($buf eq $tobe) { | ||
- | | + | $error_ct{$ago}++; |
- | | + | $error_ct++; |
- | | + | print " |
} | } | ||
- | | + | } |
- | | + | $show_percent-> |
- | + | ||
- | | + | print "Total errors: $error_ct\n"; |
- | | + | if ($error_ct) { |
print " | print " | ||
foreach (sort { $a <=> $b } keys %error_ct) { | foreach (sort { $a <=> $b } keys %error_ct) { | ||
- | | + | printf " |
} | } | ||
- | } | ||
} | } | ||
- | | + | } |
- | sub create { | + | |
- | | + | sub create { |
- | + | open (F, "> | |
- | | + | |
+ | my $ioh = IO:: | ||
or die; | or die; | ||
- | | + | |
- | | + | my $pages = int( ($size * 1024 * 1024) / $LEN ); # 50 MiB of 16k pages (3200 pages) |
- | + | ||
- | | + | my %page_hit; |
- | | + | my $pages_hit = 0; |
- | | + | my $uniq_pages_hit = 0; |
- | | + | my $start = time(); |
- | | + | my $last_dump = $start; |
- | + | ||
- | | + | while (1) { |
my $rand = int rand 2000000; | my $rand = int rand 2000000; | ||
my $buf = sprintf(" | my $buf = sprintf(" | ||
substr($buf, | substr($buf, | ||
- | | + | |
my $pagenum = int rand $pages; | my $pagenum = int rand $pages; | ||
my $offset = $pagenum * $LEN; | my $offset = $pagenum * $LEN; | ||
- | | + | |
sendmsg($sock, | sendmsg($sock, | ||
- | | + | |
- | # now wait for acknowledgement | + | # now wait for acknowledgement |
my $ok = readmsg($sock); | my $ok = readmsg($sock); | ||
die " | die " | ||
- | | + | |
sysseek F, | sysseek F, | ||
my $wv = syswrite(F, $buf, $LEN); | my $wv = syswrite(F, $buf, $LEN); | ||
die " | die " | ||
$ioh-> | $ioh-> | ||
- | | + | |
sendmsg($sock, | sendmsg($sock, | ||
- | | + | |
$pages_hit++; | $pages_hit++; | ||
unless ($page_hit{$pagenum}++) { | unless ($page_hit{$pagenum}++) { | ||
- | | + | $uniq_pages_hit++; |
} | } | ||
- | | + | |
my $now = time; | my $now = time; | ||
if ($now != $last_dump) { | if ($now != $last_dump) { | ||
- | | + | $last_dump = $now; |
- | | + | my $runtime = $now - $start; |
- | | + | printf(" |
- | $runtime, | + | $runtime, |
- | (100 * $uniq_pages_hit / $pages), | + | (100 * $uniq_pages_hit / $pages), |
- | $size, | + | $size, |
- | $pages_hit, | + | $pages_hit, |
- | $pages_hit / $runtime, | + | $pages_hit / $runtime, |
- | ); | + | ); |
} | } | ||
- | } | ||
- | } | ||
- | | ||
- | sub readmsg { | ||
- | my $sock = shift; | ||
- | my $len; | ||
- | my $rv = sysread($sock, | ||
- | return undef unless $rv == 1; | ||
- | my $msg; | ||
- | $rv = sysread($sock, | ||
- | return $msg; | ||
- | } | ||
- | | ||
- | sub sendmsg { | ||
- | my ($sock, $msg) = @_; | ||
- | my $rv = syswrite($sock, | ||
- | my $expect = length($msg) + 1; | ||
- | die " | ||
- | return 1; | ||
} | } | ||
- | | + | } |
- | sub listen_mode { | + | |
- | | + | sub readmsg { |
- | | + | my $sock = shift; |
- | Listen => 1, | + | my $len; |
- | LocalPort => $port) | + | my $rv = sysread($sock, |
+ | return undef unless $rv == 1; | ||
+ | my $msg; | ||
+ | $rv = sysread($sock, | ||
+ | return $msg; | ||
+ | } | ||
+ | |||
+ | sub sendmsg { | ||
+ | my ($sock, $msg) = @_; | ||
+ | my $rv = syswrite($sock, | ||
+ | my $expect = length($msg) + 1; | ||
+ | die " | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | sub listen_mode { | ||
+ | my $port = shift; | ||
+ | my $server = IO:: | ||
+ | Listen => 1, | ||
+ | LocalPort => $port) | ||
or die " | or die " | ||
- | | + | |
- | | + | while (1) { |
print " | print " | ||
my $sock = $server-> | my $sock = $server-> | ||
- | | + | or die " |
setsockopt($sock, | setsockopt($sock, | ||
- | | + | |
fork and next; | fork and next; | ||
process_incoming_conn($sock); | process_incoming_conn($sock); | ||
exit 0; | exit 0; | ||
- | } | ||
} | } | ||
- | | + | } |
- | sub process_incoming_conn { | + | |
- | | + | sub process_incoming_conn { |
- | | + | my $sock = shift; |
- | die " | + | my $peername = getpeername($sock) or |
- | | + | die " |
- | | + | my ($port, $iaddr) = sockaddr_in($peername); |
- | + | my $ip = inet_ntoa($iaddr); | |
- | | + | |
- | | + | my $file = "/ |
- | + | die "[$ip] $file is a symlink" | |
- | | + | |
- | + | print "[$ip] New connection\n"; | |
- | | + | |
- | | + | my $lines = 0; |
- | | + | my %state; |
- | + | my $end; | |
- | | + | |
+ | while (1) { | ||
if ($lines) { | if ($lines) { | ||
- | | + | last unless wait_for_readability(fileno($sock), |
} | } | ||
my $line = readmsg($sock); | my $line = readmsg($sock); | ||
last unless $line; | last unless $line; | ||
- | | + | |
if ($line eq " | if ($line eq " | ||
- | | + | print "[$ip] Sending state info from ${ip}' |
- | | + | open (S, " |
- | | + | while (<S>) { |
- | print $sock $_; | + | print $sock $_; |
- | | + | } |
- | | + | close S; |
- | | + | print "[$ip] Done.\n"; |
- | | + | exit 0; |
} | } | ||
- | | + | |
$lines++; | $lines++; | ||
my $now = time; | my $now = time; | ||
Ligne 238: | Ligne 238: | ||
my ($state, $pagenum, $rand) = split(/\t/, $line); | my ($state, $pagenum, $rand) = split(/\t/, $line); | ||
if ($state eq " | if ($state eq " | ||
- | | + | $state{$pagenum} = [ 0, $rand+0, $now ]; |
- | | + | sendmsg($sock, |
} elsif ($state eq " | } elsif ($state eq " | ||
- | | + | $state{$pagenum} = [ 1, $rand+0, $now ]; |
} | } | ||
print "[$ip] $lines writes\n" | print "[$ip] $lines writes\n" | ||
- | | + | } |
- | + | ||
- | | + | print "[$ip] Writing state file...\n"; |
- | | + | open (S, "> |
- | | + | foreach (sort { $a <=> $b } keys %state) { |
my $v = $state{$_}; | my $v = $state{$_}; | ||
my $before_end = $end - $v->[2]; | my $before_end = $end - $v->[2]; | ||
print S " | print S " | ||
- | } | ||
- | print "[$ip] Done.\n"; | ||
- | } | ||
- | | ||
- | sub wait_for_readability { | ||
- | my ($fileno, $timeout) = @_; | ||
- | return 0 unless $fileno && $timeout; | ||
- | | ||
- | my $rin; | ||
- | vec($rin, $fileno, 1) = 1; | ||
- | my $nfound = select($rin, | ||
- | | ||
- | return 0 unless defined $nfound; | ||
- | return $nfound ? 1 : 0; | ||
} | } | ||
+ | print "[$ip] Done.\n"; | ||
+ | } | ||
+ | |||
+ | sub wait_for_readability { | ||
+ | my ($fileno, $timeout) = @_; | ||
+ | return 0 unless $fileno && $timeout; | ||
+ | |||
+ | my $rin; | ||
+ | vec($rin, $fileno, 1) = 1; | ||
+ | my $nfound = select($rin, | ||
+ | |||
+ | return 0 unless defined $nfound; | ||
+ | return $nfound ? 1 : 0; | ||
+ | } | ||
+ | </ | ||
+ |
infrastructure/diskchecker.1536580447.txt.gz · Dernière modification : 2018/09/10 11:54 de ronan