I have also added the bytes in/out for data content per prefix.
cheers,
---
Jean-Charles
On Sat, May 30, 2009 at 18:26, Jean-Charles Redoutey
<[email protected]>wrote:
> 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..b8a85f8 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;
@@ -1219,7 +1220,7 @@ static void process_bin_get(conn *c) {
}
if (settings.detail_enabled) {
- stats_prefix_record_get(key, nkey, NULL != it);
+ stats_prefix_record_get(key, nkey, NULL != it, NULL != it ?
it->nbytes-2 : 0);
}
}
@@ -1581,7 +1582,7 @@ static void process_bin_update(conn *c) {
}
if (settings.detail_enabled) {
- stats_prefix_record_set(key, nkey);
+ stats_prefix_record_set(key, nkey, vlen);
}
it = item_alloc(key, nkey, req->message.body.flags,
@@ -1653,7 +1654,7 @@ static void process_bin_append_prepend(conn *c) {
}
if (settings.detail_enabled) {
- stats_prefix_record_set(key, nkey);
+ stats_prefix_record_set(key, nkey, vlen);
}
it = item_alloc(key, nkey, 0, 0, vlen+2);
@@ -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);
@@ -2252,7 +2254,7 @@ static inline void process_get_command(conn *c, token_t
*tokens, size_t ntokens,
stats_get_cmds++;
it = item_get(key, nkey);
if (settings.detail_enabled) {
- stats_prefix_record_get(key, nkey, NULL != it);
+ stats_prefix_record_get(key, nkey, NULL != it, NULL != it ?
it->nbytes : 0);
}
if (it) {
if (i >= c->isize) {
@@ -2435,7 +2437,7 @@ static void process_update_command(conn *c, token_t
*tokens, const size_t ntoken
}
if (settings.detail_enabled) {
- stats_prefix_record_set(key, nkey);
+ stats_prefix_record_set(key, nkey, vlen+2);
}
it = item_alloc(key, nkey, flags, realtime(exptime), vlen+2);
@@ -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..1e771fc 100644
--- a/stats.c
+++ b/stats.c
@@ -26,6 +26,8 @@ struct _prefix_stats {
uint64_t num_sets;
uint64_t num_deletes;
uint64_t num_hits;
+ uint64_t bytes_in;
+ uint64_t bytes_out;
PREFIX_STATS *next;
};
@@ -71,9 +73,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;
@@ -111,7 +118,7 @@ static PREFIX_STATS *stats_prefix_find(const char *key,
const size_t nkey) {
/*
* Records a "get" of a key.
*/
-void stats_prefix_record_get(const char *key, const size_t nkey, const bool
is_hit) {
+void stats_prefix_record_get(const char *key, const size_t nkey, const bool
is_hit, const size_t nbytes) {
PREFIX_STATS *pfs;
STATS_LOCK();
@@ -120,6 +127,7 @@ void stats_prefix_record_get(const char *key, const size_t
nkey, const bool is_h
pfs->num_gets++;
if (is_hit) {
pfs->num_hits++;
+ pfs->bytes_out += nbytes;
}
}
STATS_UNLOCK();
@@ -142,13 +150,14 @@ void stats_prefix_record_delete(const char *key, const
size_t nkey) {
/*
* Records a "set" of a key.
*/
-void stats_prefix_record_set(const char *key, const size_t nkey) {
+void stats_prefix_record_set(const char *key, const size_t nkey, const size_t
nbytes) {
PREFIX_STATS *pfs;
STATS_LOCK();
pfs = stats_prefix_find(key, nkey);
if (NULL != pfs) {
pfs->num_sets++;
+ pfs->bytes_in += nbytes;
}
STATS_UNLOCK();
}
@@ -158,7 +167,7 @@ void stats_prefix_record_set(const char *key, const size_t
nkey) {
*/
/*...@null@*/
char *stats_prefix_dump(int *length) {
- const char *format = "PREFIX %s get %llu hit %llu set %llu del %llu\r\n";
+ const char *format = "PREFIX %s get %llu hit %llu set %llu del %llu in
%llu out %llu\r\n";
PREFIX_STATS *pfs;
char *buf;
int i, pos;
@@ -173,7 +182,7 @@ char *stats_prefix_dump(int *length) {
STATS_LOCK();
size = strlen(format) + total_prefix_size +
num_prefixes * (strlen(format) - 2 /* %s */
- + 4 * (20 - 4)) /* %llu replaced by 20-digit num */
+ + 6 * (20 - 4)) /* %llu replaced by 20-digit num */
+ sizeof("END\r\n");
buf = malloc(size);
if (NULL == buf) {
@@ -187,7 +196,7 @@ char *stats_prefix_dump(int *length) {
for (pfs = prefix_stats[i]; NULL != pfs; pfs = pfs->next) {
written = snprintf(buf + pos, size-pos, format,
pfs->prefix, pfs->num_gets, pfs->num_hits,
- pfs->num_sets, pfs->num_deletes);
+ pfs->num_sets, pfs->num_deletes, pfs->bytes_in,
pfs->bytes_out);
pos += written;
total_written += written;
assert(total_written < size);
diff --git a/stats.h b/stats.h
index 4a27ae9..7106eeb 100644
--- a/stats.h
+++ b/stats.h
@@ -1,8 +1,8 @@
/* stats */
void stats_prefix_init(void);
void stats_prefix_clear(void);
-void stats_prefix_record_get(const char *key, const size_t nkey, const bool
is_hit);
+void stats_prefix_record_get(const char *key, const size_t nkey, const bool
is_hit, const size_t nbytes);
void stats_prefix_record_delete(const char *key, const size_t nkey);
-void stats_prefix_record_set(const char *key, const size_t nkey);
+void stats_prefix_record_set(const char *key, const size_t nkey, const size_t
nbytes);
/*...@null@*/
char *stats_prefix_dump(int *length);
diff --git a/t/stats-detail-fixed-size.t b/t/stats-detail-fixed-size.t
new file mode 100755
index 0000000..f77e1ca
--- /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 in 8 out 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 in 8 out 8\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 in 8 out 8\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 in 8 out 8\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 in 0 out 8\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 in 0 out 8\r\n",
"details after stats turned off");
+is(scalar <$sock>, "END\r\n", "end of details");
diff --git a/t/stats-detail.t b/t/stats-detail.t
old mode 100644
new mode 100755
index 4bb7249..3d9337c
--- a/t/stats-detail.t
+++ b/t/stats-detail.t
@@ -20,25 +20,25 @@ 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>, "PREFIX foo get 0 hit 0 set 1 del 0 in 8 out 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>, "PREFIX foo get 1 hit 1 set 1 del 0 in 8 out 8\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>, "PREFIX foo get 2 hit 1 set 1 del 0 in 8 out 8\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>, "PREFIX foo get 2 hit 1 set 1 del 1 in 8 out 8\r\n",
"details after delete");
is(scalar <$sock>, "END\r\n", "end of details");
print $sock "stats reset\r\n";
@@ -49,7 +49,7 @@ 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>, "PREFIX foo get 1 hit 1 set 0 del 0 in 0 out 8\r\n",
"details after clear and get");
is(scalar <$sock>, "END\r\n", "end of details");
print $sock "stats detail off\r\n";
@@ -59,5 +59,5 @@ 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>, "PREFIX foo get 1 hit 1 set 0 del 0 in 0 out 8\r\n",
"details after stats turned off");
is(scalar <$sock>, "END\r\n", "end of details");