root/trunk/server/scripts/memcached-tool @ 628

Revision 628, 4.7 kB (checked in by sgrimm, 2 years ago)

Allow memcached-tool dump mode to output keys containing punctuation

The regular expression that was being used to match a cache key was treating
colons as word breaks, so it couldn't read keys of the form "type:id".

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/perl
2#
3# memcached-tool:
4#   stats/management tool for memcached.
5#
6# Author:
7#   Brad Fitzpatrick <brad@danga.com>
8#
9# License:
10#   public domain.  I give up all rights to this
11#   tool.  modify and copy at will.
12#
13
14use strict;
15use IO::Socket::INET;
16
17my $host = shift;
18my $mode = shift || "display";
19my ($from, $to);
20
21if ($mode eq "display") {
22    undef $mode if @ARGV;
23} elsif ($mode eq "move") {
24    $from = shift;
25    $to = shift;
26    undef $mode if $from < 6 || $from > 17;
27    undef $mode if $to   < 6 || $to   > 17;
28    print STDERR "ERROR: parameters out of range\n\n" unless $mode;
29} elsif ($mode eq 'dump') {
30    ;
31} elsif ($mode eq 'stats') {
32    ;
33} else {
34    undef $mode;
35}
36
37undef $mode if @ARGV;
38
39die 
40"Usage: memcached-tool <host[:port]> [mode]\n
41       memcached-tool 10.0.0.5:11211 display    # shows slabs
42       memcached-tool 10.0.0.5:11211            # same.  (default is display)
43       memcached-tool 10.0.0.5:11211 stats      # shows general stats
44       memcached-tool 10.0.0.5:11211 move 7 9   # takes 1MB slab from class #7
45                                                # to class #9.
46
47You can only move slabs around once memory is totally allocated, and only
48once the target class is full.  (So you can't move from #6 to #9 and #7
49to #9 at the same itme, since you'd have to wait for #9 to fill from
50the first reassigned page)
51" unless $host && $mode;
52
53$host .= ":11211" unless $host =~ /:\d+/;
54
55my $sock = IO::Socket::INET->new(PeerAddr => $host,
56                                 Proto    => 'tcp');
57die "Couldn't connect to $host\n" unless $sock;
58
59
60if ($mode eq "move") {
61    my $tries = 0;
62    while (1) {
63        print $sock "slabs reassign $from $to\r\n";
64        my $res = <$sock>;
65        $res =~ s/\s+//;
66        if ($res eq "DONE") {
67            print "Success.\n";
68            exit 0;
69        } elsif ($res eq "CANT") {
70            print "Error: can't move from $from to $to.  Destination not yet full?  See usage docs.\n";
71            exit;
72        } elsif ($res eq "BUSY") {
73            if (++$tries == 3) {
74                print "Failed to move after 3 tries.  Try again later.\n";
75                exit;
76            }
77
78            print "Page busy, retrying...\n";
79            sleep 1;
80        }
81    }
82
83    exit;
84}
85
86if ($mode eq 'dump') {
87    my %items;
88    my $totalitems;
89
90    print $sock "stats items\r\n";
91
92    while (<$sock>) {
93        last if /^END/;
94        if (/^STAT items:(\d*):number (\d*)/) {
95            $items{$1} = $2;
96            $totalitems += $2;
97        }
98    }
99    print STDERR "Dumping memcache contents\n";
100    print STDERR "  Number of buckets: " . scalar(keys(%items)) . "\n";
101    print STDERR "  Number of items  : $totalitems\n";
102
103    foreach my $bucket (sort(keys(%items))) {
104        print STDERR "Dumping bucket $bucket - " . $items{$bucket} . " total items\n";
105        print $sock "stats cachedump $bucket $items{$bucket} 1\r\n";
106        my %keyexp;
107        while (<$sock>) {
108            last if /^END/;
109            # return format looks like this
110            # ITEM foo [6 b; 1176415152 s]
111            if (/^ITEM (\S+) \[.* (\d+) s\]/) {
112                $keyexp{$1} = $2;
113            }
114        }
115
116        foreach my $k (keys(%keyexp)) {
117            my $val;
118            print $sock "get $k\r\n";
119            my $response = <$sock>;
120            $response =~ /VALUE (\S+) (\d+) (\d+)/;
121            my $flags = $2;
122            my $len = $3;
123            read $sock, $val , $len;
124            # get the END
125            $_ = <$sock>;
126            $_ = <$sock>;
127            print "add $k $flags $keyexp{$k} $len\r\n$val\r\n";
128        }
129    }
130    exit;
131}
132
133if ($mode eq 'stats') {
134    my %items;
135
136    print $sock "stats\r\n";
137
138    while (<$sock>) {
139        last if /^END/;
140        chomp;
141        if (/^STAT\s+(\S*)\s+(.*)/) {
142            $items{$1} = $2;
143        }
144    }
145    printf ("#%-17s %5s %11s\n", $host, "Field", "Value");
146    foreach my $name (sort(keys(%items))) {
147      printf ("%24s %12s\n", $name, $items{$name});
148     
149    }
150    exit;
151}
152
153# display mode:
154
155my %items;  # class -> { number, age, chunk_size, chunks_per_page,
156            #            total_pages, total_chunks, used_chunks,
157            #            free_chunks, free_chunks_end }
158
159print $sock "stats items\r\n";
160while (<$sock>) {
161    last if /^END/;
162    if (/^STAT items:(\d+):(\w+) (\d+)/) {
163        $items{$1}{$2} = $3;
164    }
165}
166
167print $sock "stats slabs\r\n";
168while (<$sock>) {
169    last if /^END/;
170    if (/^STAT (\d+):(\w+) (\d+)/) {
171        $items{$1}{$2} = $3;
172    }
173}
174
175print "  #  Item_Size   Max_age  1MB_pages Count   Full?\n";
176foreach my $n (1..40) {
177    my $it = $items{$n};
178    next if (0 == $it->{total_pages});
179    my $size = $it->{chunk_size} < 1024 ? "$it->{chunk_size} B " : 
180        sprintf("%.1f kB", $it->{chunk_size} / 1024.0);
181    my $full = $it->{free_chunks_end} == 0 ? "yes" : " no";
182    printf "%3d   %8s %7d s %7d %7d %7s\n",
183                        $n, $size, $it->{age}, $it->{total_pages},
184                        $it->{number}, $full;
185}
186
Note: See TracBrowser for help on using the browser.