summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDustin Sallings <dustin@spy.net>2009-03-07 14:39:59 -0800
committerDustin Sallings <dustin@spy.net>2009-03-07 14:39:59 -0800
commit15e646258e7d5e7596ebccb351365c66b2ab88a4 (patch)
treea44d5db07ab5d1dbd676b350d1b2f083481b0877
parent3e0307821d0bb937ef76258a2cc9a8abbde717cb (diff)
downloadmemcached-15e646258e7d5e7596ebccb351365c66b2ab88a4.tar.gz
Added CAS stats.
CAS stats break down into three different types: * CAS misses (non-existent key) * CAS hits (key + CAS ID match) * CAS badval (key + CAS ID mismatch) hits and bad-val are slab-specific stats. Specifically, they are both based on the slab ID of the original item (the one being replaced).
-rw-r--r--memcached.c31
-rw-r--r--memcached.h3
-rw-r--r--slabs.c14
-rwxr-xr-xt/stats.t39
-rw-r--r--thread.c10
5 files changed, 95 insertions, 2 deletions
diff --git a/memcached.c b/memcached.c
index 18d2078..f209446 100644
--- a/memcached.c
+++ b/memcached.c
@@ -1868,12 +1868,25 @@ enum store_item_type do_store_item(item *it, int comm, conn *c) {
if(old_it == NULL) {
// LRU expired
stored = NOT_FOUND;
+ pthread_mutex_lock(&c->thread->stats.mutex);
+ c->thread->stats.cas_misses++;
+ pthread_mutex_unlock(&c->thread->stats.mutex);
}
else if (ITEM_get_cas(it) == ITEM_get_cas(old_it)) {
// cas validates
+ // it and old_it may belong to different classes.
+ // I'm updating the stats for the one that's getting pushed out
+ pthread_mutex_lock(&c->thread->stats.mutex);
+ c->thread->stats.slab_stats[old_it->slabs_clsid].cas_hits++;
+ pthread_mutex_unlock(&c->thread->stats.mutex);
+
item_replace(old_it, it);
stored = STORED;
} else {
+ pthread_mutex_lock(&c->thread->stats.mutex);
+ c->thread->stats.slab_stats[old_it->slabs_clsid].cas_badval++;
+ pthread_mutex_unlock(&c->thread->stats.mutex);
+
if(settings.verbose > 1) {
fprintf(stderr, "CAS: failure: expected %llu, got %llu\n",
(unsigned long long)ITEM_get_cas(old_it),
@@ -2211,6 +2224,24 @@ static char *server_stats(uint32_t (*add_stats)(char *buf, const char *key,
pos += nbytes;
*buflen += nbytes;
+ vlen = sprintf(val, "%llu", (unsigned long long)thread_stats.cas_misses);
+ nbytes = add_stats(pos, "cas_misses", strlen("cas_misses"), val, vlen,
+ (void *)c);
+ pos += nbytes;
+ *buflen += nbytes;
+
+ vlen = sprintf(val, "%llu", (unsigned long long)slab_stats.cas_hits);
+ nbytes = add_stats(pos, "cas_hits", strlen("cas_hits"), val, vlen,
+ (void *)c);
+ pos += nbytes;
+ *buflen += nbytes;
+
+ vlen = sprintf(val, "%llu", (unsigned long long)slab_stats.cas_badval);
+ nbytes = add_stats(pos, "cas_badval", strlen("cas_badval"), val, vlen,
+ (void *)c);
+ pos += nbytes;
+ *buflen += nbytes;
+
vlen = sprintf(val, "%llu", (unsigned long long)thread_stats.bytes_read);
nbytes = add_stats(pos, "bytes_read", strlen("bytes_read"), val, vlen,
(void *)c);
diff --git a/memcached.h b/memcached.h
index 8ccf980..59039ff 100644
--- a/memcached.h
+++ b/memcached.h
@@ -71,6 +71,8 @@ struct slab_stats {
uint64_t set_cmds;
uint64_t get_hits;
uint64_t delete_hits;
+ uint64_t cas_hits;
+ uint64_t cas_badval;
uint64_t incr_hits;
uint64_t decr_hits;
};
@@ -82,6 +84,7 @@ struct thread_stats {
uint64_t delete_misses;
uint64_t incr_misses;
uint64_t decr_misses;
+ uint64_t cas_misses;
uint64_t bytes_read;
uint64_t bytes_written;
struct slab_stats slab_stats[MAX_NUMBER_OF_SLAB_CLASSES];
diff --git a/slabs.c b/slabs.c
index 2c3bde2..b28fc68 100644
--- a/slabs.c
+++ b/slabs.c
@@ -476,6 +476,20 @@ static char *do_slabs_stats(uint32_t (*add_stats)(char *buf, const char *key,
linelen += nbytes;
bufcurr += nbytes;
+ sprintf(key, "%d:cas_hits", i);
+ sprintf(val, "%llu",
+ (unsigned long long)thread_stats.slab_stats[i].cas_hits);
+ nbytes = add_stats(bufcurr, key, strlen(key), val, strlen(val), c);
+ linelen += nbytes;
+ bufcurr += nbytes;
+
+ sprintf(key, "%d:cas_badval", i);
+ sprintf(val, "%llu",
+ (unsigned long long)thread_stats.slab_stats[i].cas_badval);
+ nbytes = add_stats(bufcurr, key, strlen(key), val, strlen(val), c);
+ linelen += nbytes;
+ bufcurr += nbytes;
+
total++;
}
}
diff --git a/t/stats.t b/t/stats.t
index cdbfa1a..e5d3af8 100755
--- a/t/stats.t
+++ b/t/stats.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl
use strict;
-use Test::More tests => 51;
+use Test::More tests => 70;
use FindBin qw($Bin);
use lib "$Bin/lib";
use MemcachedTest;
@@ -35,6 +35,9 @@ my $sock = $server->sock;
## STAT incr_hits 2
## STAT decr_misses 1
## STAT decr_hits 1
+## STAT cas_misses 0
+## STAT cas_hits 0
+## STAT cas_badval 0
## STAT evictions 0
## STAT bytes_read 7
## STAT bytes_written 0
@@ -43,7 +46,7 @@ my $sock = $server->sock;
my $stats = mem_stats($sock);
# Test number of keys
-is(scalar(keys(%$stats)), 28, "28 stats values");
+is(scalar(keys(%$stats)), 31, "31 stats values");
# Test initial state
foreach my $key (qw(curr_items total_items bytes cmd_get cmd_set get_hits evictions get_misses bytes_written delete_hits delete_misses incr_hits incr_misses decr_hits decr_misses)) {
@@ -110,4 +113,36 @@ print $sock "decr n 1\r\n";
is(scalar <$sock>, "2\r\n", "decr works");
check_incr_stats(1, 1, 1, 1);
+# cas stats
+sub check_cas_stats {
+ my ($ch, $cm, $cb) = @_;
+ my $stats = mem_stats($sock);
+
+ is($stats->{cas_hits}, $ch);
+ is($stats->{cas_misses}, $cm);
+ is($stats->{cas_badval}, $cb);
+}
+
+check_cas_stats(0, 0, 0);
+
+print $sock "cas c 0 0 1 99999999\r\nz\r\n";
+is(scalar <$sock>, "NOT_FOUND\r\n", "missed cas");
+check_cas_stats(0, 1, 0);
+
+print $sock "set c 0 0 1\r\nx\r\n";
+is(scalar <$sock>, "STORED\r\n", "stored c");
+my ($id, $v) = mem_gets($sock, 'c');
+is('x', $v, 'got the expected value');
+
+print $sock "cas c 0 0 1 99999999\r\nz\r\n";
+is(scalar <$sock>, "EXISTS\r\n", "missed cas");
+check_cas_stats(0, 1, 1);
+my ($newid, $v) = mem_gets($sock, 'c');
+is('x', $v, 'got the expected value');
+
+print $sock "cas c 0 0 1 $id\r\nz\r\n";
+is(scalar <$sock>, "STORED\r\n", "good cas");
+check_cas_stats(1, 1, 1);
+my ($newid, $v) = mem_gets($sock, 'c');
+is('z', $v, 'got the expected value');
diff --git a/thread.c b/thread.c
index 8ff5a59..611a9ed 100644
--- a/thread.c
+++ b/thread.c
@@ -562,6 +562,7 @@ void threadlocal_stats_aggregate(struct thread_stats *stats) {
stats->delete_misses = 0;
stats->incr_misses = 0;
stats->decr_misses = 0;
+ stats->cas_misses = 0;
stats->bytes_written = 0;
stats->bytes_read = 0;
@@ -576,6 +577,7 @@ void threadlocal_stats_aggregate(struct thread_stats *stats) {
stats->delete_misses += threads[ii].stats.delete_misses;
stats->decr_misses += threads[ii].stats.decr_misses;
stats->incr_misses += threads[ii].stats.incr_misses;
+ stats->cas_misses += threads[ii].stats.cas_misses;
stats->bytes_read += threads[ii].stats.bytes_read;
stats->bytes_written += threads[ii].stats.bytes_written;
@@ -590,6 +592,10 @@ void threadlocal_stats_aggregate(struct thread_stats *stats) {
threads[ii].stats.slab_stats[sid].decr_hits;
stats->slab_stats[sid].incr_hits +=
threads[ii].stats.slab_stats[sid].incr_hits;
+ stats->slab_stats[sid].cas_hits +=
+ threads[ii].stats.slab_stats[sid].cas_hits;
+ stats->slab_stats[sid].cas_badval +=
+ threads[ii].stats.slab_stats[sid].cas_badval;
}
pthread_mutex_unlock(&threads[ii].stats.mutex);
@@ -604,6 +610,8 @@ void slab_stats_aggregate(struct thread_stats *stats, struct slab_stats *out) {
out->delete_hits = 0;
out->incr_hits = 0;
out->decr_hits = 0;
+ out->cas_hits = 0;
+ out->cas_badval = 0;
for (sid = 0; sid < MAX_NUMBER_OF_SLAB_CLASSES; sid++) {
out->set_cmds += stats->slab_stats[sid].set_cmds;
@@ -611,6 +619,8 @@ void slab_stats_aggregate(struct thread_stats *stats, struct slab_stats *out) {
out->delete_hits += stats->slab_stats[sid].delete_hits;
out->decr_hits += stats->slab_stats[sid].decr_hits;
out->incr_hits += stats->slab_stats[sid].incr_hits;
+ out->cas_hits += stats->slab_stats[sid].cas_hits;
+ out->cas_badval += stats->slab_stats[sid].cas_badval;
}
}