112 lines
2.8 KiB
Plaintext
112 lines
2.8 KiB
Plaintext
|
#!/usr/bin/perl
|
||
|
#
|
||
|
# memcached-tool:
|
||
|
# stats/management tool for memcached.
|
||
|
#
|
||
|
# Author:
|
||
|
# Brad Fitzpatrick <brad@danga.com>
|
||
|
#
|
||
|
# License:
|
||
|
# public domain. I give up all rights to this
|
||
|
# tool. modify and copy at will.
|
||
|
#
|
||
|
|
||
|
use strict;
|
||
|
use IO::Socket::INET;
|
||
|
|
||
|
my $host = shift;
|
||
|
my $mode = shift || "display";
|
||
|
my ($from, $to);
|
||
|
|
||
|
if ($mode eq "display") {
|
||
|
undef $mode if @ARGV;
|
||
|
} elsif ($mode eq "move") {
|
||
|
$from = shift;
|
||
|
$to = shift;
|
||
|
undef $mode if $from < 6 || $from > 17;
|
||
|
undef $mode if $to < 6 || $to > 17;
|
||
|
print STDERR "ERROR: parameters out of range\n\n" unless $mode;
|
||
|
} else {
|
||
|
undef $mode;
|
||
|
}
|
||
|
|
||
|
undef $mode if @ARGV;
|
||
|
|
||
|
die
|
||
|
"Usage: memcached-tool <host[:port]> [mode]\n
|
||
|
memcached-tool 10.0.0.5:11211 display # shows slabs
|
||
|
memcached-tool 10.0.0.5:11211 # same. (default is display)
|
||
|
memcached-tool 10.0.0.5:11211 move 7 9 # takes 1MB slab from class #7
|
||
|
# to class #9.
|
||
|
|
||
|
You can only move slabs around once memory is totally allocated, and only
|
||
|
once the target class is full. (So you can't move from #6 to #9 and #7
|
||
|
to #9 at the same itme, since you'd have to wait for #9 to fill from
|
||
|
the first reassigned page)
|
||
|
" unless $host && $mode;
|
||
|
|
||
|
$host .= ":11211" unless $host =~ /:\d+/;
|
||
|
|
||
|
my $sock = IO::Socket::INET->new(PeerAddr => $host,
|
||
|
Proto => 'tcp');
|
||
|
die "Couldn't connect to $host\n" unless $sock;
|
||
|
|
||
|
|
||
|
if ($mode eq "move") {
|
||
|
my $tries = 0;
|
||
|
while (1) {
|
||
|
print $sock "slabs reassign $from $to\r\n";
|
||
|
my $res = <$sock>;
|
||
|
$res =~ s/\s+//;
|
||
|
if ($res eq "DONE") {
|
||
|
print "Success.\n";
|
||
|
exit 0;
|
||
|
} elsif ($res eq "CANT") {
|
||
|
print "Error: can't move from $from to $to. Destination not yet full? See usage docs.\n";
|
||
|
exit;
|
||
|
} elsif ($res eq "BUSY") {
|
||
|
if (++$tries == 3) {
|
||
|
print "Failed to move after 3 tries. Try again later.\n";
|
||
|
exit;
|
||
|
}
|
||
|
|
||
|
print "Page busy, retrying...\n";
|
||
|
sleep 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exit;
|
||
|
}
|
||
|
|
||
|
# display mode:
|
||
|
|
||
|
my %items; # class -> { number, age, chunk_size, chunks_per_page,
|
||
|
# total_pages, total_chunks, used_chunks,
|
||
|
# free_chunks, free_chunks_end }
|
||
|
|
||
|
print $sock "stats items\r\n";
|
||
|
while (<$sock>) {
|
||
|
last if /^END/;
|
||
|
if (/^STAT items:(\d+):(\w+) (\d+)/) {
|
||
|
$items{$1}{$2} = $3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
print $sock "stats slabs\r\n";
|
||
|
while (<$sock>) {
|
||
|
last if /^END/;
|
||
|
if (/^STAT (\d+):(\w+) (\d+)/) {
|
||
|
$items{$1}{$2} = $3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
print " # Item_Size Max_age 1MB_pages Full?\n";
|
||
|
foreach my $n (6..17) {
|
||
|
my $it = $items{$n};
|
||
|
my $size = $it->{chunk_size} < 1024 ? "$it->{chunk_size} B" :
|
||
|
sprintf("%d kB", $it->{chunk_size} / 1024);
|
||
|
my $full = $it->{free_chunks_end} == 0 ? "yes" : " no";
|
||
|
printf "%3d %6s%7d s %7d $full\n", $n, $size, $it->{age}, $it->{total_pages};
|
||
|
}
|
||
|
|