|
Packit |
4e8bc4 |
#!/usr/bin/perl
|
|
Packit |
4e8bc4 |
#
|
|
Packit |
4e8bc4 |
# memcached-tool:
|
|
Packit |
4e8bc4 |
# stats/management tool for memcached.
|
|
Packit |
4e8bc4 |
#
|
|
Packit |
4e8bc4 |
# Author:
|
|
Packit |
4e8bc4 |
# Brad Fitzpatrick <brad@danga.com>
|
|
Packit |
4e8bc4 |
#
|
|
Packit |
4e8bc4 |
# Contributor:
|
|
Packit |
4e8bc4 |
# Andrey Niakhaichyk <andrey@niakhaichyk.org>
|
|
Packit |
4e8bc4 |
#
|
|
Packit |
4e8bc4 |
# License:
|
|
Packit |
4e8bc4 |
# public domain. I give up all rights to this
|
|
Packit |
4e8bc4 |
# tool. modify and copy at will.
|
|
Packit |
4e8bc4 |
#
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
use strict;
|
|
Packit |
4e8bc4 |
use IO::Socket::INET;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
my $addr = shift;
|
|
Packit |
4e8bc4 |
my $mode = shift || "display";
|
|
Packit |
4e8bc4 |
my ($from, $to);
|
|
Packit |
4e8bc4 |
my $limit;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if ($mode eq "display") {
|
|
Packit |
4e8bc4 |
undef $mode if @ARGV;
|
|
Packit |
4e8bc4 |
} elsif ($mode eq "move") {
|
|
Packit |
4e8bc4 |
$from = shift;
|
|
Packit |
4e8bc4 |
$to = shift;
|
|
Packit |
4e8bc4 |
undef $mode if $from < 6 || $from > 17;
|
|
Packit |
4e8bc4 |
undef $mode if $to < 6 || $to > 17;
|
|
Packit |
4e8bc4 |
print STDERR "ERROR: parameters out of range\n\n" unless $mode;
|
|
Packit |
4e8bc4 |
} elsif ($mode eq 'dump') {
|
|
Packit |
4e8bc4 |
if (@ARGV) {
|
|
Packit |
4e8bc4 |
$limit = shift;
|
|
Packit |
4e8bc4 |
undef $mode if $limit < 1;
|
|
Packit |
4e8bc4 |
print STDERR "ERROR: invalid limit (should be a positive number)\n\n" unless $mode;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
} elsif ($mode eq 'stats') {
|
|
Packit |
4e8bc4 |
;
|
|
Packit |
4e8bc4 |
} elsif ($mode eq 'settings') {
|
|
Packit |
4e8bc4 |
;
|
|
Packit |
4e8bc4 |
} elsif ($mode eq 'sizes') {
|
|
Packit |
4e8bc4 |
;
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
undef $mode;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
undef $mode if @ARGV;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
die
|
|
Packit |
4e8bc4 |
"Usage: memcached-tool <host[:port] | /path/to/socket> [mode]\n
|
|
Packit |
4e8bc4 |
memcached-tool 10.0.0.5:11211 display # shows slabs
|
|
Packit |
4e8bc4 |
memcached-tool 10.0.0.5:11211 # same. (default is display)
|
|
Packit |
4e8bc4 |
memcached-tool 10.0.0.5:11211 stats # shows general stats
|
|
Packit |
4e8bc4 |
memcached-tool 10.0.0.5:11211 settings # shows settings stats
|
|
Packit |
4e8bc4 |
memcached-tool 10.0.0.5:11211 sizes # shows sizes stats
|
|
Packit |
4e8bc4 |
memcached-tool 10.0.0.5:11211 dump [limit] # dumps keys and values
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
WARNING! sizes is a development command.
|
|
Packit |
4e8bc4 |
As of 1.4 it is still the only command which will lock your memcached instance for some time.
|
|
Packit |
4e8bc4 |
If you have many millions of stored items, it can become unresponsive for several minutes.
|
|
Packit |
4e8bc4 |
Run this at your own risk. It is roadmapped to either make this feature optional
|
|
Packit |
4e8bc4 |
or at least speed it up.
|
|
Packit |
4e8bc4 |
" unless $addr && $mode;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
sub server_connect {
|
|
Packit |
4e8bc4 |
my $sock;
|
|
Packit |
4e8bc4 |
if ($addr =~ m:/:) {
|
|
Packit |
4e8bc4 |
$sock = IO::Socket::UNIX->new(
|
|
Packit |
4e8bc4 |
Peer => $addr,
|
|
Packit |
4e8bc4 |
);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
else {
|
|
Packit |
4e8bc4 |
$addr .= ':11211' unless $addr =~ /:\d+$/;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
$sock = IO::Socket::INET->new(
|
|
Packit |
4e8bc4 |
PeerAddr => $addr,
|
|
Packit |
4e8bc4 |
Proto => 'tcp',
|
|
Packit |
4e8bc4 |
);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
die "Couldn't connect to $addr\n" unless $sock;
|
|
Packit |
4e8bc4 |
return $sock;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
my $sock = server_connect();
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if ($mode eq 'dump') {
|
|
Packit |
4e8bc4 |
print STDERR "Dumping memcache contents";
|
|
Packit |
4e8bc4 |
print STDERR " (limiting to $limit keys)" unless !$limit;
|
|
Packit |
4e8bc4 |
print STDERR "\n";
|
|
Packit |
4e8bc4 |
print $sock "lru_crawler metadump all\r\n";
|
|
Packit |
4e8bc4 |
my %keyexp;
|
|
Packit |
4e8bc4 |
my $keycount = 0;
|
|
Packit |
4e8bc4 |
while (<$sock>) {
|
|
Packit |
4e8bc4 |
last if /^END/ or ($limit and $keycount == $limit);
|
|
Packit |
4e8bc4 |
# return format looks like this
|
|
Packit |
4e8bc4 |
# key=foo exp=2147483647 la=1521046038 cas=717111 fetch=no cls=13 size=1232
|
|
Packit |
4e8bc4 |
if (/^key=(\S+) exp=(-?\d+) .*/) {
|
|
Packit |
4e8bc4 |
my ($k, $exp) = ($1, $2);
|
|
Packit |
4e8bc4 |
$k =~ s/%(.{2})/chr hex $1/eg;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if ($exp == -1) {
|
|
Packit |
4e8bc4 |
$keyexp{$k} = 0;
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
$keyexp{$k} = $exp;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
$keycount++;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if ($limit) {
|
|
Packit |
4e8bc4 |
# Need to reopen the connection here to stop the metadump in
|
|
Packit |
4e8bc4 |
# case the key limit was reached.
|
|
Packit |
4e8bc4 |
#
|
|
Packit |
4e8bc4 |
# XXX: Once a limit on # of keys returned is introduced in
|
|
Packit |
4e8bc4 |
# `lru_crawler metadump`, this should be removed and the proper
|
|
Packit |
4e8bc4 |
# parameter passed in the query above.
|
|
Packit |
4e8bc4 |
close($sock);
|
|
Packit |
4e8bc4 |
$sock = server_connect();
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
foreach my $k (keys(%keyexp)) {
|
|
Packit |
4e8bc4 |
print $sock "get $k\r\n";
|
|
Packit |
4e8bc4 |
my $response = <$sock>;
|
|
Packit |
4e8bc4 |
if ($response =~ /VALUE (\S+) (\d+) (\d+)/) {
|
|
Packit |
4e8bc4 |
my $flags = $2;
|
|
Packit |
4e8bc4 |
my $len = $3;
|
|
Packit |
4e8bc4 |
my $val;
|
|
Packit |
4e8bc4 |
read $sock, $val, $len;
|
|
Packit |
4e8bc4 |
print "add $k $flags $keyexp{$k} $len\r\n$val\r\n";
|
|
Packit |
4e8bc4 |
# get the END
|
|
Packit |
4e8bc4 |
$_ = <$sock>;
|
|
Packit |
4e8bc4 |
$_ = <$sock>;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
exit;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if ($mode eq 'stats') {
|
|
Packit |
4e8bc4 |
my %items;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
print $sock "stats\r\n";
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
while (<$sock>) {
|
|
Packit |
4e8bc4 |
last if /^END/;
|
|
Packit |
4e8bc4 |
chomp;
|
|
Packit |
4e8bc4 |
if (/^STAT\s+(\S*)\s+(.*)/) {
|
|
Packit |
4e8bc4 |
$items{$1} = $2;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
printf ("#%-22s %5s %13s\n", $addr, "Field", "Value");
|
|
Packit |
4e8bc4 |
foreach my $name (sort(keys(%items))) {
|
|
Packit |
4e8bc4 |
printf ("%29s %14s\n", $name, $items{$name});
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
exit;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if ($mode eq 'settings') {
|
|
Packit |
4e8bc4 |
my %items;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
print $sock "stats settings\r\n";
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
while (<$sock>) {
|
|
Packit |
4e8bc4 |
last if /^END/;
|
|
Packit |
4e8bc4 |
chomp;
|
|
Packit |
4e8bc4 |
if (/^STAT\s+(\S*)\s+(.*)/) {
|
|
Packit |
4e8bc4 |
$items{$1} = $2;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
printf ("#%-17s %5s %11s\n", $addr, "Field", "Value");
|
|
Packit |
4e8bc4 |
foreach my $name (sort(keys(%items))) {
|
|
Packit |
4e8bc4 |
printf ("%24s %12s\n", $name, $items{$name});
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
exit;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if ($mode eq 'sizes') {
|
|
Packit |
4e8bc4 |
my %items;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
print $sock "stats sizes\r\n";
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
while (<$sock>) {
|
|
Packit |
4e8bc4 |
last if /^END/;
|
|
Packit |
4e8bc4 |
chomp;
|
|
Packit |
4e8bc4 |
if (/^STAT\s+(\S*)\s+(.*)/) {
|
|
Packit |
4e8bc4 |
$items{$1} = $2;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
printf ("#%-17s %5s %11s\n", $addr, "Size", "Count");
|
|
Packit |
4e8bc4 |
foreach my $name (sort(keys(%items))) {
|
|
Packit |
4e8bc4 |
printf ("%24s %12s\n", $name, $items{$name});
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
exit;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
# display mode:
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
my %items; # class -> { number, age, chunk_size, chunks_per_page,
|
|
Packit |
4e8bc4 |
# total_pages, total_chunks, used_chunks,
|
|
Packit |
4e8bc4 |
# free_chunks, free_chunks_end }
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
print $sock "stats items\r\n";
|
|
Packit |
4e8bc4 |
my $max = 0;
|
|
Packit |
4e8bc4 |
while (<$sock>) {
|
|
Packit |
4e8bc4 |
last if /^END/;
|
|
Packit |
4e8bc4 |
if (/^STAT items:(\d+):(\w+) (\d+)/) {
|
|
Packit |
4e8bc4 |
$items{$1}{$2} = $3;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
print $sock "stats slabs\r\n";
|
|
Packit |
4e8bc4 |
while (<$sock>) {
|
|
Packit |
4e8bc4 |
last if /^END/;
|
|
Packit |
4e8bc4 |
if (/^STAT (\d+):(\w+) (\d+)/) {
|
|
Packit |
4e8bc4 |
$items{$1}{$2} = $3;
|
|
Packit |
4e8bc4 |
$max = $1;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
print " # Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM\n";
|
|
Packit |
4e8bc4 |
foreach my $n (1..$max) {
|
|
Packit |
4e8bc4 |
my $it = $items{$n};
|
|
Packit |
4e8bc4 |
next if (0 == $it->{total_pages});
|
|
Packit |
4e8bc4 |
my $size = $it->{chunk_size} < 1024 ?
|
|
Packit |
4e8bc4 |
"$it->{chunk_size}B" :
|
|
Packit |
4e8bc4 |
sprintf("%.1fK", $it->{chunk_size} / 1024.0);
|
|
Packit |
4e8bc4 |
my $full = $it->{used_chunks} == $it->{total_chunks} ? "yes" : " no";
|
|
Packit |
4e8bc4 |
printf("%3d %8s %9ds %7d %7d %7s %8d %8d %4d\n",
|
|
Packit |
4e8bc4 |
$n, $size, $it->{age}, $it->{total_pages},
|
|
Packit |
4e8bc4 |
$it->{number}, $full, $it->{evicted},
|
|
Packit |
4e8bc4 |
$it->{evicted_time}, $it->{outofmemory});
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|