[memcached] bradfitz, r288: merge all trunk changes since tag
1.1.12... (fwd)
Paul Querna
chip at corelands.com
Tue May 30 05:30:00 UTC 2006
Brad Fitzpatrick wrote:
> FYI...
Even if there aren't many memcached commits, is it possible to get those
mails to come to this list, or a separate memcached-commits list?
Thanks,
-Paul
> ---------- Forwarded message ----------
> Date: Tue, 30 May 2006 04:05:14 +0000 (UTC)
> From: commits at code.sixapart.com
> To: cvs-commits at livejournal.com
> Subject: [memcached] bradfitz,
> r288: merge all trunk changes since tag 1.1.12...
>
> merge all trunk changes since tag 1.1.12 into the facebook branch
>
>
>
> U branches/facebook/ChangeLog
> U branches/facebook/Makefile.am
> U branches/facebook/TODO
> U branches/facebook/configure.ac
> A branches/facebook/daemon.c
> A branches/facebook/doc/OSX.txt
> U branches/facebook/doc/memcached.1
> U branches/facebook/doc/protocol.txt
> U branches/facebook/memcached.c
> U branches/facebook/memcached.h
> U branches/facebook/slabs.c
> A branches/facebook/status.sh
>
>
> Modified: branches/facebook/ChangeLog
> ===================================================================
> --- branches/facebook/ChangeLog 2006-05-30 02:31:43 UTC (rev 287)
> +++ branches/facebook/ChangeLog 2006-05-30 04:05:13 UTC (rev 288)
> @@ -1,3 +1,30 @@
> +2006-04-30
> + * River Tarnell: autoconf work for Solaris 10. Brad:
> + merge and verify it works on Nexenta.
> +
> +2006-03-04
> + * avva: bucket/generation patch (old, but Brad's just finally
> + committing it)
> +
> +2006-01-01
> + * Brad Fitzpatrick <brad at danga.com>: allocate 1 slab per class
> + on start-up, to avoid confusing users with out-of-memory errors
> + later. this is 18 MB of allocation on start, unless max memory
> + allowed with -m is lower, in which case only the smaller slab
> + classes are allocated.
> +
> +2005-08-09
> + * Elizabeth Mattijsen <liz at dijkmat.nl>: needed a way to flush all
> + memcached backend servers, but not at exactly the same time (to
> + reduce load peaks), I've added some simple functionality to the
> + memcached protocol in the "flush_all" command that allows you to
> + specify a time at which the flush will actually occur (instead of
> + always at the moment the "flush_all" command is received).
> +
> +2005-05-25
> + * patch from Peter van Dijk <peter at nextgear.nl> to make
> + stderr unbuffered, for running under daemontools
> +
> 2005-04-04
> * patch from Don MacAskill <don at smugmug.com> 'flush_all' doesn't
> seem to work properly. Basically, if you try to add a key which
>
> Modified: branches/facebook/Makefile.am
> ===================================================================
> --- branches/facebook/Makefile.am 2006-05-30 02:31:43 UTC (rev 287)
> +++ branches/facebook/Makefile.am 2006-05-30 04:05:13 UTC (rev 288)
> @@ -1,6 +1,7 @@
> bin_PROGRAMS = memcached
>
> memcached_SOURCES = memcached.c slabs.c items.c memcached.h assoc.c
> +memcached_LDADD = @LIBOBJS@
>
> SUBDIRS = doc
> DIST_DIRS = scripts
>
> Modified: branches/facebook/TODO
> ===================================================================
> --- branches/facebook/TODO 2006-05-30 02:31:43 UTC (rev 287)
> +++ branches/facebook/TODO 2006-05-30 04:05:13 UTC (rev 288)
> @@ -6,3 +6,7 @@
>
> * calendar queue for early expirations of items, so they don't push
> out other objects with infinite expirations.
> +
> +* curr_items never decreases? mailing list report.
> +
> +* memcached to listen on more than one IP. mailing list request.
>
> Modified: branches/facebook/configure.ac
> ===================================================================
> --- branches/facebook/configure.ac 2006-05-30 02:31:43 UTC (rev 287)
> +++ branches/facebook/configure.ac 2006-05-30 04:05:13 UTC (rev 288)
> @@ -1,5 +1,5 @@
> AC_PREREQ(2.52)
> -AC_INIT(memcached, 1.1.11, brad at danga.com)
> +AC_INIT(memcached, 1.1.13-pre, brad at danga.com)
> AC_CANONICAL_SYSTEM
> AC_CONFIG_SRCDIR(memcached.c)
> AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
> @@ -19,6 +19,13 @@
> AC_CHECK_LIB(event, event_set, ,
> [AC_MSG_ERROR(libevent is required. You can get it from $LIBEVENT_URL)])
>
> +AC_SEARCH_LIBS(socket, socket)
> +AC_SEARCH_LIBS(gethostbyname, nsl)
> +AC_SEARCH_LIBS(mallinfo, malloc)
> +
> +AC_CHECK_FUNC(daemon,AC_DEFINE([HAVE_DAEMON],,[Define this if you have daemon()]),[AC_LIBOBJ(daemon)])
> +
> +
> AC_CHECK_HEADER(malloc.h, AC_DEFINE(HAVE_MALLOC_H,,[do we have malloc.h?]))
> AC_CHECK_MEMBER([struct mallinfo.arena], [
> AC_DEFINE(HAVE_STRUCT_MALLINFO,,[do we have stuct mallinfo?])
>
> Copied: branches/facebook/daemon.c (from rev 287, trunk/server/daemon.c)
>
> Copied: branches/facebook/doc/OSX.txt (from rev 287, trunk/server/doc/OSX.txt)
>
>
> Property changes on: branches/facebook/doc/OSX.txt
> ___________________________________________________________________
> Name: svn:keywords
> + Author Date Id Revision
> Name: svn:eol-style
> + native
>
> Modified: branches/facebook/doc/memcached.1
> ===================================================================
> --- branches/facebook/doc/memcached.1 2006-05-30 02:31:43 UTC (rev 287)
> +++ branches/facebook/doc/memcached.1 2006-05-30 04:05:13 UTC (rev 288)
> @@ -34,10 +34,6 @@
> .B \-m <num>
> Use <num> MB memory max to use for object storage; the default is 64 megabytes.
> .TP
> -.B \-M
> -Instead of throwing items from the cache when max memory is reached, throw an
> -error
> -.TP
> .B \-c <num>
> Use <num> max simultaneous connections; the default is 1024.
> .TP
>
> Modified: branches/facebook/doc/protocol.txt
> ===================================================================
> --- branches/facebook/doc/protocol.txt 2006-05-30 02:31:43 UTC (rev 287)
> +++ branches/facebook/doc/protocol.txt 2006-05-30 04:05:13 UTC (rev 288)
> @@ -360,16 +360,17 @@
> Other commands
> --------------
>
> -"flush_all" is a command with no arguments. It always succeeds,
> -and the server sends "OK\r\n" in response. Its effect is to immediately
> -invalidate all existing items: none of them will be returned in
> -response to a retrieval command (unless it's stored again under the
> -same key *after* flush_all has been executed). flush_all doesn't
> +"flush_all" is a command with an optional numeric argument. It always
> +succeeds, and the server sends "OK\r\n" in response. Its effect is to
> +invalidate all existing items immediately (by default) or after the
> +expiration specified. After invalidation none of the items will be returned
> +in response to a retrieval command (unless it's stored again under the
> +same key *after* flush_all has invalidated the items). flush_all doesn't
> actually free all the memory taken up by existing items; that will
> happen gradually as new items are stored. The most precise definition
> of what flush_all does is the following: it causes all items whose
> -update time is earlier than the time at which flush_all was executed
> -to be ignored for retrieval purposes.
> +update time is earlier than the time at which flush_all was set to be
> +executed to be ignored for retrieval purposes.
>
> "version" is a command with no arguments:
>
>
> Modified: branches/facebook/memcached.c
> ===================================================================
> --- branches/facebook/memcached.c 2006-05-30 02:31:43 UTC (rev 287)
> +++ branches/facebook/memcached.c 2006-05-30 04:05:13 UTC (rev 288)
> @@ -66,9 +66,11 @@
> #define TRANSMIT_SOFT_ERROR 2
> #define TRANSMIT_HARD_ERROR 3
>
> +int *buckets = 0; /* bucket->generation array for a managed instance */
> +
> +#define REALTIME_MAXDELTA 60*60*24*30
> rel_time_t realtime(time_t exptime) {
> /* no. of seconds in 30 days - largest possible delta exptime */
> - #define REALTIME_MAXDELTA 60*60*24*30
>
> if (exptime == 0) return 0; /* 0 means never expire */
>
> @@ -100,6 +102,7 @@
> settings.verbose = 0;
> settings.oldest_live = 0;
> settings.evict_to_free = 1; /* push old items out of cache when memory runs out */
> + settings.managed = 0;
> settings.factor = 1.25;
> settings.chunk_size = 48; /* space for a modest key and value */
> }
> @@ -193,6 +196,11 @@
> perror("malloc()");
> return 0;
> }
> +
> + c->rsize = c->wsize = DATA_BUFFER_SIZE;
> + c->rcurr = c->rbuf;
> + c->isize = 200;
> +
> stats.conn_structs++;
> }
>
> @@ -211,7 +219,7 @@
> c->rlbytes = 0;
> c->rbytes = c->wbytes = 0;
> c->wcurr = c->wbuf;
> - c->rcurr = c->rbuf;
> + c->ritem = 0;
> c->icurr = c->ilist;
> c->ileft = 0;
> c->iovused = 0;
> @@ -221,6 +229,8 @@
> c->write_and_go = conn_read;
> c->write_and_free = 0;
> c->item = 0;
> + c->bucket = -1;
> + c->gen = 0;
>
> event_set(&c->event, sfd, event_flags, event_handler, (void *)c);
> c->ev_flags = event_flags;
> @@ -706,7 +716,23 @@
> out_string(c, "CLIENT_ERROR bad command line format");
> return;
> }
> +
> + if (settings.managed) {
> + int bucket = c->bucket;
> + if (bucket == -1) {
> + out_string(c, "CLIENT_ERROR no BG data in managed mode");
> + return;
> + }
> + c->bucket = -1;
> + if (buckets[bucket] != c->gen) {
> + out_string(c, "ERROR_NOT_OWNER");
> + return;
> + }
> + }
> +
> + expire = realtime(expire);
> it = item_alloc(key, flags, realtime(expire), len+2);
> +
> if (it == 0) {
> out_string(c, "SERVER_ERROR out of memory");
> /* swallow the data line */
> @@ -717,7 +743,7 @@
>
> c->item_comm = comm;
> c->item = it;
> - c->rcurr = ITEM_data(it);
> + c->ritem = ITEM_data(it);
> c->rlbytes = it->nbytes;
> c->state = conn_nread;
> return;
> @@ -739,7 +765,20 @@
> out_string(c, "CLIENT_ERROR bad command line format");
> return;
> }
> -
> +
> + if (settings.managed) {
> + int bucket = c->bucket;
> + if (bucket == -1) {
> + out_string(c, "CLIENT_ERROR no BG data in managed mode");
> + return;
> + }
> + c->bucket = -1;
> + if (buckets[bucket] != c->gen) {
> + out_string(c, "ERROR_NOT_OWNER");
> + return;
> + }
> + }
> +
> it = assoc_find(key);
> if (it && (it->it_flags & ITEM_DELETED)) {
> it = 0;
> @@ -786,6 +825,10 @@
> return;
> }
>
> + if (strncmp(command, "bget ", 5) == 0) {
> + c->binary = 1;
> + goto get;
> + }
> if (strncmp(command, "get ", 4) == 0) {
>
> char *start = command + 4;
> @@ -794,7 +837,21 @@
> int i = 0;
> item *it;
> rel_time_t now = current_time;
> + get:
>
> + if (settings.managed) {
> + int bucket = c->bucket;
> + if (bucket == -1) {
> + out_string(c, "CLIENT_ERROR no BG data in managed mode");
> + return;
> + }
> + c->bucket = -1;
> + if (buckets[bucket] != c->gen) {
> + out_string(c, "ERROR_NOT_OWNER");
> + return;
> + }
> + }
> +
> while(sscanf(start, " %250s%n", key, &next) >= 1) {
> start+=next;
> stats.get_cmds++;
> @@ -802,8 +859,8 @@
> if (it && (it->it_flags & ITEM_DELETED)) {
> it = 0;
> }
> - if (settings.oldest_live && it &&
> - it->time <= settings.oldest_live) {
> + if (settings.oldest_live && settings.oldest_live <= now &&
> + it && it->time <= settings.oldest_live) {
> item_unlink(it);
> it = 0;
> }
> @@ -868,6 +925,19 @@
> int res;
> time_t exptime = 0;
>
> + if (settings.managed) {
> + int bucket = c->bucket;
> + if (bucket == -1) {
> + out_string(c, "CLIENT_ERROR no BG data in managed mode");
> + return;
> + }
> + c->bucket = -1;
> + if (buckets[bucket] != c->gen) {
> + out_string(c, "ERROR_NOT_OWNER");
> + return;
> + }
> + }
> +
> res = sscanf(command, "%*s %250s %ld", key, &exptime);
> it = assoc_find(key);
> if (!it) {
> @@ -904,14 +974,97 @@
> out_string(c, "DELETED");
> return;
> }
> -
> +
> + if (strncmp(command, "own ", 4) == 0) {
> + int bucket, gen;
> + char *start = command+4;
> + if (!settings.managed) {
> + out_string(c, "CLIENT_ERROR not a managed instance");
> + return;
> + }
> + if (sscanf(start, "%u:%u\r\n", &bucket,&gen) == 2) {
> + if ((bucket < 0) || (bucket >= MAX_BUCKETS)) {
> + out_string(c, "CLIENT_ERROR bucket number out of range");
> + return;
> + }
> + buckets[bucket] = gen;
> + out_string(c, "OWNED");
> + return;
> + } else {
> + out_string(c, "CLIENT_ERROR bad format");
> + return;
> + }
> + }
> +
> + if (strncmp(command, "disown ", 7) == 0) {
> + int bucket;
> + char *start = command+7;
> + if (!settings.managed) {
> + out_string(c, "CLIENT_ERROR not a managed instance");
> + return;
> + }
> + if (sscanf(start, "%u\r\n", &bucket) == 1) {
> + if ((bucket < 0) || (bucket >= MAX_BUCKETS)) {
> + out_string(c, "CLIENT_ERROR bucket number out of range");
> + return;
> + }
> + buckets[bucket] = 0;
> + out_string(c, "DISOWNED");
> + return;
> + } else {
> + out_string(c, "CLIENT_ERROR bad format");
> + return;
> + }
> + }
> +
> + if (strncmp(command, "bg ", 3) == 0) {
> + int bucket, gen;
> + char *start = command+3;
> + if (!settings.managed) {
> + out_string(c, "CLIENT_ERROR not a managed instance");
> + return;
> + }
> + if (sscanf(start, "%u:%u\r\n", &bucket,&gen) == 2) {
> + /* we never write anything back, even if input's wrong */
> + if ((bucket < 0) || (bucket >= MAX_BUCKETS) || (gen<=0)) {
> + /* do nothing, bad input */
> + } else {
> + c->bucket = bucket;
> + c->gen = gen;
> + }
> + c->state = conn_read;
> + /* normally conn_write uncorks the connection, but this
> + is the only time we accept a command w/o writing anything */
> + set_cork(c,0);
> + return;
> + } else {
> + out_string(c, "CLIENT_ERROR bad format");
> + return;
> + }
> + }
> +
> if (strncmp(command, "stats", 5) == 0) {
> process_stat(c, command);
> return;
> }
>
> - if (strcmp(command, "flush_all") == 0) {
> - settings.oldest_live = current_time;
> + if (strncmp(command, "flush_all", 9) == 0) {
> + time_t exptime = 0;
> + int res;
> +
> + if (strcmp(command, "flush_all") == 0) {
> + settings.oldest_live = current_time;
> + out_string(c, "OK");
> + return;
> + }
> +
> + res = sscanf(command, "%*s %ld", &exptime);
> + if (res != 1) {
> + out_string(c, "ERROR");
> + return;
> + }
> +
> + settings.oldest_live = realtime(exptime);
> out_string(c, "OK");
> return;
> }
> @@ -957,29 +1110,27 @@
> }
>
> /*
> - * if we have a complete line in the buffer, process it and move whatever
> - * remains in the buffer to its beginning.
> + * if we have a complete line in the buffer, process it.
> */
> int try_read_command(conn *c) {
> char *el, *cont;
>
> if (!c->rbytes)
> return 0;
> - el = memchr(c->rbuf, '\n', c->rbytes);
> + el = memchr(c->rcurr, '\n', c->rbytes);
> if (!el)
> return 0;
> cont = el + 1;
> - if (el - c->rbuf > 1 && *(el - 1) == '\r') {
> + if (el - c->rcurr > 1 && *(el - 1) == '\r') {
> el--;
> }
> *el = '\0';
>
> - process_command(c, c->rbuf);
> + process_command(c, c->rcurr);
>
> - if (cont - c->rbuf < c->rbytes) { /* more stuff in the buffer */
> - memmove(c->rbuf, cont, c->rbytes - (cont - c->rbuf));
> - }
> - c->rbytes -= (cont - c->rbuf);
> + c->rbytes -= (cont - c->rcurr);
> + c->rcurr = cont;
> +
> return 1;
> }
>
> @@ -1019,11 +1170,20 @@
> /*
> * read from network as much as we can, handle buffer overflow and connection
> * close.
> + * before reading, move the remaining incomplete fragment of a command
> + * (if any) to the beginning of the buffer.
> * return 0 if there's nothing to read on the first read.
> */
> int try_read_network(conn *c) {
> int gotdata = 0;
> int res;
> +
> + if (c->rcurr != c->rbuf) {
> + if (c->rbytes != 0) /* otherwise there's nothing to copy */
> + memmove(c->rbuf, c->rcurr, c->rbytes);
> + c->rcurr = c->rbuf;
> + }
> +
> while (1) {
> if (c->rbytes >= c->rsize) {
> char *new_rbuf = realloc(c->rbuf, c->rsize*2);
> @@ -1035,7 +1195,8 @@
> c->write_and_go = conn_closing;
> return 1;
> }
> - c->rbuf = new_rbuf; c->rsize *= 2;
> + c->rcurr = c->rbuf = new_rbuf;
> + c->rsize *= 2;
> }
> c->request_addr_size = sizeof(c->request_addr);
> res = read(c->sfd, c->rbuf + c->rbytes, c->rsize - c->rbytes);
> @@ -1189,7 +1350,7 @@
> break;
>
> case conn_nread:
> - /* we are reading rlbytes into rcurr; */
> + /* we are reading rlbytes into ritem; */
> if (c->rlbytes == 0) {
> complete_nread(c);
> break;
> @@ -1197,21 +1358,19 @@
> /* first check if we have leftovers in the conn_read buffer */
> if (c->rbytes > 0) {
> int tocopy = c->rbytes > c->rlbytes ? c->rlbytes : c->rbytes;
> - memcpy(c->rcurr, c->rbuf, tocopy);
> + memcpy(c->ritem, c->rcurr, tocopy);
> + c->ritem += tocopy;
> + c->rlbytes -= tocopy;
> c->rcurr += tocopy;
> - c->rlbytes -= tocopy;
> - if (c->rbytes > tocopy) {
> - memmove(c->rbuf, c->rbuf+tocopy, c->rbytes - tocopy);
> - }
> c->rbytes -= tocopy;
> break;
> }
>
> /* now try reading from the socket */
> - res = read(c->sfd, c->rcurr, c->rlbytes);
> + res = read(c->sfd, c->ritem, c->rlbytes);
> if (res > 0) {
> stats.bytes_read += res;
> - c->rcurr += res;
> + c->ritem += res;
> c->rlbytes -= res;
> break;
> }
> @@ -1246,9 +1405,7 @@
> if (c->rbytes > 0) {
> int tocopy = c->rbytes > c->sbytes ? c->sbytes : c->rbytes;
> c->sbytes -= tocopy;
> - if (c->rbytes > tocopy) {
> - memmove(c->rbuf, c->rbuf+tocopy, c->rbytes - tocopy);
> - }
> + c->rcurr += tocopy;
> c->rbytes -= tocopy;
> break;
> }
> @@ -1347,10 +1504,9 @@
> return;
> }
>
> -
> void event_handler(int fd, short which, void *arg) {
> conn *c;
> -
> +
> c = (conn *)arg;
> c->which = which;
>
> @@ -1554,6 +1710,7 @@
> printf("-vv very verbose (also print client commands/reponses)\n");
> printf("-h print this help and exit\n");
> printf("-i print memcached and libevent license\n");
> + printf("-b run a managed instanced (mnemonic: buckets)\n");
> printf("-P <file> save PID in <file>, only used with -d option\n");
> printf("-f <factor> chunk size growth factor, default 1.25\n");
> printf("-s <bytes> minimum space allocated for key+value+flags, default 48\n");
> @@ -1686,12 +1843,18 @@
> /* init settings */
> settings_init();
>
> + /* set stderr non-buffering (for running under, say, daemontools) */
> + setbuf(stderr, NULL);
> +
> /* process arguments */
> - while ((c = getopt(argc, argv, "p:U:m:Mc:khirvdl:u:P:f:s:")) != -1) {
> + while ((c = getopt(argc, argv, "bp:U:m:Mc:khirvdl:u:P:f:s:")) != -1) {
> switch (c) {
> case 'U':
> settings.udpport = atoi(optarg);
> break;
> + case 'b':
> + settings.managed = 1;
> + break;
> case 'p':
> settings.port = atoi(optarg);
> break;
> @@ -1717,7 +1880,7 @@
> settings.verbose++;
> break;
> case 'l':
> - if (!inet_aton(optarg, &addr)) {
> + if (!inet_pton(AF_INET, optarg, &addr)) {
> fprintf(stderr, "Illegal address: %s\n", optarg);
> return 1;
> } else {
> @@ -1863,6 +2026,16 @@
> conn_init();
> slabs_init(settings.maxbytes, settings.factor);
>
> + /* managed instance? alloc and zero a bucket array */
> + if (settings.managed) {
> + buckets = malloc(sizeof(int)*MAX_BUCKETS);
> + if (buckets == 0) {
> + fprintf(stderr, "failed to allocate the bucket array");
> + exit(1);
> + }
> + memset(buckets, 0, sizeof(int)*MAX_BUCKETS);
> + }
> +
> /* lock paged memory if needed */
> if (lock_memory) {
> #ifdef HAVE_MLOCKALL
>
> Modified: branches/facebook/memcached.h
> ===================================================================
> --- branches/facebook/memcached.h 2006-05-30 02:31:43 UTC (rev 287)
> +++ branches/facebook/memcached.h 2006-05-30 04:05:13 UTC (rev 288)
> @@ -34,6 +34,7 @@
> struct in_addr interface;
> int verbose;
> rel_time_t oldest_live; /* ignore existing items older than this */
> + int managed; /* if 1, a tracker manages virtual buckets */
> int evict_to_free;
> double factor; /* chunk size growth factor */
> int chunk_size;
> @@ -92,11 +93,12 @@
> int state;
> struct event event;
> short ev_flags;
> - short which; /* which events were just triggered */
> + short which; /* which events were just triggered */
>
> - char *rbuf;
> - int rsize;
> - int rbytes;
> + char *rbuf; /* buffer to read commands into */
> + char *rcurr; /* but if we parsed some already, this is where we stopped */
> + int rsize; /* total allocated size of rbuf */
> + int rbytes; /* how much data, starting from rcur, do we have unparsed */
>
> char *wbuf;
> char *wcurr;
> @@ -105,7 +107,7 @@
> int write_and_go; /* which state to go into after finishing current write */
> void *write_and_free; /* free this memory after finishing writing */
>
> - char *rcurr;
> + char *ritem; /* when we read in an item's value, it goes here */
> int rlbytes;
>
> /* data for the nread state */
> @@ -145,8 +147,16 @@
> socklen_t request_addr_size;
> unsigned char *hdrbuf; /* udp packet headers */
> int hdrsize; /* number of headers' worth of space is allocated */
> +
> + int binary; /* are we in binary mode */
> + int bucket; /* bucket number for the next command, if running as
> + a managed instance. -1 (_not_ 0) means invalid. */
> + int gen; /* generation requested for the bucket */
> } conn;
>
> +/* number of virtual buckets for a managed instance */
> +#define MAX_BUCKETS 32768
> +
> /* listening socket */
> extern int l_socket;
>
> @@ -179,6 +189,14 @@
> size equal to the previous slab's chunk size times this factor. */
> void slabs_init(size_t limit, double factor);
>
> +/* Preallocate as many slab pages as possible (called from slabs_init)
> + on start-up, so users don't get confused out-of-memory errors when
> + they do have free (in-slab) space, but no space to make new slabs.
> + if maxslabs is 18 (POWER_LARGEST - POWER_SMALLEST + 1), then all
> + slab types can be made. if max memory is less than 18 MB, only the
> + smaller ones will be made. */
> +void slabs_preallocate (unsigned int maxslabs);
> +
> /* Given object size, return id to use when allocating/freeing memory for object */
> /* 0 means error: can't store such a large object */
> unsigned int slabs_clsid(size_t size);
>
> Modified: branches/facebook/slabs.c
> ===================================================================
> --- branches/facebook/slabs.c 2006-05-30 02:31:43 UTC (rev 287)
> +++ branches/facebook/slabs.c 2006-05-30 04:05:13 UTC (rev 288)
> @@ -106,8 +106,30 @@
> power_largest = i;
> slabclass[power_largest].size = POWER_BLOCK;
> slabclass[power_largest].perslab = 1;
> +
> +#ifndef DONT_PREALLOC_SLABS
> + slabs_preallocate(limit / POWER_BLOCK);
> +#endif
> }
>
> +void slabs_preallocate (unsigned int maxslabs) {
> + int i;
> + unsigned int prealloc = 0;
> +
> + /* pre-allocate a 1MB slab in every size class so people don't get
> + confused by non-intuitive "SERVER_ERROR out of memory"
> + messages. this is the most common question on the mailing
> + list. if you really don't want this, you can rebuild without
> + these three lines. */
> +
> + for(i=POWER_SMALLEST; i<=POWER_LARGEST; i++) {
> + if (++prealloc > maxslabs)
> + return;
> + slabs_newslab(i);
> + }
> +
> +}
> +
> static int grow_slab_list (unsigned int id) {
> slabclass_t *p = &slabclass[id];
> if (p->slabs == p->list_size) {
>
> Added: branches/facebook/status.sh
> ===================================================================
> --- branches/facebook/status.sh 2006-05-30 02:31:43 UTC (rev 287)
> +++ branches/facebook/status.sh 2006-05-30 04:05:13 UTC (rev 288)
> @@ -0,0 +1,3 @@
> +#!/bin/sh
> +
> +svn diff http://code.sixapart.com/svn/memcached/trunk/server http://code.sixapart.com/svn/memcached/branches/facebook
>
>
> Property changes on: branches/facebook/status.sh
> ___________________________________________________________________
> Name: svn:executable
> + *
>
More information about the memcached
mailing list