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