From d3807d06f0693b0435545d35462de2829a61a7d1 Mon Sep 17 00:00:00 2001 From: Trond Norbye Date: Tue, 17 Mar 2009 12:48:36 +0100 Subject: Try to recycle allocated memory from expired items before allocating more. see http://code.google.com/p/memcached/issues/detail?id=14 --- items.c | 34 +++++++++++++++++++++++++++++----- t/issue_14.t | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 t/issue_14.t 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..") -- cgit v1.2.1