Skip to content

Instantly share code, notes, and snippets.

@benclark
Created December 30, 2015 20:52
Show Gist options
  • Save benclark/6205473a05030d6e2e6f to your computer and use it in GitHub Desktop.
Save benclark/6205473a05030d6e2e6f to your computer and use it in GitHub Desktop.
#!/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 $addr = 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;
} elsif ($mode eq 'dump') {
;
} elsif ($mode eq 'stats') {
;
} else {
undef $mode;
}
undef $mode if @ARGV;
die
"Usage: memcached-tool <host[:port] | /path/to/socket> [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 stats # shows general stats
memcached-tool 10.0.0.5:11211 dump # dumps keys and values
" unless $addr && $mode;
my $sock;
if ($addr =~ m:/:) {
$sock = IO::Socket::UNIX->new(
Peer => $addr,
);
}
else {
$addr .= ':11211' unless $addr =~ /:\d+$/;
$sock = IO::Socket::INET->new(
PeerAddr => $addr,
Proto => 'tcp',
);
}
die "Couldn't connect to $addr\n" unless $sock;
if ($mode eq 'dump') {
my %items;
my $totalitems;
print $sock "stats items\r\n";
while (<$sock>) {
last if /^END/;
if (/^STAT items:(\d*):number (\d*)/) {
$items{$1} = $2;
$totalitems += $2;
}
}
print STDERR "Dumping memcache contents\n";
print STDERR " Number of buckets: " . scalar(keys(%items)) . "\n";
print STDERR " Number of items : $totalitems\n";
foreach my $bucket (sort(keys(%items))) {
print STDERR "Dumping bucket $bucket - " . $items{$bucket} . " total items\n";
print $sock "stats cachedump $bucket $items{$bucket}\r\n";
my %keyexp;
while (<$sock>) {
last if /^END/;
# return format looks like this
# ITEM foo [6 b; 1176415152 s]
if (/^ITEM (\S+) \[.* (\d+) s\]/) {
$keyexp{$1} = $2;
}
}
foreach my $k (keys(%keyexp)) {
print $sock "get $k\r\n";
my $response = <$sock>;
if ($response =~ /VALUE (\S+) (\d+) (\d+)/) {
my $flags = $2;
my $len = $3;
my $val;
read $sock, $val, $len;
print "add $k $flags $keyexp{$k} $len\r\n$val\r\n";
# get the END
$_ = <$sock>;
$_ = <$sock>;
}
}
}
exit;
}
if ($mode eq 'stats') {
my %items;
print $sock "stats\r\n";
while (<$sock>) {
last if /^END/;
chomp;
if (/^STAT\s+(\S*)\s+(.*)/) {
$items{$1} = $2;
}
}
printf ("#%-17s %5s %11s\n", $addr, "Field", "Value");
foreach my $name (sort(keys(%items))) {
printf ("%24s %12s\n", $name, $items{$name});
}
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";
my $max = 0;
while (<$sock>) {
last if /^END/;
if (/^STAT items:(\d+):(\w+) (\d+)/) {
$items{$1}{$2} = $3;
$max = $1;
}
}
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 Pages Count Full? Evicted Evict_Time OOM\n";
foreach my $n (1..$max) {
my $it = $items{$n};
next if (0 == $it->{total_pages});
my $size = $it->{chunk_size} < 1024 ?
"$it->{chunk_size}B" :
sprintf("%.1fK", $it->{chunk_size} / 1024.0);
my $full = $it->{free_chunks_end} == 0 ? "yes" : " no";
printf("%3d %8s %9ds %7d %7d %7s %8d %8d %4d\n",
$n, $size, $it->{age}, $it->{total_pages},
$it->{number}, $full, $it->{evicted},
$it->{evicted_time}, $it->{outofmemory});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment