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");

Reply via email to