Hi evreyone,
I just found out the "stats detail" command, which is not far from a point I
raised some time ago about more detailed statistics :-)
However, in my use, the keys are using a fixed size prefix without delimiter
so the -D option is pretty useless :-(
So I have just added in what I hope a seamless way the support for fixed
sized prefix.
the patch is attached,
cheers,
Jean-Charles
diff --git a/memcached.c b/memcached.c
index 98578c4..3898153 100644
--- a/memcached.c
+++ b/memcached.c
@@ -189,6 +189,7 @@ static void settings_init(void) {
settings.chunk_size = 48; /* space for a modest key and value */
settings.num_threads = 4 + 1; /* N workers + 1 dispatcher */
settings.prefix_delimiter = ':';
+ settings.prefix_size = 0;
settings.detail_enabled = 0;
settings.reqs_per_event = 20;
settings.backlog = 1024;
@@ -2136,6 +2137,7 @@ static void process_stat_settings(ADD_STAT add_stats,
void *c) {
APPEND_STAT("chunk_size", "%d", settings.chunk_size);
APPEND_STAT("num_threads", "%d", settings.num_threads);
APPEND_STAT("stat_key_prefix", "%c", settings.prefix_delimiter);
+ APPEND_STAT("stat_key_prefix_size", "%d", settings.prefix_size);
APPEND_STAT("detail_enabled", "%s",
settings.detail_enabled ? "yes" : "no");
APPEND_STAT("reqs_per_event", "%d", settings.reqs_per_event);
@@ -3717,7 +3719,9 @@ static void usage(void) {
#endif
);
- printf("-D <char> Use <char> as the delimiter between key prefixes and
IDs.\n"
+ printf("-D <char>|[len] Use <char> as the delimiter between key prefixes
and IDs.\n"
+ " If the given value is surrounded by [], this is
interpreted\n"
+ " as a fixed size prefix length. \n"
" This is used for per-prefix stats reporting. The
default is\n"
" \":\" (colon). If this option is specified, stats
collection\n"
" is turned on automatically; if not, then it may be
turned on\n"
@@ -4024,7 +4028,17 @@ int main (int argc, char **argv) {
fprintf(stderr, "No delimiter specified\n");
return 1;
}
- settings.prefix_delimiter = optarg[0];
+ if(optarg[1] != 0 && (optarg[0] == '[' || optarg[0] == '_')) /*
looks like a prefix length, '_' is to allow bypassing perl issue with '['*/
+ {
+ settings.prefix_size = atoi(optarg+1);
+ if (settings.prefix_size == 0) {
+ fprintf(stderr, "Prefix size must be greater than 0\n");
+ return 1;
+ }
+ }
+ else {
+ settings.prefix_delimiter = optarg[0]; /* single character
delimiter */
+ }
settings.detail_enabled = 1;
break;
case 'L' :
diff --git a/memcached.h b/memcached.h
index 2764b52..4e3fa81 100644
--- a/memcached.h
+++ b/memcached.h
@@ -252,6 +252,7 @@ struct settings {
int chunk_size;
int num_threads; /* number of libevent threads to run */
char prefix_delimiter; /* character that marks a key prefix (for stats) */
+ int prefix_size; /* prefix length if fixed size prefix (used rather
than prefix_delimiter if not null)*/
int detail_enabled; /* nonzero if we're collecting detailed stats */
int reqs_per_event; /* Maximum number of io to process on each
io-event. */
diff --git a/stats.c b/stats.c
index 636107e..65cd7d7 100644
--- a/stats.c
+++ b/stats.c
@@ -71,9 +71,14 @@ static PREFIX_STATS *stats_prefix_find(const char *key,
const size_t nkey) {
assert(key != NULL);
- for (length = 0; key[length] != '\0' && length < nkey; length++)
- if (key[length] == settings.prefix_delimiter)
- break;
+ if( settings.prefix_size == 0) /* we are using prefix_delimiter */
+ {
+ for (length = 0; key[length] != '\0' && length < nkey; length++)
+ if (key[length] == settings.prefix_delimiter)
+ break;
+ } else { /* we are using fixed size prefix */
+ length = settings.prefix_size < nkey ? settings.prefix_size : nkey;
+ }
hashval = hash(key, length, 0) % PREFIX_HASH_SIZE;
diff --git a/t/stats-detail-fixed-size.t b/t/stats-detail-fixed-size.t
new file mode 100755
index 0000000..11e1144
--- /dev/null
+++ b/t/stats-detail-fixed-size.t
@@ -0,0 +1,63 @@
+#!/usr/bin/perl
+
+use strict;
+use Test::More tests => 24;
+use FindBin qw($Bin);
+use lib "$Bin/lib";
+use MemcachedTest;
+
+my $server = new_memcached('-D _3');
+my $sock = $server->sock;
+my $expire;
+
+print $sock "stats detail dump\r\n";
+is(scalar <$sock>, "END\r\n", "verified empty stats at start");
+
+print $sock "stats detail on\r\n";
+is(scalar <$sock>, "OK\r\n", "detail collection turned on");
+
+print $sock "set foo:123 0 0 6\r\nfooval\r\n";
+is(scalar <$sock>, "STORED\r\n", "stored foo");
+
+print $sock "stats detail dump\r\n";
+is(scalar <$sock>, "PREFIX foo get 0 hit 0 set 1 del 0\r\n", "details after
set");
+is(scalar <$sock>, "END\r\n", "end of details");
+
+mem_get_is($sock, "foo:123", "fooval");
+print $sock "stats detail dump\r\n";
+is(scalar <$sock>, "PREFIX foo get 1 hit 1 set 1 del 0\r\n", "details after
get with hit");
+is(scalar <$sock>, "END\r\n", "end of details");
+
+mem_get_is($sock, "foo:124", undef);
+
+print $sock "stats detail dump\r\n";
+is(scalar <$sock>, "PREFIX foo get 2 hit 1 set 1 del 0\r\n", "details after
get without hit");
+is(scalar <$sock>, "END\r\n", "end of details");
+
+print $sock "delete foo:125 0\r\n";
+is(scalar <$sock>, "NOT_FOUND\r\n", "sent delete command");
+
+print $sock "stats detail dump\r\n";
+is(scalar <$sock>, "PREFIX foo get 2 hit 1 set 1 del 1\r\n", "details after
delete");
+is(scalar <$sock>, "END\r\n", "end of details");
+
+print $sock "stats reset\r\n";
+is(scalar <$sock>, "RESET\r\n", "stats cleared");
+
+print $sock "stats detail dump\r\n";
+is(scalar <$sock>, "END\r\n", "empty stats after clear");
+
+mem_get_is($sock, "foo:123", "fooval");
+print $sock "stats detail dump\r\n";
+is(scalar <$sock>, "PREFIX foo get 1 hit 1 set 0 del 0\r\n", "details after
clear and get");
+is(scalar <$sock>, "END\r\n", "end of details");
+
+print $sock "stats detail off\r\n";
+is(scalar <$sock>, "OK\r\n", "detail collection turned off");
+
+mem_get_is($sock, "foo:124", undef);
+
+mem_get_is($sock, "foo:123", "fooval");
+print $sock "stats detail dump\r\n";
+is(scalar <$sock>, "PREFIX foo get 1 hit 1 set 0 del 0\r\n", "details after
stats turned off");
+is(scalar <$sock>, "END\r\n", "end of details");