Hello community,

here is the log from the commit of package memcached for openSUSE:Factory 
checked in at 2012-11-12 07:04:17
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/memcached (Old)
 and      /work/SRC/openSUSE:Factory/.memcached.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "memcached", Maintainer is "[email protected]"

Changes:
--------
--- /work/SRC/openSUSE:Factory/memcached/memcached.changes      2012-08-15 
11:20:02.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.memcached.new/memcached.changes 2012-11-12 
07:04:18.000000000 +0100
@@ -1,0 +2,24 @@
+Wed Nov  7 20:47:22 UTC 2012 - [email protected]
+
+- update to version 1.4.15
+  * Add some mild thread documentation
+  * README.md was missing from dist tarball
+  * Issue 286 : --disable-coverage drops "-pthread" option
+  * Reduce odds of getting OOM errors in some odd cases 
+- rebase use-endian_h, autofoo patch and 1.4.5.dif
+- fix build <= 1140
+  * export LIBEVENT_CFLAGS and LIBEVENT_LIBS so we dont need
+    pkgconfig check for libevent on <= 1140
+
+-------------------------------------------------------------------
+Wed Nov  7 19:58:59 UTC 2012 - [email protected]
+
+- fix build on older distros
+  - memcached-autofoo.patch: removed no-dist-gzip dist-xz
+  - added new conditional to guard all the systemd stuff and
+    guarded the general bcond_without with an suse_version > 12.2
+  - export LIBEVENT_CFLAGS and LIBEVENT_LIBS so we dont need
+    pkgconfig check for libevent on sles11
+  - use makeinstall instead of make_install
+
+-------------------------------------------------------------------

Old:
----
  memcached-1.4.14.tar.gz

New:
----
  memcached-1.4.15.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ memcached.spec ++++++
--- /var/tmp/diff_new_pack.Eg19fT/_old  2012-11-12 07:04:20.000000000 +0100
+++ /var/tmp/diff_new_pack.Eg19fT/_new  2012-11-12 07:04:20.000000000 +0100
@@ -16,8 +16,12 @@
 #
 
 
+%if 0%{?suse_version} > 1210
+%bcond_without systemd
+%endif
+
 Name:           memcached
-Version:        1.4.14
+Version:        1.4.15
 Release:        0
 %define pkg_name memcached
 %define pkg_version %{version}
@@ -32,7 +36,9 @@
 BuildRequires:  automake
 BuildRequires:  cyrus-sasl-devel
 BuildRequires:  pkgconfig
+%if %{with systemd}
 BuildRequires:  systemd
+%endif
 PreReq:         %insserv_prereq %fillup_prereq /usr/sbin/groupadd 
/usr/sbin/useradd
 Conflicts:      memcached-unstable
 %define home_dir /var/lib/%{pkg_name}
@@ -50,8 +56,9 @@
 Summary:        A high-performance, distributed memory object caching system
 License:        BSD-3-Clause
 Group:          Productivity/Networking/Other
+%if %{with systemd}
 %{?systemd_requires}
-
+%endif
 %description
 Memcached is a high-performance, distributed memory object caching
 system, generic in nature, but intended for use in speeding up dynamic
@@ -73,6 +80,10 @@
 
 %build
 autoreconf -fiv
+%if 0%{?suse_version} <= 1140
+export LIBEVENT_CFLAGS="-I%{_includedir}"
+export LIBEVENT_LIBS="-levent"
+%endif
 %configure --enable-sasl --disable-coverage --bindir=%{_sbindir}
 
 make %{?_smp_mflags}
@@ -81,32 +92,44 @@
 %{__make} test
 
 %install
-%make_install
+%makeinstall
 %{__install} -D  -m 0755 scripts/memcached-tool 
%{buildroot}%{_sbindir}/memcached-tool
 %{__install} -Dd -m 0755 %{buildroot}%{home_dir}
 %{__install} -D  -m 0755 %{S:1} %{buildroot}%{_sysconfdir}/init.d/%{pkg_name}
 %{__ln_s} -f ../..%{_sysconfdir}/init.d/%{pkg_name} 
%{buildroot}%{_sbindir}/rc%{pkg_name}
 %{__install} -D  -m 0644 %{S:2} 
%{buildroot}/var/adm/fillup-templates/sysconfig.%{pkg_name}
+%if %{with systemd}
 %{__install} -D  -m 0644 %{S:4} %{buildroot}%{_unitdir}/%{pkg_name}.service
+%endif
+
 %clean
 %{__rm} -rf %{buildroot};
 
 %pre
 /usr/sbin/groupadd -r %{pkg_name} &>/dev/null || :
 /usr/sbin/useradd -o -g %{pkg_name} -s /bin/false -r -c "user for %{pkg_name}" 
-d %{home_dir} %{pkg_name} &>/dev/null || :
+%if %{with systemd}
 %service_add_pre %{pkg_name}.service
+%endif
 
 %post
 %fillup_and_insserv %{pkg_name}
+%if %{with systemd}
 %service_add_post %{pkg_name}.service
+%endif
+
 %preun
 %stop_on_removal %{pkg_name}
+%if %{with systemd}
 %service_del_preun %{pkg_name}.service
+%endif
 
 %postun
 %restart_on_update %{pkg_name}
 %{insserv_cleanup}
+%if %{with systemd}
 %service_del_postun %{pkg_name}.service
+%endif
 
 %files
 %defattr(-,root,root)
@@ -120,6 +143,8 @@
 %{_includedir}/%{pkg_name}
 /var/adm/fillup-templates/sysconfig.%{pkg_name}
 %dir %attr(755,root,root) %{home_dir}
+%if %{with systemd}
 %{_unitdir}/%{pkg_name}.service
+%endif
 
 %changelog

++++++ memcached-1.4.14.tar.gz -> memcached-1.4.15.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/Makefile.am 
new/memcached-1.4.15/Makefile.am
--- old/memcached-1.4.14/Makefile.am    2012-01-06 19:19:50.000000000 +0100
+++ new/memcached-1.4.15/Makefile.am    2012-09-03 20:23:23.000000000 +0200
@@ -69,7 +69,7 @@
 
 SUBDIRS = doc
 DIST_DIRS = scripts
-EXTRA_DIST = doc scripts t memcached.spec memcached_dtrace.d version.m4
+EXTRA_DIST = doc scripts t memcached.spec memcached_dtrace.d version.m4 
README.md
 
 MOSTLYCLEANFILES = *.gcov *.gcno *.gcda *.tcov
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/Makefile.in 
new/memcached-1.4.15/Makefile.in
--- old/memcached-1.4.14/Makefile.in    2012-07-30 22:56:58.000000000 +0200
+++ new/memcached-1.4.15/Makefile.in    2012-09-04 02:13:01.000000000 +0200
@@ -324,7 +324,7 @@
 CLEANFILES = $(am__append_6) $(am__append_11)
 SUBDIRS = doc
 DIST_DIRS = scripts
-EXTRA_DIST = doc scripts t memcached.spec memcached_dtrace.d version.m4
+EXTRA_DIST = doc scripts t memcached.spec memcached_dtrace.d version.m4 
README.md
 MOSTLYCLEANFILES = *.gcov *.gcno *.gcda *.tcov
 all: $(BUILT_SOURCES) config.h
        $(MAKE) $(AM_MAKEFLAGS) all-recursive
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/README.md 
new/memcached-1.4.15/README.md
--- old/memcached-1.4.14/README.md      1970-01-01 01:00:00.000000000 +0100
+++ new/memcached-1.4.15/README.md      2012-07-30 03:05:16.000000000 +0200
@@ -0,0 +1,38 @@
+# Memcached
+
+## Dependencies
+
+* libevent, http://www.monkey.org/~provos/libevent/ (libevent-dev)
+
+## Environment
+
+### Linux
+
+If using Linux, you need a kernel with epoll.  Sure, libevent will
+work with normal select, but it sucks.
+
+epoll isn't in Linux 2.4, but there's a backport at:
+
+    http://www.xmailserver.org/linux-patches/nio-improve.html
+
+You want the epoll-lt patch (level-triggered).
+
+### Mac OS X
+
+If you're using MacOS, you'll want libevent 1.1 or higher to deal with
+a kqueue bug.
+
+Also, be warned that the -k (mlockall) option to memcached might be
+dangerous when using a large cache.  Just make sure the memcached machines
+don't swap.  memcached does non-blocking network I/O, but not disk.  (it
+should never go to disk, or you've lost the whole point of it)
+
+## Website
+
+* http://www.memcached.org
+
+## Contributing
+
+Want to contribute?  Up-to-date pointers should be at:
+
+* http://contributing.appspot.com/memcached
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/assoc.c new/memcached-1.4.15/assoc.c
--- old/memcached-1.4.14/assoc.c        2012-07-30 22:21:59.000000000 +0200
+++ new/memcached-1.4.15/assoc.c        2012-09-03 20:23:23.000000000 +0200
@@ -32,7 +32,7 @@
 typedef  unsigned       char ub1;   /* unsigned 1-byte quantities */
 
 /* how many powers of 2's worth of buckets we use */
-static unsigned int hashpower = HASHPOWER_DEFAULT;
+unsigned int hashpower = HASHPOWER_DEFAULT;
 
 #define hashsize(n) ((ub4)1<<(n))
 #define hashmask(n) (hashsize(n)-1)
@@ -51,6 +51,7 @@
 
 /* Flag: Are we in the middle of expanding now? */
 static bool expanding = false;
+static bool started_expanding = false;
 
 /*
  * During expansion we migrate values with bucket granularity; this is how
@@ -136,13 +137,19 @@
         stats.hash_bytes += hashsize(hashpower) * sizeof(void *);
         stats.hash_is_expanding = 1;
         STATS_UNLOCK();
-        pthread_cond_signal(&maintenance_cond);
     } else {
         primary_hashtable = old_hashtable;
         /* Bad news, but we can keep running. */
     }
 }
 
+static void assoc_start_expand(void) {
+    if (started_expanding)
+        return;
+    started_expanding = true;
+    pthread_cond_signal(&maintenance_cond);
+}
+
 /* Note: this isn't an assoc_update.  The key must not already exist to call 
this */
 int assoc_insert(item *it, const uint32_t hv) {
     unsigned int oldbucket;
@@ -161,7 +168,7 @@
 
     hash_items++;
     if (! expanding && hash_items > (hashsize(hashpower) * 3) / 2) {
-        assoc_expand();
+        assoc_start_expand();
     }
 
     MEMCACHED_ASSOC_INSERT(ITEM_key(it), it->nkey, hash_items);
@@ -201,6 +208,7 @@
 
         /* Lock the cache, and bulk move multiple buckets to the new
          * hash table. */
+        item_lock_global();
         mutex_lock(&cache_lock);
 
         for (ii = 0; ii < hash_bulk_move && expanding; ++ii) {
@@ -230,12 +238,25 @@
             }
         }
 
+        mutex_unlock(&cache_lock);
+        item_unlock_global();
+
         if (!expanding) {
+            /* finished expanding. tell all threads to use fine-grained locks 
*/
+            switch_item_lock_type(ITEM_LOCK_GRANULAR);
+            slabs_rebalancer_resume();
             /* We are done expanding.. just wait for next invocation */
+            mutex_lock(&cache_lock);
+            started_expanding = false;
             pthread_cond_wait(&maintenance_cond, &cache_lock);
+            /* Before doing anything, tell threads to use a global lock */
+            mutex_unlock(&cache_lock);
+            slabs_rebalancer_pause();
+            switch_item_lock_type(ITEM_LOCK_GLOBAL);
+            mutex_lock(&cache_lock);
+            assoc_expand();
+            mutex_unlock(&cache_lock);
         }
-
-        mutex_unlock(&cache_lock);
     }
     return NULL;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/assoc.h new/memcached-1.4.15/assoc.h
--- old/memcached-1.4.14/assoc.h        2012-01-06 19:19:50.000000000 +0100
+++ new/memcached-1.4.15/assoc.h        2012-09-03 20:23:23.000000000 +0200
@@ -6,4 +6,4 @@
 void do_assoc_move_next_bucket(void);
 int start_assoc_maintenance_thread(void);
 void stop_assoc_maintenance_thread(void);
-
+extern unsigned int hashpower;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/configure 
new/memcached-1.4.15/configure
--- old/memcached-1.4.14/configure      2012-07-30 22:56:58.000000000 +0200
+++ new/memcached-1.4.15/configure      2012-09-04 02:13:01.000000000 +0200
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.65 for memcached 1.4.14.
+# Generated by GNU Autoconf 2.65 for memcached 1.4.15.
 #
 # Report bugs to <[email protected]>.
 #
@@ -552,8 +552,8 @@
 # Identity of this package.
 PACKAGE_NAME='memcached'
 PACKAGE_TARNAME='memcached'
-PACKAGE_VERSION='1.4.14'
-PACKAGE_STRING='memcached 1.4.14'
+PACKAGE_VERSION='1.4.15'
+PACKAGE_STRING='memcached 1.4.15'
 PACKAGE_BUGREPORT='[email protected]'
 PACKAGE_URL=''
 
@@ -1272,7 +1272,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures memcached 1.4.14 to adapt to many kinds of systems.
+\`configure' configures memcached 1.4.15 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1343,7 +1343,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of memcached 1.4.14:";;
+     short | recursive ) echo "Configuration of memcached 1.4.15:";;
    esac
   cat <<\_ACEOF
 
@@ -1441,7 +1441,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-memcached configure 1.4.14
+memcached configure 1.4.15
 generated by GNU Autoconf 2.65
 
 Copyright (C) 2009 Free Software Foundation, Inc.
@@ -1905,7 +1905,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by memcached $as_me 1.4.14, which was
+It was created by memcached $as_me 1.4.15, which was
 generated by GNU Autoconf 2.65.  Invocation command line was
 
   $ $0 $@
@@ -2825,7 +2825,7 @@
 
 # Define the identity of the package.
  PACKAGE=memcached
- VERSION=1.4.14
+ VERSION=1.4.15
 
 
 cat >>confdefs.h <<_ACEOF
@@ -4294,6 +4294,9 @@
 fi
 
 
+if test "$ICC" = "yes" -o "$GCC" = "yes"; then :
+  CFLAGS="$CFLAGS -pthread"
+fi
 
 if test "$ICC" = "no"; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept 
ISO C99" >&5
@@ -4848,10 +4851,7 @@
 
 
 if test "x$enable_coverage" != "xno"; then
-   if test "$ICC" = "yes"
-   then
-            CFLAGS="$CFLAGS -pthread"
-   elif test "$GCC" = "yes"
+   if test "$GCC" = "yes" -a "$ICC" != "yes"
    then
       CFLAGS="$CFLAGS -pthread"
       # Extract the first word of "gcov", so it can be a program name with 
args.
@@ -6822,7 +6822,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by memcached $as_me 1.4.14, which was
+This file was extended by memcached $as_me 1.4.15, which was
 generated by GNU Autoconf 2.65.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -6888,7 +6888,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; 
s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-memcached config.status 1.4.14
+memcached config.status 1.4.15
 configured by $0, generated by GNU Autoconf 2.65,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/configure.ac 
new/memcached-1.4.15/configure.ac
--- old/memcached-1.4.14/configure.ac   2012-02-02 07:01:29.000000000 +0100
+++ new/memcached-1.4.15/configure.ac   2012-09-03 09:35:54.000000000 +0200
@@ -49,6 +49,8 @@
 ])
 
 DETECT_SUNCC([CFLAGS="-mt $CFLAGS"], [])
+AS_IF([test "$ICC" = "yes" -o "$GCC" = "yes"],
+      [CFLAGS="$CFLAGS -pthread"])
 
 if test "$ICC" = "no"; then
    AC_PROG_CC_C99
@@ -140,11 +142,7 @@
   [AS_HELP_STRING([--disable-coverage],[Disable code coverage])])
 
 if test "x$enable_coverage" != "xno"; then
-   if test "$ICC" = "yes"
-   then
-      dnl ICC trying to be gcc, but not well
-      CFLAGS="$CFLAGS -pthread"
-   elif test "$GCC" = "yes"
+   if test "$GCC" = "yes" -a "$ICC" != "yes"
    then
       CFLAGS="$CFLAGS -pthread"
       AC_PATH_PROG([PROFILER], [gcov], "no", [$PATH])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/doc/Makefile 
new/memcached-1.4.15/doc/Makefile
--- old/memcached-1.4.14/doc/Makefile   2012-07-30 22:57:03.000000000 +0200
+++ new/memcached-1.4.15/doc/Makefile   2012-09-04 02:13:06.000000000 +0200
@@ -82,7 +82,7 @@
 AWK = gawk
 CC = gcc -std=gnu99
 CCDEPMODE = depmode=gcc3
-CFLAGS = -g -O2 -pthread -Wall -Werror -pedantic -Wmissing-prototypes 
-Wmissing-declarations -Wredundant-decls -fno-strict-aliasing
+CFLAGS = -g -O2 -pthread -pthread -Wall -Werror -pedantic -Wmissing-prototypes 
-Wmissing-declarations -Wredundant-decls -fno-strict-aliasing
 CPP = gcc -E
 CPPFLAGS = 
 CYGPATH_W = echo
@@ -112,10 +112,10 @@
 PACKAGE = memcached
 PACKAGE_BUGREPORT = [email protected]
 PACKAGE_NAME = memcached
-PACKAGE_STRING = memcached 1.4.14
+PACKAGE_STRING = memcached 1.4.15
 PACKAGE_TARNAME = memcached
 PACKAGE_URL = 
-PACKAGE_VERSION = 1.4.14
+PACKAGE_VERSION = 1.4.15
 PATH_SEPARATOR = :
 PROFILER = /usr/bin/gcov
 PROFILER_FLAGS = -fprofile-arcs -ftest-coverage
@@ -123,7 +123,7 @@
 SET_MAKE = 
 SHELL = /bin/bash
 STRIP = 
-VERSION = 1.4.14
+VERSION = 1.4.15
 XML2RFC = no
 XSLTPROC = /usr/bin/xsltproc
 abs_builddir = /home/dormando/p/danga/git/memcached/doc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/doc/threads.txt 
new/memcached-1.4.15/doc/threads.txt
--- old/memcached-1.4.14/doc/threads.txt        1970-01-01 01:00:00.000000000 
+0100
+++ new/memcached-1.4.15/doc/threads.txt        2012-09-04 00:17:10.000000000 
+0200
@@ -0,0 +1,46 @@
+WARNING: This document is currently a stub. It is incomplete, but provided to
+give a vague overview of how threads are implemented.
+
+Multithreading in memcached *was* originally simple:
+
+- One listener thread
+- N "event worker" threads
+- Some misc background threads
+
+Each worker thread is assigned connections, and runs its own epoll loop. The
+central hash table, LRU lists, and some statistics counters are covered by
+global locks. Protocol parsing, data transfer happens in threads. Data lookups
+and modifications happen under central locks.
+
+THIS HAS CHANGED!
+
+I do need to flesh this out more, and it'll need a lot more tuning, but it has
+changed in the following ways:
+
+- A secondary small hash table of locks is used to lock an item by its hash
+  value. This prevents multiple threads from acting on the same item at the
+  same time.
+- This secondary hash table is mapped to the central hash tables buckets. This
+  allows multiple threads to access the hash table in parallel. Only one
+  thread may read or write against a particular hash table bucket.
+- atomic refcounts per item are used to manage garbage collection and
+  mutability.
+- A central lock is still held around any "item modifications" - any change to
+  any item flags on any item, the LRU state, or refcount incrementing are
+  still centrally locked.
+
+- When pulling an item off of the LRU tail for eviction or re-allocation, the
+  system must attempt to lock the item's bucket, which is done with a trylock
+  to avoid deadlocks. If a bucket is in use (and not by that thread) it will
+  walk up the LRU a little in an attempt to fetch a non-busy item.
+
+Since I'm sick of hearing it:
+
+- If you remove the per-thread stats lock, CPU usage goes down by less than a
+  point of a percent, and it does not improve scalability.
+- In my testing, the remaining global STATS_LOCK calls never seem to collide.
+
+Yes, more stats can be moved to threads, and those locks can actually be
+removed entirely on x86-64 systems. However my tests haven't shown that as
+beneficial so far, so I've prioritized other work. Apologies for the rant but
+it's a common question.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/items.c new/memcached-1.4.15/items.c
--- old/memcached-1.4.14/items.c        2012-07-30 22:23:37.000000000 +0200
+++ new/memcached-1.4.15/items.c        2012-09-03 20:23:23.000000000 +0200
@@ -85,7 +85,9 @@
 }
 
 /*@null@*/
-item *do_item_alloc(char *key, const size_t nkey, const int flags, const 
rel_time_t exptime, const int nbytes) {
+item *do_item_alloc(char *key, const size_t nkey, const int flags,
+                    const rel_time_t exptime, const int nbytes,
+                    const uint32_t cur_hv) {
     uint8_t nsuffix;
     item *it = NULL;
     char suffix[40];
@@ -100,87 +102,93 @@
 
     mutex_lock(&cache_lock);
     /* do a quick check if we have any expired items in the tail.. */
+    int tries = 5;
+    int tried_alloc = 0;
     item *search;
+    void *hold_lock = NULL;
     rel_time_t oldest_live = settings.oldest_live;
 
     search = tails[id];
-    if (search != NULL && (refcount_incr(&search->refcount) == 2)) {
+    /* We walk up *only* for locked items. Never searching for expired.
+     * Waste of CPU for almost all deployments */
+    for (; tries > 0 && search != NULL; tries--, search=search->prev) {
+        uint32_t hv = hash(ITEM_key(search), search->nkey, 0);
+        /* Attempt to hash item lock the "search" item. If locked, no
+         * other callers can incr the refcount
+         */
+        /* FIXME: I think we need to mask the hv here for comparison? */
+        if (hv != cur_hv && (hold_lock = item_trylock(hv)) == NULL)
+            continue;
+        /* Now see if the item is refcount locked */
+        if (refcount_incr(&search->refcount) != 2) {
+            refcount_decr(&search->refcount);
+            /* Old rare bug could cause a refcount leak. We haven't seen
+             * it in years, but we leave this code in to prevent failures
+             * just in case */
+            if (search->time + TAIL_REPAIR_TIME < current_time) {
+                itemstats[id].tailrepairs++;
+                search->refcount = 1;
+                do_item_unlink_nolock(search, hv);
+            }
+            if (hold_lock)
+                item_trylock_unlock(hold_lock);
+            continue;
+        }
+
+        /* Expired or flushed */
         if ((search->exptime != 0 && search->exptime < current_time)
-            || (search->time <= oldest_live && oldest_live <= current_time)) { 
 // dead by flush
-            STATS_LOCK();
-            stats.reclaimed++;
-            STATS_UNLOCK();
+            || (search->time <= oldest_live && oldest_live <= current_time)) {
             itemstats[id].reclaimed++;
             if ((search->it_flags & ITEM_FETCHED) == 0) {
-                STATS_LOCK();
-                stats.expired_unfetched++;
-                STATS_UNLOCK();
                 itemstats[id].expired_unfetched++;
             }
             it = search;
             slabs_adjust_mem_requested(it->slabs_clsid, ITEM_ntotal(it), 
ntotal);
-            do_item_unlink_nolock(it, hash(ITEM_key(it), it->nkey, 0));
+            do_item_unlink_nolock(it, hv);
             /* Initialize the item block: */
             it->slabs_clsid = 0;
         } else if ((it = slabs_alloc(ntotal, id)) == NULL) {
+            tried_alloc = 1;
             if (settings.evict_to_free == 0) {
                 itemstats[id].outofmemory++;
-                mutex_unlock(&cache_lock);
-                return NULL;
-            }
-            itemstats[id].evicted++;
-            itemstats[id].evicted_time = current_time - search->time;
-            if (search->exptime != 0)
-                itemstats[id].evicted_nonzero++;
-            if ((search->it_flags & ITEM_FETCHED) == 0) {
-                STATS_LOCK();
-                stats.evicted_unfetched++;
-                STATS_UNLOCK();
-                itemstats[id].evicted_unfetched++;
+            } else {
+                itemstats[id].evicted++;
+                itemstats[id].evicted_time = current_time - search->time;
+                if (search->exptime != 0)
+                    itemstats[id].evicted_nonzero++;
+                if ((search->it_flags & ITEM_FETCHED) == 0) {
+                    itemstats[id].evicted_unfetched++;
+                }
+                it = search;
+                slabs_adjust_mem_requested(it->slabs_clsid, ITEM_ntotal(it), 
ntotal);
+                do_item_unlink_nolock(it, hv);
+                /* Initialize the item block: */
+                it->slabs_clsid = 0;
+
+                /* If we've just evicted an item, and the automover is set to
+                 * angry bird mode, attempt to rip memory into this slab class.
+                 * TODO: Move valid object detection into a function, and on a
+                 * "successful" memory pull, look behind and see if the next 
alloc
+                 * would be an eviction. Then kick off the slab mover before 
the
+                 * eviction happens.
+                 */
+                if (settings.slab_automove == 2)
+                    slabs_reassign(-1, id);
             }
-            STATS_LOCK();
-            stats.evictions++;
-            STATS_UNLOCK();
-            it = search;
-            slabs_adjust_mem_requested(it->slabs_clsid, ITEM_ntotal(it), 
ntotal);
-            do_item_unlink_nolock(it, hash(ITEM_key(it), it->nkey, 0));
-            /* Initialize the item block: */
-            it->slabs_clsid = 0;
-
-            /* If we've just evicted an item, and the automover is set to
-             * angry bird mode, attempt to rip memory into this slab class.
-             * TODO: Move valid object detection into a function, and on a
-             * "successful" memory pull, look behind and see if the next alloc
-             * would be an eviction. Then kick off the slab mover before the
-             * eviction happens.
-             */
-            if (settings.slab_automove == 2)
-                slabs_reassign(-1, id);
-        } else {
-            refcount_decr(&search->refcount);
         }
-    } else {
-        /* If the LRU is empty or locked, attempt to allocate memory */
-        it = slabs_alloc(ntotal, id);
-        if (search != NULL)
-            refcount_decr(&search->refcount);
+
+        refcount_decr(&search->refcount);
+        /* If hash values were equal, we don't grab a second lock */
+        if (hold_lock)
+            item_trylock_unlock(hold_lock);
+        break;
     }
 
+    if (!tried_alloc && (tries == 0 || search == NULL))
+        it = slabs_alloc(ntotal, id);
+
     if (it == NULL) {
         itemstats[id].outofmemory++;
-        /* Last ditch effort. There was a very rare bug which caused
-         * refcount leaks. We leave this just in case they ever happen again.
-         * We can reasonably assume no item can stay locked for more than
-         * three hours, so if we find one in the tail which is that old,
-         * free it anyway.
-         */
-        if (search != NULL &&
-            search->refcount != 2 &&
-            search->time + TAIL_REPAIR_TIME < current_time) {
-            itemstats[id].tailrepairs++;
-            search->refcount = 1;
-            do_item_unlink_nolock(search, hash(ITEM_key(search), search->nkey, 
0));
-        }
         mutex_unlock(&cache_lock);
         return NULL;
     }
@@ -416,6 +424,26 @@
     mutex_unlock(&cache_lock);
 }
 
+void do_item_stats_totals(ADD_STAT add_stats, void *c) {
+    itemstats_t totals;
+    memset(&totals, 0, sizeof(itemstats_t));
+    int i;
+    for (i = 0; i < LARGEST_ID; i++) {
+        totals.expired_unfetched += itemstats[i].expired_unfetched;
+        totals.evicted_unfetched += itemstats[i].evicted_unfetched;
+        totals.evicted += itemstats[i].evicted;
+        totals.reclaimed += itemstats[i].reclaimed;
+    }
+    APPEND_STAT("expired_unfetched", "%llu",
+                (unsigned long long)totals.expired_unfetched);
+    APPEND_STAT("evicted_unfetched", "%llu",
+                (unsigned long long)totals.evicted_unfetched);
+    APPEND_STAT("evictions", "%llu",
+                (unsigned long long)totals.evicted);
+    APPEND_STAT("reclaimed", "%llu",
+                (unsigned long long)totals.reclaimed);
+}
+
 void do_item_stats(ADD_STAT add_stats, void *c) {
     int i;
     for (i = 0; i < LARGEST_ID; i++) {
@@ -491,7 +519,7 @@
 
 /** wrapper around assoc_find which does the lazy expiration logic */
 item *do_item_get(const char *key, const size_t nkey, const uint32_t hv) {
-    mutex_lock(&cache_lock);
+    //mutex_lock(&cache_lock);
     item *it = assoc_find(key, nkey, hv);
     if (it != NULL) {
         refcount_incr(&it->refcount);
@@ -505,7 +533,7 @@
             it = NULL;
         }
     }
-    mutex_unlock(&cache_lock);
+    //mutex_unlock(&cache_lock);
     int was_found = 0;
 
     if (settings.verbose > 2) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/items.h new/memcached-1.4.15/items.h
--- old/memcached-1.4.14/items.h        2012-01-09 05:36:49.000000000 +0100
+++ new/memcached-1.4.15/items.h        2012-09-03 20:23:23.000000000 +0200
@@ -2,7 +2,7 @@
 uint64_t get_cas_id(void);
 
 /*@null@*/
-item *do_item_alloc(char *key, const size_t nkey, const int flags, const 
rel_time_t exptime, const int nbytes);
+item *do_item_alloc(char *key, const size_t nkey, const int flags, const 
rel_time_t exptime, const int nbytes, const uint32_t cur_hv);
 void item_free(item *it);
 bool item_size_ok(const size_t nkey, const int flags, const int nbytes);
 
@@ -16,6 +16,7 @@
 /*@null@*/
 char *do_item_cachedump(const unsigned int slabs_clsid, const unsigned int 
limit, unsigned int *bytes);
 void do_item_stats(ADD_STAT add_stats, void *c);
+void do_item_stats_totals(ADD_STAT add_stats, void *c);
 /*@null@*/
 void do_item_stats_sizes(ADD_STAT add_stats, void *c);
 void do_item_flush_expired(void);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/memcached.c 
new/memcached-1.4.15/memcached.c
--- old/memcached-1.4.14/memcached.c    2012-07-30 22:26:47.000000000 +0200
+++ new/memcached-1.4.15/memcached.c    2012-09-03 20:23:23.000000000 +0200
@@ -2325,7 +2325,7 @@
 
                 flags = (int) strtol(ITEM_suffix(old_it), (char **) NULL, 10);
 
-                new_it = item_alloc(key, it->nkey, flags, old_it->exptime, 
it->nbytes + old_it->nbytes - 2 /* CRLF */);
+                new_it = do_item_alloc(key, it->nkey, flags, old_it->exptime, 
it->nbytes + old_it->nbytes - 2 /* CRLF */, hv);
 
                 if (new_it == NULL) {
                     /* SERVER_ERROR out of memory */
@@ -2585,8 +2585,6 @@
     APPEND_STAT("hash_power_level", "%u", stats.hash_power_level);
     APPEND_STAT("hash_bytes", "%llu", (unsigned long long)stats.hash_bytes);
     APPEND_STAT("hash_is_expanding", "%u", stats.hash_is_expanding);
-    APPEND_STAT("expired_unfetched", "%llu", stats.expired_unfetched);
-    APPEND_STAT("evicted_unfetched", "%llu", stats.evicted_unfetched);
     if (settings.slab_reassign) {
         APPEND_STAT("slab_reassign_running", "%u", 
stats.slab_reassign_running);
         APPEND_STAT("slabs_moved", "%llu", stats.slabs_moved);
@@ -3101,7 +3099,7 @@
     res = strlen(buf);
     if (res + 2 > it->nbytes || it->refcount != 1) { /* need to realloc */
         item *new_it;
-        new_it = item_alloc(ITEM_key(it), it->nkey, atoi(ITEM_suffix(it) + 1), 
it->exptime, res + 2 );
+        new_it = do_item_alloc(ITEM_key(it), it->nkey, atoi(ITEM_suffix(it) + 
1), it->exptime, res + 2, hv);
         if (new_it == 0) {
             do_item_remove(it);
             return EOM;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/memcached.h 
new/memcached-1.4.15/memcached.h
--- old/memcached-1.4.14/memcached.h    2012-07-30 00:40:49.000000000 +0200
+++ new/memcached-1.4.15/memcached.h    2012-09-03 20:23:23.000000000 +0200
@@ -180,6 +180,11 @@
     udp_transport
 };
 
+enum item_lock_types {
+    ITEM_LOCK_GRANULAR = 0,
+    ITEM_LOCK_GLOBAL
+};
+
 #define IS_UDP(x) (x == udp_transport)
 
 #define NREAD_ADD 1
@@ -352,6 +357,7 @@
     struct thread_stats stats;  /* Stats generated by this thread */
     struct conn_queue *new_conn_queue; /* queue of new connections to handle */
     cache_t *suffix_cache;      /* suffix cache */
+    uint8_t item_lock_type;     /* use fine-grained or global item lock */
 } LIBEVENT_THREAD;
 
 typedef struct {
@@ -527,12 +533,18 @@
 void  item_remove(item *it);
 int   item_replace(item *it, item *new_it, const uint32_t hv);
 void  item_stats(ADD_STAT add_stats, void *c);
+void  item_stats_totals(ADD_STAT add_stats, void *c);
 void  item_stats_sizes(ADD_STAT add_stats, void *c);
 void  item_unlink(item *it);
 void  item_update(item *it);
 
+void item_lock_global(void);
+void item_unlock_global(void);
 void item_lock(uint32_t hv);
+void *item_trylock(uint32_t hv);
+void item_trylock_unlock(void *arg);
 void item_unlock(uint32_t hv);
+void switch_item_lock_type(enum item_lock_types type);
 unsigned short refcount_incr(unsigned short *refcount);
 unsigned short refcount_decr(unsigned short *refcount);
 void STATS_LOCK(void);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/memcached.spec 
new/memcached-1.4.15/memcached.spec
--- old/memcached-1.4.14/memcached.spec 2012-07-30 22:56:56.000000000 +0200
+++ new/memcached-1.4.15/memcached.spec 2012-09-04 02:12:59.000000000 +0200
@@ -1,12 +1,12 @@
 Name:           memcached
-Version:        1.4.14
+Version:        1.4.15
 Release:        1%{?dist}
 Summary:        High Performance, Distributed Memory Object Cache
 
 Group:          System Environment/Daemons
 License:        BSD
 URL:            http://www.danga.com/memcached/
-Source0:        http://memcached.googlecode.com/files/%{name}-1.4.14.tar.gz
+Source0:        http://memcached.googlecode.com/files/%{name}-1.4.15.tar.gz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
 BuildRequires:  libevent-devel
@@ -23,7 +23,7 @@
 web applications by alleviating database load.
 
 %prep
-%setup -q -n %{name}-1.4.14
+%setup -q -n %{name}-1.4.15
 
 
 %build
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/slabs.c new/memcached-1.4.15/slabs.c
--- old/memcached-1.4.14/slabs.c        2012-07-30 06:09:13.000000000 +0200
+++ new/memcached-1.4.15/slabs.c        2012-09-03 20:23:23.000000000 +0200
@@ -293,11 +293,8 @@
             APPEND_STAT("bytes", "%llu", (unsigned long long)stats.curr_bytes);
             APPEND_STAT("curr_items", "%u", stats.curr_items);
             APPEND_STAT("total_items", "%u", stats.total_items);
-            APPEND_STAT("evictions", "%llu",
-                        (unsigned long long)stats.evictions);
-            APPEND_STAT("reclaimed", "%llu",
-                        (unsigned long long)stats.reclaimed);
             STATS_UNLOCK();
+            item_stats_totals(add_stats, c);
         } else if (nz_strcmp(nkey, stat_type, "items") == 0) {
             item_stats(add_stats, c);
         } else if (nz_strcmp(nkey, stat_type, "slabs") == 0) {
@@ -498,7 +495,7 @@
 }
 
 enum move_status {
-    MOVE_PASS=0, MOVE_DONE, MOVE_BUSY
+    MOVE_PASS=0, MOVE_DONE, MOVE_BUSY, MOVE_LOCKED
 };
 
 /* refcount == 0 is safe since nobody can incr while cache_lock is held.
@@ -522,36 +519,43 @@
         item *it = slab_rebal.slab_pos;
         status = MOVE_PASS;
         if (it->slabs_clsid != 255) {
-            refcount = refcount_incr(&it->refcount);
-            if (refcount == 1) { /* item is unlinked, unused */
-                if (it->it_flags & ITEM_SLABBED) {
-                    /* remove from slab freelist */
-                    if (s_cls->slots == it) {
-                        s_cls->slots = it->next;
+            void *hold_lock = NULL;
+            uint32_t hv = hash(ITEM_key(it), it->nkey, 0);
+            if ((hold_lock = item_trylock(hv)) == NULL) {
+                status = MOVE_LOCKED;
+            } else {
+                refcount = refcount_incr(&it->refcount);
+                if (refcount == 1) { /* item is unlinked, unused */
+                    if (it->it_flags & ITEM_SLABBED) {
+                        /* remove from slab freelist */
+                        if (s_cls->slots == it) {
+                            s_cls->slots = it->next;
+                        }
+                        if (it->next) it->next->prev = it->prev;
+                        if (it->prev) it->prev->next = it->next;
+                        s_cls->sl_curr--;
+                        status = MOVE_DONE;
+                    } else {
+                        status = MOVE_BUSY;
+                    }
+                } else if (refcount == 2) { /* item is linked but not busy */
+                    if ((it->it_flags & ITEM_LINKED) != 0) {
+                        do_item_unlink_nolock(it, hash(ITEM_key(it), it->nkey, 
0));
+                        status = MOVE_DONE;
+                    } else {
+                        /* refcount == 1 + !ITEM_LINKED means the item is being
+                         * uploaded to, or was just unlinked but hasn't been 
freed
+                         * yet. Let it bleed off on its own and try again 
later */
+                        status = MOVE_BUSY;
                     }
-                    if (it->next) it->next->prev = it->prev;
-                    if (it->prev) it->prev->next = it->next;
-                    s_cls->sl_curr--;
-                    status = MOVE_DONE;
-                } else {
-                    status = MOVE_BUSY;
-                }
-            } else if (refcount == 2) { /* item is linked but not busy */
-                if ((it->it_flags & ITEM_LINKED) != 0) {
-                    do_item_unlink_nolock(it, hash(ITEM_key(it), it->nkey, 0));
-                    status = MOVE_DONE;
                 } else {
-                    /* refcount == 1 + !ITEM_LINKED means the item is being
-                     * uploaded to, or was just unlinked but hasn't been freed
-                     * yet. Let it bleed off on its own and try again later */
+                    if (settings.verbose > 2) {
+                        fprintf(stderr, "Slab reassign hit a busy item: 
refcount: %d (%d -> %d)\n",
+                            it->refcount, slab_rebal.s_clsid, 
slab_rebal.d_clsid);
+                    }
                     status = MOVE_BUSY;
                 }
-            } else {
-                if (settings.verbose > 2) {
-                    fprintf(stderr, "Slab reassign hit a busy item: refcount: 
%d (%d -> %d)\n",
-                        it->refcount, slab_rebal.s_clsid, slab_rebal.d_clsid);
-                }
-                status = MOVE_BUSY;
+                item_trylock_unlock(hold_lock);
             }
         }
 
@@ -562,9 +566,10 @@
                 it->slabs_clsid = 255;
                 break;
             case MOVE_BUSY:
+                refcount_decr(&it->refcount);
+            case MOVE_LOCKED:
                 slab_rebal.busy_items++;
                 was_busy++;
-                refcount_decr(&it->refcount);
                 break;
             case MOVE_PASS:
                 break;
@@ -731,6 +736,8 @@
  */
 static void *slab_rebalance_thread(void *arg) {
     int was_busy = 0;
+    /* So we first pass into cond_wait with the mutex held */
+    mutex_lock(&slabs_rebalance_lock);
 
     while (do_run_slab_rebalance_thread) {
         if (slab_rebalance_signal == 1) {
@@ -819,6 +826,15 @@
     return ret;
 }
 
+/* If we hold this lock, rebalancer can't wake up or move */
+void slabs_rebalancer_pause(void) {
+    pthread_mutex_lock(&slabs_rebalance_lock);
+}
+
+void slabs_rebalancer_resume(void) {
+    pthread_mutex_unlock(&slabs_rebalance_lock);
+}
+
 static pthread_t maintenance_tid;
 static pthread_t rebalance_tid;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/slabs.h new/memcached-1.4.15/slabs.h
--- old/memcached-1.4.14/slabs.h        2012-07-29 10:30:59.000000000 +0200
+++ new/memcached-1.4.15/slabs.h        2012-09-03 20:23:23.000000000 +0200
@@ -43,4 +43,7 @@
 
 enum reassign_result_type slabs_reassign(int src, int dst);
 
+void slabs_rebalancer_pause(void);
+void slabs_rebalancer_resume(void);
+
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/thread.c 
new/memcached-1.4.15/thread.c
--- old/memcached-1.4.14/thread.c       2012-07-30 22:28:21.000000000 +0200
+++ new/memcached-1.4.15/thread.c       2012-09-03 20:23:23.000000000 +0200
@@ -57,8 +57,12 @@
 static pthread_mutex_t *item_locks;
 /* size of the item lock hash table */
 static uint32_t item_lock_count;
-/* size - 1 for lookup masking */
-static uint32_t item_lock_mask;
+#define hashsize(n) ((unsigned long int)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+/* this lock is temporarily engaged during a hash table expansion */
+static pthread_mutex_t item_global_lock;
+/* thread-specific variable for deeply finding the item lock type */
+static pthread_key_t item_lock_type_key;
 
 static LIBEVENT_DISPATCHER_THREAD dispatcher_thread;
 
@@ -108,12 +112,92 @@
 #endif
 }
 
+/* Convenience functions for calling *only* when in ITEM_LOCK_GLOBAL mode */
+void item_lock_global(void) {
+    mutex_lock(&item_global_lock);
+}
+
+void item_unlock_global(void) {
+    mutex_unlock(&item_global_lock);
+}
+
 void item_lock(uint32_t hv) {
-    mutex_lock(&item_locks[hv & item_lock_mask]);
+    uint8_t *lock_type = pthread_getspecific(item_lock_type_key);
+    if (likely(*lock_type == ITEM_LOCK_GRANULAR)) {
+        mutex_lock(&item_locks[(hv & hashmask(hashpower)) % item_lock_count]);
+    } else {
+        mutex_lock(&item_global_lock);
+    }
+}
+
+/* Special case. When ITEM_LOCK_GLOBAL mode is enabled, this should become a
+ * no-op, as it's only called from within the item lock if necessary.
+ * However, we can't mix a no-op and threads which are still synchronizing to
+ * GLOBAL. So instead we just always try to lock. When in GLOBAL mode this
+ * turns into an effective no-op. Threads re-synchronize after the power level
+ * switch so it should stay safe.
+ */
+void *item_trylock(uint32_t hv) {
+    pthread_mutex_t *lock = &item_locks[(hv & hashmask(hashpower)) % 
item_lock_count];
+    if (pthread_mutex_trylock(lock) == 0) {
+        return lock;
+    }
+    return NULL;
+}
+
+void item_trylock_unlock(void *lock) {
+    mutex_unlock((pthread_mutex_t *) lock);
 }
 
 void item_unlock(uint32_t hv) {
-    mutex_unlock(&item_locks[hv & item_lock_mask]);
+    uint8_t *lock_type = pthread_getspecific(item_lock_type_key);
+    if (likely(*lock_type == ITEM_LOCK_GRANULAR)) {
+        mutex_unlock(&item_locks[(hv & hashmask(hashpower)) % 
item_lock_count]);
+    } else {
+        mutex_unlock(&item_global_lock);
+    }
+}
+
+static void wait_for_thread_registration(int nthreads) {
+    while (init_count < nthreads) {
+        pthread_cond_wait(&init_cond, &init_lock);
+    }
+}
+
+static void register_thread_initialized(void) {
+    pthread_mutex_lock(&init_lock);
+    init_count++;
+    pthread_cond_signal(&init_cond);
+    pthread_mutex_unlock(&init_lock);
+}
+
+void switch_item_lock_type(enum item_lock_types type) {
+    char buf[1];
+    int i;
+
+    switch (type) {
+        case ITEM_LOCK_GRANULAR:
+            buf[0] = 'l';
+            break;
+        case ITEM_LOCK_GLOBAL:
+            buf[0] = 'g';
+            break;
+        default:
+            fprintf(stderr, "Unknown lock type: %d\n", type);
+            assert(1 == 0);
+            break;
+    }
+
+    pthread_mutex_lock(&init_lock);
+    init_count = 0;
+    for (i = 0; i < settings.num_threads; i++) {
+        if (write(threads[i].notify_send_fd, buf, 1) != 1) {
+            perror("Failed writing to notify pipe");
+            /* TODO: This is a fatal problem. Can it ever happen temporarily? 
*/
+        }
+    }
+    wait_for_thread_registration(settings.num_threads);
+    pthread_mutex_unlock(&init_lock);
 }
 
 /*
@@ -278,7 +362,6 @@
     }
 }
 
-
 /*
  * Worker thread: main event loop
  */
@@ -289,10 +372,14 @@
      * all threads have finished initializing.
      */
 
-    pthread_mutex_lock(&init_lock);
-    init_count++;
-    pthread_cond_signal(&init_cond);
-    pthread_mutex_unlock(&init_lock);
+    /* set an indexable thread-specific memory item for the lock type.
+     * this could be unnecessary if we pass the conn *c struct through
+     * all item_lock calls...
+     */
+    me->item_lock_type = ITEM_LOCK_GRANULAR;
+    pthread_setspecific(item_lock_type_key, &me->item_lock_type);
+
+    register_thread_initialized();
 
     event_base_loop(me->base, 0);
     return NULL;
@@ -312,6 +399,8 @@
         if (settings.verbose > 0)
             fprintf(stderr, "Can't read from libevent pipe\n");
 
+    switch (buf[0]) {
+    case 'c':
     item = cq_pop(me->new_conn_queue);
 
     if (NULL != item) {
@@ -333,6 +422,17 @@
         }
         cqi_free(item);
     }
+        break;
+    /* we were told to flip the lock type and report in */
+    case 'l':
+    me->item_lock_type = ITEM_LOCK_GRANULAR;
+    register_thread_initialized();
+        break;
+    case 'g':
+    me->item_lock_type = ITEM_LOCK_GLOBAL;
+    register_thread_initialized();
+        break;
+    }
 }
 
 /* Which thread we assigned a connection to most recently. */
@@ -346,6 +446,7 @@
 void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags,
                        int read_buffer_size, enum network_transport transport) 
{
     CQ_ITEM *item = cqi_new();
+    char buf[1];
     int tid = (last_thread + 1) % settings.num_threads;
 
     LIBEVENT_THREAD *thread = threads + tid;
@@ -361,7 +462,8 @@
     cq_push(thread->new_conn_queue, item);
 
     MEMCACHED_CONN_DISPATCH(sfd, thread->thread_id);
-    if (write(thread->notify_send_fd, "", 1) != 1) {
+    buf[0] = 'c';
+    if (write(thread->notify_send_fd, buf, 1) != 1) {
         perror("Writing to thread notify pipe");
     }
 }
@@ -381,7 +483,7 @@
 item *item_alloc(char *key, size_t nkey, int flags, rel_time_t exptime, int 
nbytes) {
     item *it;
     /* do_item_alloc handles its own locks */
-    it = do_item_alloc(key, nkey, flags, exptime, nbytes);
+    it = do_item_alloc(key, nkey, flags, exptime, nbytes, 0);
     return it;
 }
 
@@ -529,6 +631,12 @@
     mutex_unlock(&cache_lock);
 }
 
+void  item_stats_totals(ADD_STAT add_stats, void *c) {
+    mutex_lock(&cache_lock);
+    do_item_stats_totals(add_stats, c);
+    mutex_unlock(&cache_lock);
+}
+
 /*
  * Dumps a list of objects of each size in 32-byte increments
  */
@@ -686,8 +794,7 @@
         power = 13;
     }
 
-    item_lock_count = ((unsigned long int)1 << (power));
-    item_lock_mask  = item_lock_count - 1;
+    item_lock_count = hashsize(power);
 
     item_locks = calloc(item_lock_count, sizeof(pthread_mutex_t));
     if (! item_locks) {
@@ -697,6 +804,8 @@
     for (i = 0; i < item_lock_count; i++) {
         pthread_mutex_init(&item_locks[i], NULL);
     }
+    pthread_key_create(&item_lock_type_key, NULL);
+    pthread_mutex_init(&item_global_lock, NULL);
 
     threads = calloc(nthreads, sizeof(LIBEVENT_THREAD));
     if (! threads) {
@@ -729,9 +838,7 @@
 
     /* Wait for all the threads to set themselves up before returning. */
     pthread_mutex_lock(&init_lock);
-    while (init_count < nthreads) {
-        pthread_cond_wait(&init_cond, &init_lock);
-    }
+    wait_for_thread_registration(nthreads);
     pthread_mutex_unlock(&init_lock);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/memcached-1.4.14/version.m4 
new/memcached-1.4.15/version.m4
--- old/memcached-1.4.14/version.m4     2012-07-30 22:56:56.000000000 +0200
+++ new/memcached-1.4.15/version.m4     2012-09-04 02:12:59.000000000 +0200
@@ -1 +1 @@
-m4_define([VERSION_NUMBER], [1.4.14])
+m4_define([VERSION_NUMBER], [1.4.15])

++++++ memcached-1.4.5.dif ++++++
--- /var/tmp/diff_new_pack.Eg19fT/_old  2012-11-12 07:04:20.000000000 +0100
+++ /var/tmp/diff_new_pack.Eg19fT/_new  2012-11-12 07:04:20.000000000 +0100
@@ -1,6 +1,8 @@
---- memcached.c.orig   2012-04-02 20:24:27.715193171 -0400
-+++ memcached.c        2012-04-02 20:27:08.442183805 -0400
-@@ -2498,15 +2498,19 @@
+Index: memcached.c
+===================================================================
+--- memcached.c.orig
++++ memcached.c
+@@ -2498,15 +2498,19 @@ void append_stat(const char *name, ADD_S
  inline static void process_stats_detail(conn *c, const char *command) {
      assert(c != NULL);
  

++++++ memcached-autofoo.patch ++++++
--- /var/tmp/diff_new_pack.Eg19fT/_old  2012-11-12 07:04:20.000000000 +0100
+++ /var/tmp/diff_new_pack.Eg19fT/_new  2012-11-12 07:04:20.000000000 +0100
@@ -1,6 +1,8 @@
+Index: configure.ac
+===================================================================
 --- configure.ac.orig
 +++ configure.ac
-@@ -1,59 +1,15 @@
+@@ -1,61 +1,15 @@
 -AC_PREREQ(2.52)
 +AC_PREREQ([2.60])
  m4_include([version.m4])
@@ -55,11 +57,13 @@
 -])
 -
 -DETECT_SUNCC([CFLAGS="-mt $CFLAGS"], [])
+-AS_IF([test "$ICC" = "yes" -o "$GCC" = "yes"],
+-      [CFLAGS="$CFLAGS -pthread"])
 -
 -if test "$ICC" = "no"; then
 -   AC_PROG_CC_C99
 -fi
-+AM_INIT_AUTOMAKE([foreign -Wall -Wno-portability tar-pax no-dist-gzip dist-xz 
subdir-objects])
++AM_INIT_AUTOMAKE([foreign -Wall -Wno-portability tar-pax subdir-objects])
 +AC_CONFIG_HEADERS([config.h])
  
 +AC_PROG_CC_STDC
@@ -68,7 +72,7 @@
  AM_PROG_CC_C_O
  AC_PROG_INSTALL
  
-@@ -76,14 +32,11 @@ AC_DEFUN([AC_C_DETECT_SASL_CB_GETCONF],
+@@ -78,14 +32,11 @@ AC_DEFUN([AC_C_DETECT_SASL_CB_GETCONF],
  [
      AC_CACHE_CHECK([for SASL_CB_GETCONF],
          [ac_cv_c_sasl_cb_getconf],
@@ -86,7 +90,7 @@
          ])
      AS_IF([test "$ac_cv_c_sasl_cb_getconf" = "yes"],
            [AC_DEFINE([HAVE_SASL_CB_GETCONF], 1,
-@@ -170,23 +123,6 @@ fi
+@@ -168,23 +119,6 @@ fi
  AC_SUBST(PROFILER_FLAGS)
  
  
@@ -110,7 +114,7 @@
  # Issue 213: Search for clock_gettime to help people linking
  #            with a static version of libevent
  AC_SEARCH_LIBS(clock_gettime, rt)
-@@ -195,91 +131,7 @@ AC_SEARCH_LIBS(clock_gettime, rt)
+@@ -193,91 +127,7 @@ AC_SEARCH_LIBS(clock_gettime, rt)
  AC_SEARCH_LIBS(socket, socket)
  AC_SEARCH_LIBS(gethostbyname, nsl)
  
@@ -203,7 +207,7 @@
  
  dnl 
----------------------------------------------------------------------------
  
-@@ -308,14 +160,14 @@ dnl ************************************
+@@ -306,14 +156,14 @@ dnl ************************************
  AC_DEFUN([AC_HAVE_SASL_CALLBACK_FT],
  [AC_CACHE_CHECK(for sasl_callback_ft, ac_cv_has_sasl_callback_ft,
  [
@@ -221,7 +225,7 @@
      ac_cv_has_sasl_callback_ft=yes
    ],[
      ac_cv_has_sasl_callback_ft=no
-@@ -337,18 +189,15 @@ AC_DEFUN([AC_C_DETECT_UINT64_SUPPORT],
+@@ -335,18 +185,15 @@ AC_DEFUN([AC_C_DETECT_UINT64_SUPPORT],
  [
      AC_CACHE_CHECK([for print macros for integers (C99 section 7.8.1)],
          [ac_cv_c_uint64_support],
@@ -243,7 +247,7 @@
          ])
  ])
  
-@@ -367,12 +216,12 @@ dnl Check if the type socklen_t is defin
+@@ -365,12 +212,12 @@ dnl Check if the type socklen_t is defin
  AC_DEFUN([AC_C_SOCKLEN_T],
  [AC_CACHE_CHECK(for socklen_t, ac_cv_c_socklen_t,
  [
@@ -259,7 +263,7 @@
      ac_cv_c_socklen_t=yes
    ],[
      ac_cv_c_socklen_t=no
-@@ -411,35 +260,6 @@ fi
+@@ -409,35 +256,6 @@ fi
  
  AC_C_ENDIAN
  
@@ -295,7 +299,7 @@
  
  AC_CHECK_FUNCS(mlockall)
  AC_CHECK_FUNCS(getpagesizes)
-@@ -486,13 +306,13 @@ dnl These were added in 4.1.2, but 32bit
+@@ -484,13 +302,13 @@ dnl These were added in 4.1.2, but 32bit
  dnl lacks testable defines.
  have_gcc_atomics=no
  AC_MSG_CHECKING(for GCC atomics)
@@ -312,7 +316,7 @@
  AC_MSG_RESULT($have_gcc_atomics)
  
  dnl Check for the requirements for running memcached with less privileges
-@@ -529,29 +349,5 @@ AM_CONDITIONAL([BUILD_SPECIFICATIONS],
+@@ -527,29 +345,5 @@ AM_CONDITIONAL([BUILD_SPECIFICATIONS],
                 [test "x$enable_docs" != "xno" -a "x$XML2RFC" != "xno" -a 
"x$XSLTPROC" != "xno"])
  
  
@@ -342,6 +346,8 @@
 -
  AC_CONFIG_FILES(Makefile doc/Makefile)
  AC_OUTPUT
+Index: Makefile.am
+===================================================================
 --- Makefile.am.orig
 +++ Makefile.am
 @@ -1,3 +1,6 @@

++++++ memcached-use-endian_h.patch ++++++
--- /var/tmp/diff_new_pack.Eg19fT/_old  2012-11-12 07:04:20.000000000 +0100
+++ /var/tmp/diff_new_pack.Eg19fT/_new  2012-11-12 07:04:20.000000000 +0100
@@ -1,3 +1,5 @@
+Index: util.c
+===================================================================
 --- util.c.orig
 +++ util.c
 @@ -115,30 +115,3 @@ void vperror(const char *fmt, ...) {
@@ -31,6 +33,8 @@
 -}
 -#endif
 -
+Index: util.h
+===================================================================
 --- util.h.orig
 +++ util.h
 @@ -7,15 +7,16 @@

-- 
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to