summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrond Norbye <Trond.Norbye@sun.com>2009-03-17 12:48:36 +0100
committerDustin Sallings <dustin@spy.net>2009-03-17 14:15:37 -0700
commitd3807d06f0693b0435545d35462de2829a61a7d1 (patch)
tree10ab54e91760bcda1709e0a039c803b71bddc9a7
parent4f5e1853192e473d67ef1b1bcce092a686e1dce1 (diff)
downloadmemcached-d3807d06f0693b0435545d35462de2829a61a7d1.tar.gz
Try to recycle allocated memory from expired items before allocating more.
see http://code.google.com/p/memcached/issues/detail?id=14
-rw-r--r--items.c34
-rw-r--r--t/issue_14.t34
2 files changed, 63 insertions, 5 deletions
diff --git a/items.c b/items.c
index f9ccb03..3594432 100644
--- a/items.c
+++ b/items.c
@@ -85,7 +85,7 @@ static size_t item_make_header(const uint8_t nkey, const int flags, const int nb
/*@null@*/
item *do_item_alloc(char *key, const size_t nkey, const int flags, const rel_time_t exptime, const int nbytes) {
uint8_t nsuffix;
- item *it;
+ item *it = NULL;
char suffix[40];
size_t ntotal = item_make_header(nkey + 1, flags, nbytes, suffix, &nsuffix);
if (settings.use_cas) {
@@ -96,10 +96,34 @@ item *do_item_alloc(char *key, const size_t nkey, const int flags, const rel_tim
if (id == 0)
return 0;
- it = slabs_alloc(ntotal, id);
- if (it == 0) {
- int tries = 50;
- item *search;
+ /* do a quick check if we have any expired items in the tail.. */
+ int tries = 50;
+ item *search;
+
+ for (search = tails[id];
+ tries > 0 && search != NULL;
+ tries--, search=search->prev) {
+ if (search->refcount == 0 &&
+ (search->exptime != 0 && search->exptime < current_time)) {
+ it = search;
+ /* I don't want to actually free the object, just steal
+ * the item to avoid to grab the slab mutex twice ;-)
+ */
+ it->refcount = 1;
+ do_item_unlink(it);
+ /* Initialize the item block: */
+ it->slabs_clsid = 0;
+ it->refcount = 0;
+ break;
+ }
+ }
+
+ if (it == NULL && (it = slabs_alloc(ntotal, id)) == NULL) {
+ /*
+ ** Could not find an expired item at the tail, and memory allocation
+ ** failed. Try to evict some items!
+ */
+ tries = 50;
/* If requested to not push old items out of cache when memory runs out,
* we're out of luck at this point...
diff --git a/t/issue_14.t b/t/issue_14.t
new file mode 100644
index 0000000..fb14b03
--- /dev/null
+++ b/t/issue_14.t
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+
+use strict;
+use Test::More tests => 21;
+use FindBin qw($Bin);
+use lib "$Bin/lib";
+use MemcachedTest;
+
+my $server = new_memcached();
+my $sock = $server->sock;
+my $value = "B"x66560;
+my $key = 0;
+
+for ($key = 0; $key < 10; $key++) {
+ print $sock "set key$key 0 2 66560\r\n$value\r\n";
+ is (scalar <$sock>, "STORED\r\n", "stored key$key");
+}
+
+#print $sock "stats slabs"
+my $first_stats = mem_stats($sock, "slabs");
+my $first_malloc = $first_stats->{total_malloced};
+
+sleep(4);
+
+for ($key = 10; $key < 20; $key++) {
+ print $sock "set key$key 0 2 66560\r\n$value\r\n";
+ is (scalar <$sock>, "STORED\r\n", "stored key$key");
+}
+
+my $second_stats = mem_stats($sock, "slabs");
+my $second_malloc = $second_stats->{total_malloced};
+
+
+is ($second_malloc, $first_malloc, "Memory grows..")