[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