[patch] Configurable slab size and large object support

Jeffrey Horner jeff.horner at vanderbilt.edu
Wed Mar 15 23:03:48 UTC 2006


Hello all,

I've been playing around with the attached patch, and I'd like some 
feedback on it's usefulness. The -Z <num> flag adds the ability to 
change the POWER_LARGEST setting in slabs.c which allows for storing 
objects of just under 2^POWER_LARGEST. The -L flag allows objects larger 
than 2^POWER_LARGEST to be stored, although malloc() is used instead of 
the slab allocator.

The -Z flag may be useful to those users who see the "SERVER_ERROR out 
of memory" error and you know it's because your object sizes are just a 
little over 1 Mb. By setting the -Z argument to 21 like so:

memcached -Z 21

clients can now store and retrieve objects that are just under 2 Mb in 
size. However the full implication is that all slabs are 2Mb, and you're 
memory utilization will probably go down. Also, note that as you 
increase -Z by 1 then you're doubling the slab size, so -Z 29 means that 
ALL slabs are 512Mb, and -Z 30 means ALL slabs are 1Gb. Use at your own 
risk!!!

Also, these flags honor the memory limit you set with the -m flag, so 
don't set your slab size larger than your max memory limit (memcached 
won't let you store anything).

This is definitely not a performance enhancing patch. Clients getting or 
setting large objects can potentially starve other clients 
setting/getting smaller objects. However, I expect that memcached with 
this patch should perform on par with default settings when -Z is 20 and 
no -L flag.

On a related note, I'd like to run some more benchmarking utilities on 
this patch. Does anyone have some code they'd like to share?

Cheers,
-- 
Jeffrey Horner       Computer Systems Analyst         School of Medicine
615-322-8606         Department of Biostatistics   Vanderbilt University
-------------- next part --------------
diff -burN memcached-1.1.12/memcached.c memcached-1.1.12-patched/memcached.c
--- memcached-1.1.12/memcached.c	2006-03-14 23:32:57.000000000 -0600
+++ memcached-1.1.12-patched/memcached.c	2006-03-15 16:22:50.000000000 -0600
@@ -93,6 +93,11 @@
     settings.verbose = 0;
     settings.oldest_live = 0;
     settings.evict_to_free = 1;       /* push old items out of cache when memory runs out */
+    settings.power_largest = 20;
+    settings.power_block = 1048576;
+    settings.large_objects = 0; /* by default, max object size is 2^power_largest, setting
+                                 * this to 1 will enable caching of larger objects...
+                                 */
 }
 
 conn **freeconns;
@@ -1234,6 +1239,8 @@
     printf("-h            print this help and exit\n");
     printf("-i            print memcached and libevent license\n");
     printf("-P <file>     save PID in <file>, only used with -d option\n");
+    printf("-L            allow storage/retrieval of large objects\n");
+    printf("-Z <num>      sets slab size to 2^<num>, default is 20\n");
     return;
 }
 
@@ -1341,6 +1348,7 @@
     int c;
     conn *l_conn;
     struct in_addr addr;
+    int power_size = 0;
     int lock_memory = 0;
     int daemonize = 0;
     int maxcore = 0;
@@ -1354,7 +1362,7 @@
     settings_init();
 
     /* process arguments */
-    while ((c = getopt(argc, argv, "p:m:Mc:khirvdl:u:P:")) != -1) {
+    while ((c = getopt(argc, argv, "p:m:Mc:khirvdl:u:P:LZ:")) != -1) {
         switch (c) {
         case 'p':
             settings.port = atoi(optarg);
@@ -1400,6 +1408,26 @@
         case 'P':
             pid_file = optarg;
             break;
+        case 'L':
+            settings.large_objects = 1;
+            break;
+        case 'Z':
+            settings.power_largest = atoi(optarg);
+            if (settings.power_largest <=3){
+                fprintf(stderr, "POWER_LARGEST too small: %s\n", optarg);
+                return 1;
+            }
+            if (settings.power_largest >=32){
+                fprintf(stderr, "POWER_LARGEST too large: %s\n", optarg);
+                return 1;
+            }
+            if (settings.power_largest >=30){
+                fprintf(stderr, "POWER_LARGEST is %s: are you sure you know what you're doing?\n", optarg);
+            }
+            power_size = settings.power_largest;
+            settings.power_block = 1;
+            while(power_size--) settings.power_block <<= 1;
+            break;
         default:
             fprintf(stderr, "Illegal argument \"%c\"\n", c);
             return 1;
diff -burN memcached-1.1.12/memcached.h memcached-1.1.12-patched/memcached.h
--- memcached-1.1.12/memcached.h	2006-03-14 23:32:57.000000000 -0600
+++ memcached-1.1.12-patched/memcached.h	2006-03-15 14:39:23.000000000 -0600
@@ -31,11 +31,21 @@
     int verbose;
     time_t oldest_live;   /* ignore existing items older than this */
     int evict_to_free;
+    int power_largest;
+    int power_block;
+    int large_objects;
 };
 
 extern struct stats stats;
 extern struct settings settings;
 
+#define POWER_SMALLEST 3
+#define POWER_LARGEST  settings.power_largest
+#define POWER_BLOCK settings.power_block
+
+/* slab class id from large objects */
+#define LARGE_OBJECT_CLSID 1
+
 #define ITEM_LINKED 1
 #define ITEM_DELETED 2
 
diff -burN memcached-1.1.12/slabs.c memcached-1.1.12-patched/slabs.c
--- memcached-1.1.12/slabs.c	2006-03-14 23:32:57.000000000 -0600
+++ memcached-1.1.12-patched/slabs.c	2006-03-15 14:36:16.000000000 -0600
@@ -23,10 +23,7 @@
 
 #include "memcached.h"
 
-#define POWER_SMALLEST 3
-#define POWER_LARGEST  20
-#define POWER_BLOCK 1048576
-
+/* moved POWER #defines to memcached.h */
 /* powers-of-2 allocation structures */
 
 typedef struct {
@@ -48,7 +45,7 @@
     unsigned int killing;  /* index+1 of dying slab, or zero if none */
 } slabclass_t;
 
-static slabclass_t slabclass[POWER_LARGEST+1];
+static slabclass_t *slabclass;
 static unsigned int mem_limit = 0;
 static unsigned int mem_malloced = 0;
 
@@ -63,7 +60,8 @@
     if (res < POWER_SMALLEST) 
         res = POWER_SMALLEST;
     if (res > POWER_LARGEST)
-        res = 0;
+        res = (settings.large_objects)? LARGE_OBJECT_CLSID : 0;
+
     return res;
 }
 
@@ -71,6 +69,11 @@
     int i;
     int size=1;
 
+	if (!(slabclass = (slabclass_t *)malloc(sizeof (slabclass_t)*(settings.power_largest+1)))){
+            perror("malloc()");
+			exit(1);
+	}
+
     mem_limit = limit;
     for(i=0; i<=POWER_LARGEST; i++, size*=2) {
         slabclass[i].size = size;
@@ -124,6 +127,14 @@
     slabclass_t *p;
 
     unsigned char id = slabs_clsid(size);
+
+    if (settings.large_objects && id == LARGE_OBJECT_CLSID) {
+       if (mem_limit && mem_malloced + size > mem_limit)
+           return 0;
+       mem_malloced += size;
+       return malloc(size);
+    }
+
     if (id < POWER_SMALLEST || id > POWER_LARGEST)
         return 0;
 
@@ -165,6 +176,13 @@
     slabclass_t *p;
 
     assert(((item *)ptr)->slabs_clsid==0);
+
+    if (settings.large_objects && id == LARGE_OBJECT_CLSID) {
+       mem_malloced -= size;
+       free(ptr);
+       return;
+    }
+
     assert(id >= POWER_SMALLEST && id <= POWER_LARGEST);
     if (id < POWER_SMALLEST || id > POWER_LARGEST)
         return;


More information about the memcached mailing list