diff --git a/doc/protocol.txt b/doc/protocol.txt index eb4f72126f..ca80fe124c 100644 --- a/doc/protocol.txt +++ b/doc/protocol.txt @@ -401,6 +401,8 @@ integers separated by a colon (treat this as a floating point number). | auth_errors | 64u | Number of failed authentications. | | evictions | 64u | Number of valid items removed from cache | | | | to free memory for new items | +| reclaimed | 64u | Number of times an entry was stored using | +| | | memory from an expired entry | | bytes_read | 64u | Total number of bytes read by this server | | | | from network | | bytes_written | 64u | Total number of bytes sent by this server | @@ -490,6 +492,8 @@ outofmemory Number of times the underlying slab class was unable to tailrepairs Number of times we self-healed a slab with a refcount leak. If this counter is increasing a lot, please report your situation to the developers. +reclaimed Number of times an entry was stored using memory from + an expired entry. Note this will only display information about slabs which exist, so an empty cache will return an empty set. diff --git a/items.c b/items.c index 665122f0b3..1e7ac57843 100644 --- a/items.c +++ b/items.c @@ -29,6 +29,7 @@ typedef struct { unsigned int evicted; unsigned int evicted_nonzero; rel_time_t evicted_time; + unsigned int reclaimed; unsigned int outofmemory; unsigned int tailrepairs; } itemstats_t; @@ -108,6 +109,10 @@ item *do_item_alloc(char *key, const size_t nkey, const int flags, const rel_tim /* I don't want to actually free the object, just steal * the item to avoid to grab the slab mutex twice ;-) */ + STATS_LOCK(); + stats.reclaimed++; + STATS_UNLOCK(); + itemstats[id].reclaimed++; it->refcount = 1; do_item_unlink(it); /* Initialize the item block: */ @@ -155,6 +160,11 @@ item *do_item_alloc(char *key, const size_t nkey, const int flags, const rel_tim STATS_LOCK(); stats.evictions++; STATS_UNLOCK(); + } else { + itemstats[id].reclaimed++; + STATS_LOCK(); + stats.reclaimed++; + STATS_UNLOCK(); } do_item_unlink(search); break; @@ -405,6 +415,8 @@ void do_item_stats(ADD_STAT add_stats, void *c) { "%u", itemstats[i].outofmemory); APPEND_NUM_FMT_STAT(fmt, i, "tailrepairs", "%u", itemstats[i].tailrepairs);; + APPEND_NUM_FMT_STAT(fmt, i, "reclaimed", + "%u", itemstats[i].reclaimed);; } } diff --git a/memcached.c b/memcached.c index 537fc86305..4ea00c53cc 100644 --- a/memcached.c +++ b/memcached.c @@ -149,7 +149,7 @@ static rel_time_t realtime(const time_t exptime) { static void stats_init(void) { stats.curr_items = stats.total_items = stats.curr_conns = stats.total_conns = stats.conn_structs = 0; - stats.get_cmds = stats.set_cmds = stats.get_hits = stats.get_misses = stats.evictions = 0; + stats.get_cmds = stats.set_cmds = stats.get_hits = stats.get_misses = stats.evictions = stats.reclaimed = 0; stats.curr_bytes = stats.listen_disabled_num = 0; stats.accepting_conns = true; /* assuming we start in this state. */ @@ -165,6 +165,7 @@ static void stats_reset(void) { STATS_LOCK(); stats.total_items = stats.total_conns = 0; stats.evictions = 0; + stats.reclaimed = 0; stats.listen_disabled_num = 0; stats_prefix_clear(); STATS_UNLOCK(); diff --git a/memcached.h b/memcached.h index fedb6f9752..4a7295bf69 100644 --- a/memcached.h +++ b/memcached.h @@ -240,6 +240,7 @@ struct stats { uint64_t get_hits; uint64_t get_misses; uint64_t evictions; + uint64_t reclaimed; time_t started; /* when the process was started */ bool accepting_conns; /* whether we are currently accepting */ uint64_t listen_disabled_num; diff --git a/slabs.c b/slabs.c index b769d527fc..a725a0be38 100644 --- a/slabs.c +++ b/slabs.c @@ -309,11 +309,15 @@ bool get_stats(const char *stat_type, int nkey, ADD_STAT add_stats, void *c) { if (add_stats != NULL) { if (!stat_type) { /* prepare general statistics for the engine */ + STATS_LOCK(); APPEND_STAT("bytes", "%llu", (unsigned long long)stats.curr_bytes); APPEND_STAT("curr_items", "%u", stats.curr_items); APPEND_STAT("total_items", "%u", stats.total_items); APPEND_STAT("evictions", "%llu", (unsigned long long)stats.evictions); + APPEND_STAT("reclaimed", "%llu", + (unsigned long long)stats.reclaimed); + STATS_UNLOCK(); } else if (nz_strcmp(nkey, stat_type, "items") == 0) { item_stats(add_stats, c); } else if (nz_strcmp(nkey, stat_type, "slabs") == 0) { diff --git a/t/binary.t b/t/binary.t index 90d6c51186..1108b8ee65 100755 --- a/t/binary.t +++ b/t/binary.t @@ -2,7 +2,7 @@ use strict; use warnings; -use Test::More tests => 3349; +use Test::More tests => 3361; use FindBin qw($Bin); use lib "$Bin/lib"; use MemcachedTest; diff --git a/t/stats.t b/t/stats.t index 646dae3b66..055bb06d2d 100755 --- a/t/stats.t +++ b/t/stats.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use strict; -use Test::More tests => 94; +use Test::More tests => 95; use FindBin qw($Bin); use lib "$Bin/lib"; use MemcachedTest; @@ -49,6 +49,7 @@ my $sock = $server->sock; ## STAT curr_items 0 ## STAT total_items 0 ## STAT evictions 0 +## STAT reclaimed 0 # note that auth stats are tested in auth specfic tests @@ -56,7 +57,7 @@ my $sock = $server->sock; my $stats = mem_stats($sock); # Test number of keys -is(scalar(keys(%$stats)), 37, "37 stats values"); +is(scalar(keys(%$stats)), 38, "38 stats values"); # Test initial state foreach my $key (qw(curr_items total_items bytes cmd_get cmd_set get_hits evictions get_misses @@ -185,6 +186,7 @@ is(0, $stats->{'cas_misses'}); is(0, $stats->{'cas_hits'}); is(0, $stats->{'cas_badval'}); is(0, $stats->{'evictions'}); +is(0, $stats->{'reclaimed'}); print $sock "flush_all\r\n"; is(scalar <$sock>, "OK\r\n", "flushed");