[memcached] bradfitz, r288: merge all trunk changes since tag
1.1.12... (fwd)
Brad Fitzpatrick
brad at danga.com
Tue May 30 04:05:56 UTC 2006
FYI...
---------- 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