Blame scripts/memcached-tool

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