Merge in updates for the pool library.
authorBrian Aker <brian@tangent.org>
Tue, 19 Apr 2011 21:30:45 +0000 (14:30 -0700)
committerBrian Aker <brian@tangent.org>
Tue, 19 Apr 2011 21:30:45 +0000 (14:30 -0700)
clients/memstat.c
libmemcached/include.am
libmemcached/memcached.c
libmemcached/memcached.h
libmemcached/util/ping.c [deleted file]
libmemcached/util/ping.cc [new file with mode: 0644]
libmemcached/util/pool.c [deleted file]
libmemcached/util/pool.cc [new file with mode: 0644]
libmemcached/util/version.c [deleted file]
libmemcached/util/version.cc [new file with mode: 0644]
tests/mem_functions.c

index 765e7ab7e4b0047dc80ebea010d9d728d8e17107..d35184588161f99860ec82f7d9627671009f1ba4 100644 (file)
@@ -79,10 +79,6 @@ static memcached_return_t stat_printer(memcached_server_instance_st instance,
 
 int main(int argc, char *argv[])
 {
-  memcached_return_t rc;
-  memcached_st *memc;
-  memcached_server_st *servers;
-
   options_parse(argc, argv);
   initialize_sockets();
 
@@ -100,10 +96,12 @@ int main(int argc, char *argv[])
     }
   }
 
-  memc= memcached_create(NULL);
+  memcached_st *memc= memcached_create(NULL);
+
+  memcached_server_st *servers= memcached_servers_parse(opt_servers);
+  free(opt_servers);
 
-  servers= memcached_servers_parse(opt_servers);
-  rc= memcached_server_push(memc, servers);
+  memcached_return_t rc= memcached_server_push(memc, servers);
   memcached_server_list_free(servers);
 
   if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS)
@@ -131,11 +129,9 @@ int main(int argc, char *argv[])
     rc= memcached_stat_execute(memc, stat_args, stat_printer, NULL);
   }
 
-  free(opt_servers);
-
   memcached_free(memc);
 
-  return rc == MEMCACHED_SUCCESS ? 0: -1;
+  return rc == MEMCACHED_SUCCESS ? EXIT_SUCCESS: EXIT_FAILURE;
 }
 
 static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat)
index 5a4b8b09ed0fd9cdb8e073af0f12272b69b024d5..496b7a9b2da8929067f8257a8a53fd0b7e4cb16a 100644 (file)
@@ -151,9 +151,9 @@ lib_LTLIBRARIES+= libmemcached/libmemcachedutil.la
 endif
 
 libmemcached_libmemcachedutil_la_SOURCES= \
-                                         libmemcached/util/ping.c \
-                                         libmemcached/util/pool.c \
-                                         libmemcached/util/version.c
+                                         libmemcached/util/ping.cc \
+                                         libmemcached/util/pool.cc \
+                                         libmemcached/util/version.cc
 libmemcached_libmemcachedutil_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION} ${PTHREAD_CFLAGS}
 libmemcached_libmemcachedutil_la_LIBADD= libmemcached/libmemcached.la
 libmemcached_libmemcachedutil_la_LDFLAGS= ${AM_LDFLAGS} ${PTHREAD_LIBS} -version-info ${MEMCACHED_UTIL_LIBRARY_VERSION}
index 3c583502adf0afc31ae59ea9bf3d5402472a0a17..c57b257734a093401375c5804e9bb9774870f346 100644 (file)
@@ -123,6 +123,7 @@ static inline bool _memcached_init(memcached_st *self)
   self->prefix_key= NULL;
   self->configure.initial_pool_size= 1;
   self->configure.max_pool_size= 1;
+  self->configure.version= -1;
   self->configure.filename= NULL;
 
   return true;
index 2f1caf2b74abb66795836cf6af4ede772b55b163..83072e9ae1e97dc95256b196c7f8435f0dd49558 100644 (file)
@@ -161,6 +161,7 @@ struct memcached_st {
   struct {
     uint32_t initial_pool_size;
     uint32_t max_pool_size;
+    int32_t version; // This is used by pool and others to determine if the memcached_st is out of date.
     struct memcached_array_st *filename;
   } configure;
   struct {
diff --git a/libmemcached/util/ping.c b/libmemcached/util/ping.c
deleted file mode 100644 (file)
index 3d5471a..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: connects to a host, and makes sure it is alive.
- *
- */
-
-#include "libmemcached/common.h"
-#include "libmemcached/memcached_util.h"
-
-
-bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_return_t *ret)
-{
-  memcached_return_t rc;
-  memcached_st memc, *memc_ptr;
-
-  memc_ptr= memcached_create(&memc);
-
-  rc= memcached_server_add(memc_ptr, hostname, port);
-
-  if (rc == MEMCACHED_SUCCESS)
-  {
-    rc= memcached_version(memc_ptr);
-  }
-
-  memcached_free(memc_ptr);
-
-  if (ret)
-  {
-    *ret= rc;
-  }
-
-  return rc == MEMCACHED_SUCCESS;
-}
diff --git a/libmemcached/util/ping.cc b/libmemcached/util/ping.cc
new file mode 100644 (file)
index 0000000..3d5471a
--- /dev/null
@@ -0,0 +1,38 @@
+/* LibMemcached
+ * Copyright (C) 2010 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: connects to a host, and makes sure it is alive.
+ *
+ */
+
+#include "libmemcached/common.h"
+#include "libmemcached/memcached_util.h"
+
+
+bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_return_t *ret)
+{
+  memcached_return_t rc;
+  memcached_st memc, *memc_ptr;
+
+  memc_ptr= memcached_create(&memc);
+
+  rc= memcached_server_add(memc_ptr, hostname, port);
+
+  if (rc == MEMCACHED_SUCCESS)
+  {
+    rc= memcached_version(memc_ptr);
+  }
+
+  memcached_free(memc_ptr);
+
+  if (ret)
+  {
+    *ret= rc;
+  }
+
+  return rc == MEMCACHED_SUCCESS;
+}
diff --git a/libmemcached/util/pool.c b/libmemcached/util/pool.c
deleted file mode 100644 (file)
index 948f765..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: connects to a host, and makes sure it is alive.
- *
- */
-
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/common.h"
-#include "libmemcached/memcached_util.h"
-
-#include <errno.h>
-#include <pthread.h>
-
-struct memcached_pool_st
-{
-  pthread_mutex_t mutex;
-  pthread_cond_t cond;
-  memcached_st *master;
-  memcached_st **mmc;
-  int firstfree;
-  uint32_t size;
-  uint32_t current_size;
-  bool _owns_master;
-  char *version;
-};
-
-static memcached_return_t mutex_enter(pthread_mutex_t *mutex)
-{
-  int ret;
-  do
-    ret= pthread_mutex_lock(mutex);
-  while (ret == -1 && errno == EINTR);
-
-  return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t mutex_exit(pthread_mutex_t *mutex)
-{
-  int ret;
-  do
-    ret= pthread_mutex_unlock(mutex);
-  while (ret == -1 && errno == EINTR);
-
-  return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
-}
-
-/**
- * Grow the connection pool by creating a connection structure and clone the
- * original memcached handle.
- */
-static int grow_pool(memcached_pool_st* pool)
-{
-  memcached_st *obj= calloc(1, sizeof(*obj));
-
-  if (obj == NULL)
-    return -1;
-
-  if (memcached_clone(obj, pool->master) == NULL)
-  {
-    free(obj);
-    return -1;
-  }
-
-  pool->mmc[++pool->firstfree] = obj;
-  pool->current_size++;
-
-  return EXIT_SUCCESS;
-}
-
-static inline memcached_pool_st *_pool_create(memcached_st* mmc, uint32_t initial, uint32_t max)
-{
-  memcached_pool_st* ret= NULL;
-
-  if (! initial || ! max || initial > max)
-  {
-    errno= EINVAL;
-    return NULL;
-  }
-
-  memcached_pool_st object= { .mutex = PTHREAD_MUTEX_INITIALIZER,
-    .cond= PTHREAD_COND_INITIALIZER,
-    .master= mmc,
-    .mmc= calloc(max, sizeof(memcached_st*)),
-    .firstfree= -1,
-    .size= max,
-    .current_size= 0,
-    ._owns_master= false};
-
-  if (object.mmc != NULL)
-  {
-    ret= (memcached_pool_st*)calloc(1, sizeof(memcached_pool_st));
-    if (ret == NULL)
-    {
-      free(object.mmc);
-      errno= ENOMEM; // Set this for the failed calloc
-      return NULL;
-    }
-
-    *ret= object;
-
-    /*
-      Try to create the initial size of the pool. An allocation failure at
-      this time is not fatal..
-    */
-    for (unsigned int ii= 0; ii < initial; ++ii)
-    {
-      if (grow_pool(ret) == -1)
-        break;
-    }
-  }
-
-  return ret;
-}
-
-memcached_pool_st *memcached_pool_create(memcached_st* mmc, uint32_t initial, uint32_t max)
-{
-  return _pool_create(mmc, initial, max);
-}
-
-memcached_pool_st * memcached_pool(const char *option_string, size_t option_string_length)
-{
-  memcached_pool_st *self;
-  memcached_st *memc= memcached(option_string, option_string_length);
-
-  if (! memc)
-    return NULL;
-
-  self= memcached_pool_create(memc, memc->configure.initial_pool_size, memc->configure.max_pool_size);
-  if (! self)
-  {
-    memcached_free(memc);
-    errno= ENOMEM;
-    return NULL;
-  }
-  errno= 0;
-
-  self->_owns_master= true;
-
-  return self;
-}
-
-memcached_st*  memcached_pool_destroy(memcached_pool_st* pool)
-{
-  if (! pool)
-    return NULL;
-
-  memcached_st *ret= pool->master;
-
-  for (int xx= 0; xx <= pool->firstfree; ++xx)
-  {
-    memcached_free(pool->mmc[xx]);
-    free(pool->mmc[xx]);
-    pool->mmc[xx] = NULL;
-  }
-
-  pthread_mutex_destroy(&pool->mutex);
-  pthread_cond_destroy(&pool->cond);
-  free(pool->mmc);
-  if (pool->_owns_master)
-  {
-    memcached_free(pool->master);
-    ret= NULL;
-  }
-  free(pool);
-
-  return ret;
-}
-
-memcached_st* memcached_pool_pop(memcached_pool_st* pool,
-                                 bool block,
-                                 memcached_return_t *rc)
-{
-  if (! pool || ! rc)
-  {
-    errno= EINVAL;
-    return NULL;
-  }
-
-  memcached_st *ret= NULL;
-  if ((*rc= mutex_enter(&pool->mutex)) != MEMCACHED_SUCCESS)
-  {
-    return NULL;
-  }
-
-  do
-  {
-    if (pool->firstfree > -1)
-    {
-      ret= pool->mmc[pool->firstfree--];
-    }
-    else if (pool->current_size == pool->size)
-    {
-      if (!block)
-      {
-        *rc= mutex_exit(&pool->mutex);
-        return NULL;
-      }
-
-      if (pthread_cond_wait(&pool->cond, &pool->mutex) == -1)
-      {
-        int err= errno;
-        mutex_exit(&pool->mutex);
-        errno= err;
-        *rc= MEMCACHED_ERRNO;
-        return NULL;
-      }
-    }
-    else if (grow_pool(pool) == -1)
-    {
-      *rc= mutex_exit(&pool->mutex);
-      return NULL;
-    }
-  }
-  while (ret == NULL);
-
-  *rc= mutex_exit(&pool->mutex);
-
-  return ret;
-}
-
-memcached_return_t memcached_pool_push(memcached_pool_st* pool,
-                                       memcached_st *mmc)
-{
-  if (! pool)
-    return MEMCACHED_INVALID_ARGUMENTS;
-
-  memcached_return_t rc= mutex_enter(&pool->mutex);
-
-  if (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  char* version= memcached_get_user_data(mmc);
-  /* Someone updated the behavior on the object.. */
-  if (version != pool->version)
-  {
-    memcached_free(mmc);
-    memset(mmc, 0, sizeof(*mmc));
-    if (memcached_clone(mmc, pool->master) == NULL)
-    {
-      rc= MEMCACHED_SOME_ERRORS;
-    }
-  }
-
-  pool->mmc[++pool->firstfree]= mmc;
-
-  if (pool->firstfree == 0 && pool->current_size == pool->size)
-  {
-    /* we might have people waiting for a connection.. wake them up :-) */
-    pthread_cond_broadcast(&pool->cond);
-  }
-
-  memcached_return_t rval= mutex_exit(&pool->mutex);
-  if (rc == MEMCACHED_SOME_ERRORS)
-    return rc;
-
-  return rval;
-}
-
-
-memcached_return_t memcached_pool_behavior_set(memcached_pool_st *pool,
-                                               memcached_behavior_t flag,
-                                               uint64_t data)
-{
-  if (! pool)
-    return MEMCACHED_INVALID_ARGUMENTS;
-
-  memcached_return_t rc= mutex_enter(&pool->mutex);
-  if (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  /* update the master */
-  rc= memcached_behavior_set(pool->master, flag, data);
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    mutex_exit(&pool->mutex);
-    return rc;
-  }
-
-  ++pool->version;
-  memcached_set_user_data(pool->master, pool->version);
-  /* update the clones */
-  for (int xx= 0; xx <= pool->firstfree; ++xx)
-  {
-    rc= memcached_behavior_set(pool->mmc[xx], flag, data);
-    if (rc == MEMCACHED_SUCCESS)
-    {
-      memcached_set_user_data(pool->mmc[xx], pool->version);
-    }
-    else
-    {
-      memcached_free(pool->mmc[xx]);
-      memset(pool->mmc[xx], 0, sizeof(*pool->mmc[xx]));
-
-      if (memcached_clone(pool->mmc[xx], pool->master) == NULL)
-      {
-        /* I'm not sure what to do in this case.. this would happen
-          if we fail to push the server list inside the client..
-          I should add a testcase for this, but I believe the following
-          would work, except that you would add a hole in the pool list..
-          in theory you could end up with an empty pool....
-        */
-        free(pool->mmc[xx]);
-        pool->mmc[xx]= NULL;
-      }
-    }
-  }
-
-  return mutex_exit(&pool->mutex);
-}
-
-memcached_return_t memcached_pool_behavior_get(memcached_pool_st *pool,
-                                               memcached_behavior_t flag,
-                                               uint64_t *value)
-{
-  if (! pool)
-    return MEMCACHED_INVALID_ARGUMENTS;
-
-  memcached_return_t rc= mutex_enter(&pool->mutex);
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  *value= memcached_behavior_get(pool->master, flag);
-
-  return mutex_exit(&pool->mutex);
-}
diff --git a/libmemcached/util/pool.cc b/libmemcached/util/pool.cc
new file mode 100644 (file)
index 0000000..17cff07
--- /dev/null
@@ -0,0 +1,392 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ *
+ *      * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *
+ *      * Redistributions in binary form must reproduce the above
+ *  copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the
+ *  distribution.
+ *
+ *      * The names of its contributors may not be used to endorse or
+ *  promote products derived from this software without specific prior
+ *  written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+#include <libmemcached/memcached_util.h>
+
+#include <cassert>
+#include <cerrno>
+#include <pthread.h>
+#include <memory>
+
+static bool grow_pool(memcached_pool_st* pool);
+
+struct memcached_pool_st
+{
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
+  memcached_st *master;
+  memcached_st **server_pool;
+  int firstfree;
+  const uint32_t size;
+  uint32_t current_size;
+  bool _owns_master;
+
+  memcached_pool_st(memcached_st *master_arg, size_t max_arg) :
+    master(master_arg),
+    server_pool(NULL),
+    firstfree(-1),
+    size(max_arg),
+    current_size(0),
+    _owns_master(false)
+  {
+    pthread_mutex_init(&mutex, NULL);
+    pthread_cond_init(&cond, NULL);
+  }
+
+  bool init(uint32_t initial)
+  {
+    server_pool= new (std::nothrow) memcached_st *[size];
+    if (not server_pool)
+      return false;
+
+    /*
+      Try to create the initial size of the pool. An allocation failure at
+      this time is not fatal..
+    */
+    for (unsigned int x= 0; x < initial; ++x)
+    {
+      if (not grow_pool(this))
+        break;
+    }
+
+    return true;
+  }
+
+  ~memcached_pool_st()
+  {
+    for (int x= 0; x <= firstfree; ++x)
+    {
+      memcached_free(server_pool[x]);
+      server_pool[x] = NULL;
+    }
+
+    pthread_mutex_destroy(&mutex);
+    pthread_cond_destroy(&cond);
+    delete [] server_pool;
+    if (_owns_master)
+    {
+      memcached_free(master);
+    }
+  }
+
+  void increment_version()
+  {
+    ++master->configure.version;
+  }
+
+  bool compare_version(const memcached_st *arg) const
+  {
+    return (arg->configure.version == version());
+  }
+
+  int32_t version() const
+  {
+    return master->configure.version;
+  }
+};
+
+static memcached_return_t mutex_enter(pthread_mutex_t *mutex)
+{
+  int ret;
+  do
+  {
+    ret= pthread_mutex_lock(mutex);
+  } while (ret == -1 && errno == EINTR);
+
+  return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t mutex_exit(pthread_mutex_t *mutex)
+{
+  int ret;
+  do
+  {
+    ret= pthread_mutex_unlock(mutex);
+  } while (ret == -1 && errno == EINTR);
+
+  return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
+}
+
+/**
+ * Grow the connection pool by creating a connection structure and clone the
+ * original memcached handle.
+ */
+static bool grow_pool(memcached_pool_st* pool)
+{
+  memcached_st *obj;
+  if (not (obj= memcached_clone(NULL, pool->master)))
+  {
+    return false;
+  }
+
+  pool->server_pool[++pool->firstfree]= obj;
+  pool->current_size++;
+  obj->configure.version= pool->version();
+
+  return true;
+}
+
+static inline memcached_pool_st *_pool_create(memcached_st* master, uint32_t initial, uint32_t max)
+{
+  if (! initial || ! max || initial > max)
+  {
+    errno= EINVAL;
+    return NULL;
+  }
+
+  memcached_pool_st *object= new (std::nothrow) memcached_pool_st(master, max);
+  if (not object)
+  {
+    errno= ENOMEM; // Set this for the failed calloc
+    return NULL;
+  }
+
+  /*
+    Try to create the initial size of the pool. An allocation failure at
+    this time is not fatal..
+  */
+  if (not object->init(initial))
+  {
+    delete object;
+    return NULL;
+  }
+
+  return object;
+}
+
+memcached_pool_st *memcached_pool_create(memcached_st* master, uint32_t initial, uint32_t max)
+{
+  return _pool_create(master, initial, max);
+}
+
+memcached_pool_st * memcached_pool(const char *option_string, size_t option_string_length)
+{
+  memcached_st *memc= memcached(option_string, option_string_length);
+
+  if (not memc)
+    return NULL;
+
+  memcached_pool_st *self;
+  self= memcached_pool_create(memc, memc->configure.initial_pool_size, memc->configure.max_pool_size);
+  if (not self)
+  {
+    memcached_free(memc);
+    errno= ENOMEM;
+    return NULL;
+  }
+  errno= 0;
+
+  self->_owns_master= true;
+
+  return self;
+}
+
+memcached_st*  memcached_pool_destroy(memcached_pool_st* pool)
+{
+  if (not pool)
+    return NULL;
+
+  // Legacy that we return the original structure
+  memcached_st *ret= NULL;
+  if (pool->_owns_master)
+  { }
+  else
+  {
+    ret= pool->master;
+  }
+
+  delete pool;
+
+  return ret;
+}
+
+memcached_st* memcached_pool_pop(memcached_pool_st* pool,
+                                 bool block,
+                                 memcached_return_t *rc)
+{
+  assert(pool);
+  assert(rc);
+  if (not pool ||  not rc)
+  {
+    errno= EINVAL;
+    return NULL;
+  }
+
+  if ((*rc= mutex_enter(&pool->mutex)) != MEMCACHED_SUCCESS)
+  {
+    return NULL;
+  }
+
+  memcached_st *ret= NULL;
+  do
+  {
+    if (pool->firstfree > -1)
+    {
+      ret= pool->server_pool[pool->firstfree--];
+    }
+    else if (pool->current_size == pool->size)
+    {
+      if (not block)
+      {
+        *rc= mutex_exit(&pool->mutex); // this should be a different error
+        return NULL;
+      }
+
+      if (pthread_cond_wait(&pool->cond, &pool->mutex) == -1)
+      {
+        int err= errno;
+        mutex_exit(&pool->mutex);
+        errno= err;
+        *rc= MEMCACHED_ERRNO;
+        return NULL;
+      }
+    }
+    else if (not grow_pool(pool))
+    {
+      (void)mutex_exit(&pool->mutex);
+      *rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+      return NULL;
+    }
+  }
+  while (ret == NULL);
+
+  *rc= mutex_exit(&pool->mutex);
+
+  return ret;
+}
+
+memcached_return_t memcached_pool_push(memcached_pool_st* pool, memcached_st *released)
+{
+  if (not pool)
+    return MEMCACHED_INVALID_ARGUMENTS;
+
+  memcached_return_t rc= mutex_enter(&pool->mutex);
+
+  if (rc != MEMCACHED_SUCCESS)
+    return rc;
+
+  /* Someone updated the behavior on the object.. */
+  if (not pool->compare_version(released))
+  {
+    memcached_free(released);
+    if (not (released= memcached_clone(NULL, pool->master)))
+    {
+      rc= MEMCACHED_SOME_ERRORS;
+    }
+  }
+
+  pool->server_pool[++pool->firstfree]= released;
+
+  if (pool->firstfree == 0 && pool->current_size == pool->size)
+  {
+    /* we might have people waiting for a connection.. wake them up :-) */
+    pthread_cond_broadcast(&pool->cond);
+  }
+
+  memcached_return_t rval= mutex_exit(&pool->mutex);
+  if (rc == MEMCACHED_SOME_ERRORS)
+    return rc;
+
+  return rval;
+}
+
+
+memcached_return_t memcached_pool_behavior_set(memcached_pool_st *pool,
+                                               memcached_behavior_t flag,
+                                               uint64_t data)
+{
+  if (not pool)
+    return MEMCACHED_INVALID_ARGUMENTS;
+
+  memcached_return_t rc= mutex_enter(&pool->mutex);
+  if (rc != MEMCACHED_SUCCESS)
+    return rc;
+
+  /* update the master */
+  rc= memcached_behavior_set(pool->master, flag, data);
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    mutex_exit(&pool->mutex);
+    return rc;
+  }
+
+  pool->increment_version();
+  /* update the clones */
+  for (int xx= 0; xx <= pool->firstfree; ++xx)
+  {
+    rc= memcached_behavior_set(pool->server_pool[xx], flag, data);
+    if (rc == MEMCACHED_SUCCESS)
+    {
+      pool->server_pool[xx]->configure.version= pool->version();
+    }
+    else
+    {
+      memcached_free(pool->server_pool[xx]);
+      if (not (pool->server_pool[xx]= memcached_clone(NULL, pool->master)))
+      {
+        /* I'm not sure what to do in this case.. this would happen
+          if we fail to push the server list inside the client..
+          I should add a testcase for this, but I believe the following
+          would work, except that you would add a hole in the pool list..
+          in theory you could end up with an empty pool....
+        */
+      }
+    }
+  }
+
+  return mutex_exit(&pool->mutex);
+}
+
+memcached_return_t memcached_pool_behavior_get(memcached_pool_st *pool,
+                                               memcached_behavior_t flag,
+                                               uint64_t *value)
+{
+  if (! pool)
+    return MEMCACHED_INVALID_ARGUMENTS;
+
+  memcached_return_t rc= mutex_enter(&pool->mutex);
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    return rc;
+  }
+
+  *value= memcached_behavior_get(pool->master, flag);
+
+  return mutex_exit(&pool->mutex);
+}
diff --git a/libmemcached/util/version.c b/libmemcached/util/version.c
deleted file mode 100644 (file)
index a0b6925..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: connect to all hosts, and make sure they meet a minimum version
- *
- */
-
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/common.h"
-#include "libmemcached/memcached_util.h"
-
-struct local_context
-{
-  uint8_t major_version;
-  uint8_t minor_version;
-  uint8_t micro_version;
-
-  bool truth;
-};
-
-static memcached_return_t check_server_version(const memcached_st *ptr,
-                                               const memcached_server_st *instance,
-                                               void *context)
-{
-  /* Do Nothing */
-  struct local_context *check= (struct local_context *)context;
-  (void)ptr;
-
-  if (instance->major_version != UINT8_MAX &&
-      instance->major_version >= check->major_version &&
-      instance->minor_version >= check->minor_version &&
-      instance->micro_version >= check->micro_version )
-  {
-    return MEMCACHED_SUCCESS;
-  }
-
-  check->truth= false;
-
-  return MEMCACHED_FAILURE;
-}
-
-bool libmemcached_util_version_check(memcached_st *memc,
-                                     uint8_t major_version,
-                                     uint8_t minor_version,
-                                     uint8_t micro_version)
-{
-  memcached_server_fn callbacks[1];
-  memcached_return_t rc= memcached_version(memc);
-
-  if (rc != MEMCACHED_SUCCESS)
-    return false;
-
-  struct local_context check= { .major_version= major_version, .minor_version= minor_version, .micro_version= micro_version, .truth= true };
-
-  callbacks[0]= check_server_version;
-  memcached_server_cursor(memc, callbacks, (void *)&check,  1);
-
-  return check.truth;
-}
diff --git a/libmemcached/util/version.cc b/libmemcached/util/version.cc
new file mode 100644 (file)
index 0000000..761cbbf
--- /dev/null
@@ -0,0 +1,63 @@
+/* LibMemcached
+ * Copyright (C) 2010 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: connect to all hosts, and make sure they meet a minimum version
+ *
+ */
+
+/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+#include "libmemcached/common.h"
+#include "libmemcached/memcached_util.h"
+
+struct local_context
+{
+  uint8_t major_version;
+  uint8_t minor_version;
+  uint8_t micro_version;
+
+  bool truth;
+};
+
+static memcached_return_t check_server_version(const memcached_st *ptr,
+                                               const memcached_server_st *instance,
+                                               void *context)
+{
+  /* Do Nothing */
+  struct local_context *check= (struct local_context *)context;
+  (void)ptr;
+
+  if (instance->major_version != UINT8_MAX &&
+      instance->major_version >= check->major_version &&
+      instance->minor_version >= check->minor_version &&
+      instance->micro_version >= check->micro_version )
+  {
+    return MEMCACHED_SUCCESS;
+  }
+
+  check->truth= false;
+
+  return MEMCACHED_FAILURE;
+}
+
+bool libmemcached_util_version_check(memcached_st *memc,
+                                     uint8_t major_version,
+                                     uint8_t minor_version,
+                                     uint8_t micro_version)
+{
+  memcached_server_fn callbacks[1];
+  memcached_return_t rc= memcached_version(memc);
+
+  if (rc != MEMCACHED_SUCCESS)
+    return false;
+
+  struct local_context check= { major_version, minor_version, micro_version, true };
+
+  callbacks[0]= check_server_version;
+  memcached_server_cursor(memc, callbacks, (void *)&check,  1);
+
+  return check.truth;
+}
index a5e28e6949c0182f7d6b31a294e4a94cd018e290..1ab8d6a3327eebc1ccb2d4b50636f930db486d98 100644 (file)
@@ -4310,6 +4310,7 @@ static void* connection_release(void *arg)
   } *resource= arg;
 
   usleep(250);
+  // Release all of the memc we are holding
   assert(memcached_pool_push(resource->pool, resource->mmc) == MEMCACHED_SUCCESS);
   return arg;
 }
@@ -4322,6 +4323,7 @@ static test_return_t connection_pool_test(memcached_st *memc)
   memcached_st *mmc[POOL_SIZE];
   memcached_return_t rc;
 
+  // Fill up our array that we will store the memc that are in the pool
   for (size_t x= 0; x < POOL_SIZE; ++x)
   {
     mmc[x]= memcached_pool_pop(pool, false, &rc);
@@ -4329,6 +4331,7 @@ static test_return_t connection_pool_test(memcached_st *memc)
     test_true(rc == MEMCACHED_SUCCESS);
   }
 
+  // All memc should be gone
   test_true(memcached_pool_pop(pool, false, &rc) == NULL);
   test_true(rc == MEMCACHED_SUCCESS);
 
@@ -4337,11 +4340,12 @@ static test_return_t connection_pool_test(memcached_st *memc)
     memcached_pool_st* pool;
     memcached_st* mmc;
   } item= { .pool = pool, .mmc = mmc[9] };
+
   pthread_create(&tid, NULL, connection_release, &item);
   mmc[9]= memcached_pool_pop(pool, true, &rc);
   test_true(rc == MEMCACHED_SUCCESS);
   pthread_join(tid, NULL);
-  test_true(mmc[9] == item.mmc);
+  test_true(mmc[9]);
   const char *key= "key";
   size_t keylen= strlen(key);