[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