Add function slabs_reclaim() to reclaim free slabs positively
Henry Lu
henrylu21 at gmail.com
Wed Sep 6 03:22:14 UTC 2006
Skipped content of type multipart/alternative-------------- next part --------------
--- memcached-1.1.12/slabs.c 2004-04-27 05:26:48.000000000 +0800
+++ ./slabs.c 2006-09-06 11:28:23.000000000 +0800
@@ -3,6 +3,10 @@
* Slabs memory allocation, based on powers-of-2
*
* $Id: slabs.c,v 1.15 2003/09/05 22:37:36 bradfitz Exp $
+ *
+ * Modified by Henry Lu(henrylu21 at gmail.com)
+ * Add function slabs_reclaim() to relaim
+ * free slabs positively
*/
#include <sys/types.h>
@@ -19,18 +23,21 @@
#include <netinet/in.h>
#include <errno.h>
#include <event.h>
+#include <time.h>
#include <assert.h>
#include "memcached.h"
#define POWER_SMALLEST 3
#define POWER_LARGEST 20
-#define POWER_BLOCK 1048576
+#define POWER_BLOCK 1048576 /* 1M */
+#define MAX_FREE_SLABS 2048 /* Max free slabs 2048 * POWER_BLOCK */
/* powers-of-2 allocation structures */
typedef struct {
unsigned int size; /* sizes of items */
+
unsigned int perslab; /* how many items per slab */
void **slots; /* list of item ptrs */
@@ -52,6 +59,9 @@
static unsigned int mem_limit = 0;
static unsigned int mem_malloced = 0;
+static void *global_free_slab_list[MAX_FREE_SLABS];
+static int global_free_slabs = 0;
+
unsigned int slabs_clsid(unsigned int size) {
int res = 1;
@@ -70,6 +80,7 @@
void slabs_init(unsigned int limit) {
int i;
int size=1;
+ int len = POWER_BLOCK;
mem_limit = limit;
for(i=0; i<=POWER_LARGEST; i++, size*=2) {
@@ -83,12 +94,22 @@
slabclass[i].list_size = 0;
slabclass[i].killing = 0;
}
+
+ /* Prealloc global free slabs */
+ i = 0;
+ while(mem_limit && mem_malloced + len <= mem_limit) {
+ global_free_slab_list[global_free_slabs] = malloc(len);
+ memset(global_free_slab_list[global_free_slabs], 0, len);
+ mem_malloced += len;
+ ++global_free_slabs;
+ ++i;
+ }
}
static int grow_slab_list (unsigned int id) {
slabclass_t *p = &slabclass[id];
- if (p->slabs == p->list_size) {
- unsigned int new_size = p->list_size ? p->list_size * 2 : 16;
+ if (p->slabs == p->list_size) {
+ unsigned int new_size = p->list_size ? p->list_size * 2 : 16;
void *new_list = realloc(p->slab_list, new_size*sizeof(void*));
if (new_list == 0) return 0;
p->list_size = new_size;
@@ -103,20 +124,29 @@
int len = POWER_BLOCK;
char *ptr;
- if (mem_limit && mem_malloced + len > mem_limit)
- return 0;
-
if (! grow_slab_list(id)) return 0;
-
- ptr = malloc(len);
- if (ptr == 0) return 0;
+
+ if(global_free_slabs > 0) {
+ ptr = (char*)global_free_slab_list[--global_free_slabs];
+ assert(ptr);
+ }
+ else {
+ if (mem_limit && mem_malloced + len > mem_limit) {
+ return 0;
+ }
+
+ ptr = malloc(len);
+ if (ptr == 0) return 0;
+
+ mem_malloced += len;
+ }
memset(ptr, 0, len);
p->end_page_ptr = ptr;
p->end_page_free = num;
p->slab_list[p->slabs++] = ptr;
- mem_malloced += len;
+
return 1;
}
@@ -160,10 +190,13 @@
return 0; /* shouldn't ever get here */
}
+/* This function is cancelled */
void slabs_free(void *ptr, unsigned int size) {
unsigned char id = slabs_clsid(size);
slabclass_t *p;
+ assert(0);
+
assert(((item *)ptr)->slabs_clsid==0);
assert(id >= POWER_SMALLEST && id <= POWER_LARGEST);
if (id < POWER_SMALLEST || id > POWER_LARGEST)
@@ -288,3 +321,88 @@
return 1;
}
+
+/*
+ * Add by HenryLu(henrylu21 at gmail.com) 2006.03
+ *
+ * Try to reclaim one free slab for every
+ * clsid. slabs_reclaim() has been add to
+ * function delete_handle(), so it will be
+ * called every 5 seconds
+ */
+void slabs_reclaim() {
+ void *slab, *slab_end;
+ slabclass_t *p = NULL;
+ void *iter = NULL;
+ time_t now = time(0);
+ unsigned int count, fi = 0;
+ int free_counter = 0;
+ int clsid = POWER_SMALLEST;
+ item *free_item_list[POWER_BLOCK] = {0};
+
+ /* global_free_slab_list is full */
+ if(global_free_slabs >= MAX_FREE_SLABS) {
+ return;
+ }
+
+ for(; clsid <= POWER_LARGEST; ++clsid) {
+ p = &slabclass[clsid];
+
+ /* fail if no slab to give up in src */
+ if (p->slabs <= 1) {
+ continue;
+ }
+
+ count = p->slabs;
+ if(p->end_page_ptr) {
+ assert(p->end_page_free > 0);
+ --count;
+ }
+
+ assert(p->slots == 0);
+ assert(p->sl_total == 0);
+ assert(p->sl_curr == 0);
+
+ /* Release items expired as much as
+ * possiable
+ */
+ while(count-- > 0) {
+ slab = p->slab_list[0];
+ slab_end = slab + POWER_BLOCK;
+ free_counter = 0;
+
+ for (iter=slab; iter<slab_end; iter+=p->size) {
+ item *it = (item *) iter;
+ if (it->exptime < now) { /* item expired */
+ free_item_list[free_counter++] = it;
+ }
+ else if(it->it_flags & ITEM_SLABBED) { /* item already released */
+ ++free_counter;
+ }
+ }
+
+ /* We got a whole free slab */
+ if(free_counter == p->perslab) {
+ /* unlink free items in this slab */
+ for(fi = 0; fi < free_counter; ++fi) {
+ item *it = free_item_list[fi];
+ if(it)
+ {
+ it->it_flags &= ~ITEM_DELETED;
+ item_unlink(it);
+ }
+ }
+
+ /* link this slab to global free slab list */
+ memset(slab, 0, POWER_BLOCK);
+ global_free_slab_list[global_free_slabs++] = slab;
+
+ /* slab_list move upwards */
+ memmove(&(p->slab_list[0]), &(p->slab_list[1]), --p->slabs * sizeof(void*));
+ } else {
+ break;
+ }
+ }
+ }
+}
+
More information about the memcached
mailing list