Index: /branches/binary/server/slabs.c
===================================================================
--- /branches/binary/server/slabs.c (revision 725)
+++ /branches/binary/server/slabs.c (revision 745)
@@ -219,8 +219,7 @@
 
 /*@null@*/
-void *do_slabs_alloc(const size_t size) {
+void *do_slabs_alloc(const size_t size, unsigned int id) {
     slabclass_t *p;
 
-    unsigned int id = slabs_clsid(size);
     if (id < POWER_SMALLEST || id > power_largest)
         return NULL;
@@ -259,6 +258,5 @@
 }
 
-void do_slabs_free(void *ptr, const size_t size) {
-    unsigned char id = slabs_clsid(size);
+void do_slabs_free(void *ptr, const size_t size, unsigned int id) {
     slabclass_t *p;
 
Index: /branches/binary/server/memcached.c
===================================================================
--- /branches/binary/server/memcached.c (revision 735)
+++ /branches/binary/server/memcached.c (revision 745)
@@ -1613,5 +1613,5 @@
         c->write_and_go = get_init_state(c);
     } else {
-        out_string(c, "SERVER_ERROR out of memory");
+        out_string(c, "SERVER_ERROR out of memory writing stats");
     }
 }
@@ -1750,5 +1750,5 @@
 
         if ((wbuf = (char *)malloc(wsize)) == NULL) {
-            out_string(c, "SERVER_ERROR out of memory");
+            out_string(c, "SERVER_ERROR out of memory writing stats maps");
             return;
         }
@@ -1917,5 +1917,5 @@
                     stats.get_misses += stats_get_misses;
                     STATS_UNLOCK();
-                    out_string(c, "SERVER_ERROR out of memory");
+                    out_string(c, "SERVER_ERROR out of memory making CAS suffix");
                     return;
                   }
@@ -1986,5 +1986,5 @@
     if (key_token->value != NULL || add_iov(c, "END\r\n", 5) != 0
         || (IS_UDP(c->protocol) && build_udp_headers(c) != 0)) {
-        out_string(c, "SERVER_ERROR out of memory");
+        out_string(c, "SERVER_ERROR out of memory writing get response");
     }
     else {
@@ -2061,5 +2061,5 @@
             out_string(c, "SERVER_ERROR object too large for cache");
         else
-            out_string(c, "SERVER_ERROR out of memory");
+            out_string(c, "SERVER_ERROR out of memory storing object");
         /* swallow the data line */
         c->write_and_go = conn_swallow;
@@ -2164,5 +2164,5 @@
         new_it = do_item_alloc(ITEM_key(it), it->nkey, atoi(ITEM_suffix(it) + 1), it->exptime, res + 2 );
         if (new_it == 0) {
-            return "SERVER_ERROR out of memory";
+            return "SERVER_ERROR out of memory in incr/decr";
         }
         memcpy(ITEM_data(new_it), buf, res);
@@ -2255,5 +2255,5 @@
              */
             item_remove(it);    /* release reference */
-            return "SERVER_ERROR out of memory";
+            return "SERVER_ERROR out of memory expanding delete queue";
         }
     }
@@ -2300,5 +2300,5 @@
     c->iovused = 0;
     if (add_msghdr(c) != 0) {
-        out_string(c, "SERVER_ERROR out of memory");
+        out_string(c, "SERVER_ERROR out of memory preparing response");
         return;
     }
@@ -2580,5 +2580,5 @@
                     fprintf(stderr, "Couldn't realloc input buffer\n");
                 c->rbytes = 0; /* ignore what we read */
-                out_string(c, "SERVER_ERROR out of memory");
+                out_string(c, "SERVER_ERROR out of memory reading request");
                 c->write_and_go = conn_closing;
                 return 1;
Index: /branches/binary/server/ChangeLog
===================================================================
--- /branches/binary/server/ChangeLog (revision 722)
+++ /branches/binary/server/ChangeLog (revision 745)
@@ -1,2 +1,16 @@
+2008-03-02 [Version 1.2.5-rc1 released]
+
+       * Add per-item-class tracking of evictions and OOM errors (dormando)
+
+       * Optimize item_alloc() a little (dormando)
+
+       * Give 'SERVER_ERROR out of memory' errors more context (dormando)
+
+       * Enable usage of large memory pages under solaris
+         (Trond.Norbye@Sun.COM)
+
+       * Enable UDP by default, clean up server socket code
+         (brian@tangent.org)
+
        * 'noreply' support (Tomash Brechko)
 
Index: /branches/binary/server/thread.c
===================================================================
--- /branches/binary/server/thread.c (revision 672)
+++ /branches/binary/server/thread.c (revision 745)
@@ -572,16 +572,16 @@
 /******************************* SLAB ALLOCATOR ******************************/
 
-void *mt_slabs_alloc(size_t size) {
+void *mt_slabs_alloc(size_t size, unsigned int id) {
     void *ret;
 
     pthread_mutex_lock(&slabs_lock);
-    ret = do_slabs_alloc(size);
+    ret = do_slabs_alloc(size, id);
     pthread_mutex_unlock(&slabs_lock);
     return ret;
 }
 
-void mt_slabs_free(void *ptr, size_t size) {
+void mt_slabs_free(void *ptr, size_t size, unsigned int id) {
     pthread_mutex_lock(&slabs_lock);
-    do_slabs_free(ptr, size);
+    do_slabs_free(ptr, size, id);
     pthread_mutex_unlock(&slabs_lock);
 }
Index: /branches/binary/server/slabs.h
===================================================================
--- /branches/binary/server/slabs.h (revision 725)
+++ /branches/binary/server/slabs.h (revision 745)
@@ -18,8 +18,8 @@
 
 /** Allocate object of given length. 0 on error */ /*@null@*/
-void *do_slabs_alloc(const size_t size);
+void *do_slabs_alloc(const size_t size, unsigned int id);
 
 /** Free previously allocated object */
-void do_slabs_free(void *ptr, size_t size);
+void do_slabs_free(void *ptr, size_t size, unsigned int id);
 
 /** Fill buffer with stats */ /*@null@*/
Index: /branches/binary/server/memcached.h
===================================================================
--- /branches/binary/server/memcached.h (revision 733)
+++ /branches/binary/server/memcached.h (revision 745)
@@ -364,6 +364,6 @@
 void  mt_item_update(item *it);
 void  mt_run_deferred_deletes(void);
-void *mt_slabs_alloc(size_t size);
-void  mt_slabs_free(void *ptr, size_t size);
+void *mt_slabs_alloc(size_t size, unsigned int id);
+void  mt_slabs_free(void *ptr, size_t size, unsigned int id);
 int   mt_slabs_reassign(unsigned char srcid, unsigned char dstid);
 char *mt_slabs_stats(int *buflen);
@@ -393,6 +393,6 @@
 # define item_unlink(x)              mt_item_unlink(x)
 # define run_deferred_deletes()      mt_run_deferred_deletes()
-# define slabs_alloc(x)              mt_slabs_alloc(x)
-# define slabs_free(x,y)             mt_slabs_free(x,y)
+# define slabs_alloc(x,y)            mt_slabs_alloc(x,y)
+# define slabs_free(x,y,z)           mt_slabs_free(x,y,z)
 # define slabs_reassign(x,y)         mt_slabs_reassign(x,y)
 # define slabs_stats(x)              mt_slabs_stats(x)
@@ -426,6 +426,6 @@
 # define item_update(x)              do_item_update(x)
 # define run_deferred_deletes()      do_run_deferred_deletes()
-# define slabs_alloc(x)              do_slabs_alloc(x)
-# define slabs_free(x,y)             do_slabs_free(x,y)
+# define slabs_alloc(x,y)            do_slabs_alloc(x,y)
+# define slabs_free(x,y,z)           do_slabs_free(x,y,z)
 # define slabs_reassign(x,y)         do_slabs_reassign(x,y)
 # define slabs_stats(x)              do_slabs_stats(x)
Index: /branches/binary/server/memcached.spec
===================================================================
--- /branches/binary/server/memcached.spec (revision 648)
+++ /branches/binary/server/memcached.spec (revision 745)
@@ -1,4 +1,4 @@
 Name:           memcached
-Version:        1.2.4
+Version:        1.2.5
 Release:        1%{?dist}
 Summary:        High Performance, Distributed Memory Object Cache
Index: /branches/binary/server/items.c
===================================================================
--- /branches/binary/server/items.c (revision 642)
+++ /branches/binary/server/items.c (revision 745)
@@ -28,10 +28,17 @@
 
 #define LARGEST_ID 255
+typedef struct {
+    unsigned int evicted;
+    unsigned int outofmemory;
+} itemstats_t;
+
 static item *heads[LARGEST_ID];
 static item *tails[LARGEST_ID];
+static itemstats_t itemstats[LARGEST_ID];
 static unsigned int sizes[LARGEST_ID];
 
 void item_init(void) {
     int i;
+    memset(itemstats, 0, sizeof(itemstats_t) * LARGEST_ID);
     for(i = 0; i < LARGEST_ID; i++) {
         heads[i] = NULL;
@@ -89,5 +96,5 @@
         return 0;
 
-    it = slabs_alloc(ntotal);
+    it = slabs_alloc(ntotal, id);
     if (it == 0) {
         int tries = 50;
@@ -98,5 +105,8 @@
          */
 
-        if (settings.evict_to_free == 0) return NULL;
+        if (settings.evict_to_free == 0) {
+            itemstats[id].outofmemory++;
+            return NULL;
+        }
 
         /*
@@ -107,13 +117,16 @@
          */
 
-        if (id > LARGEST_ID) return NULL;
-        if (tails[id] == 0) return NULL;
+        if (tails[id] == 0) {
+            itemstats[id].outofmemory++;
+            return NULL;
+        }
 
         for (search = tails[id]; tries > 0 && search != NULL; tries--, search=search->prev) {
             if (search->refcount == 0) {
-               if (search->exptime == 0 || search->exptime > current_time) {
-                       STATS_LOCK();
-                       stats.evictions++;
-                       STATS_UNLOCK();
+                if (search->exptime == 0 || search->exptime > current_time) {
+                    itemstats[id].evicted++;
+                    STATS_LOCK();
+                    stats.evictions++;
+                    STATS_UNLOCK();
                 }
                 do_item_unlink(search);
@@ -121,6 +134,9 @@
             }
         }
-        it = slabs_alloc(ntotal);
-        if (it == 0) return NULL;
+        it = slabs_alloc(ntotal, id);
+        if (it == 0) {
+            itemstats[id].outofmemory++;
+            return NULL;
+        }
     }
 
@@ -146,4 +162,5 @@
 void item_free(item *it) {
     size_t ntotal = ITEM_ntotal(it);
+    unsigned int clsid;
     assert((it->it_flags & ITEM_LINKED) == 0);
     assert(it != heads[it->slabs_clsid]);
@@ -152,8 +169,9 @@
 
     /* so slab size changer can tell later if item is already free or not */
+    clsid = it->slabs_clsid;
     it->slabs_clsid = 0;
     it->it_flags |= ITEM_SLABBED;
     DEBUG_REFCNT(it, 'F');
-    slabs_free(it, ntotal);
+    slabs_free(it, ntotal, clsid);
 }
 
@@ -311,5 +329,5 @@
 
 char *do_item_stats(int *bytes) {
-    size_t bufleft = (size_t) LARGEST_ID * 80;
+    size_t bufleft = (size_t) LARGEST_ID * 160;
     char *buffer = malloc(bufleft);
     char *bufcurr = buffer;
@@ -324,6 +342,11 @@
     for (i = 0; i < LARGEST_ID; i++) {
         if (tails[i] != NULL) {
-            linelen = snprintf(bufcurr, bufleft, "STAT items:%d:number %u\r\nSTAT items:%d:age %u\r\n",
-                               i, sizes[i], i, now - tails[i]->time);
+            linelen = snprintf(bufcurr, bufleft,
+                "STAT items:%d:number %u\r\n"
+                "STAT items:%d:age %u\r\n"
+                "STAT items:%d:evicted %u\r\n"
+                "STAT items:%d:outofmemory %u\r\n",
+                    i, sizes[i], i, now - tails[i]->time, i,
+                    itemstats[i].evicted, i, itemstats[i].outofmemory);
             if (linelen + sizeof("END\r\n") < bufleft) {
                 bufcurr += linelen;
Index: /branches/binary/server/configure.ac
===================================================================
--- /branches/binary/server/configure.ac (revision 725)
+++ /branches/binary/server/configure.ac (revision 745)
@@ -1,4 +1,4 @@
 AC_PREREQ(2.52)
-AC_INIT(memcached, 1.2.4, brad@danga.com)
+AC_INIT(memcached, 1.2.5, brad@danga.com)
 AC_CANONICAL_SYSTEM
 AC_CONFIG_SRCDIR(memcached.c)
Index: /branches/binary/server/doc/memcached.1
===================================================================
--- /branches/binary/server/doc/memcached.1 (revision 629)
+++ /branches/binary/server/doc/memcached.1 (revision 745)
@@ -106,4 +106,10 @@
 specified, stats collection is turned on automatically; if not, then it may
 be turned on by sending the "stats detail on" command to the server.
+.TP
+.B \-L
+Try to use large memory pages (if available). Increasing the memory page size
+could reduce the number of TLB misses and improve the performance. In order to
+get large pages from the OS, memcached will allocate the total item-cache in
+one large chunk. Only available if supported on your OS.
 .br
 .SH LICENSE
