Adding a copy of memcached to the tree.
[awesomized/libmemcached] / memcached / scripts / memcached-tool
diff --git a/memcached/scripts/memcached-tool b/memcached/scripts/memcached-tool
new file mode 100755 (executable)
index 0000000..bae4efd
--- /dev/null
@@ -0,0 +1,169 @@
+#!/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});
+}
+