Merge in conversion to C++.
authorBrian Aker <brian@tangent.org>
Thu, 28 Apr 2011 00:28:00 +0000 (17:28 -0700)
committerBrian Aker <brian@tangent.org>
Thu, 28 Apr 2011 00:28:00 +0000 (17:28 -0700)
173 files changed:
Makefile.am
clients/execute.c [deleted file]
clients/execute.cc [new file with mode: 0644]
clients/execute.h
clients/generator.c [deleted file]
clients/generator.cc [new file with mode: 0644]
clients/generator.h
clients/include.am
clients/memcapable.c [deleted file]
clients/memcapable.cc [new file with mode: 0644]
clients/memcat.c [deleted file]
clients/memcat.cc [new file with mode: 0644]
clients/memcp.c [deleted file]
clients/memcp.cc [new file with mode: 0644]
clients/memdump.c [deleted file]
clients/memdump.cc [new file with mode: 0644]
clients/memerror.c [deleted file]
clients/memerror.cc [new file with mode: 0644]
clients/memflush.c [deleted file]
clients/memflush.cc [new file with mode: 0644]
clients/memrm.c [deleted file]
clients/memrm.cc [new file with mode: 0644]
clients/memslap.c [deleted file]
clients/memslap.cc [new file with mode: 0644]
clients/memstat.c [deleted file]
clients/memstat.cc [new file with mode: 0644]
clients/ms_conn.h
clients/ms_memslap.h
clients/ms_setting.h
clients/utilities.c [deleted file]
clients/utilities.cc [new file with mode: 0644]
clients/utilities.h
configure.ac
example/include.am
libhashkit/algorithm.c [deleted file]
libhashkit/algorithm.cc [new file with mode: 0644]
libhashkit/behavior.c [deleted file]
libhashkit/behavior.cc [new file with mode: 0644]
libhashkit/common.h
libhashkit/crc32.c [deleted file]
libhashkit/crc32.cc [new file with mode: 0644]
libhashkit/digest.c [deleted file]
libhashkit/digest.cc [new file with mode: 0644]
libhashkit/fnv.c [deleted file]
libhashkit/fnv.cc [new file with mode: 0644]
libhashkit/function.c [deleted file]
libhashkit/function.cc [new file with mode: 0644]
libhashkit/hashkit.c [deleted file]
libhashkit/hashkit.cc [new file with mode: 0644]
libhashkit/hashkit.h
libhashkit/hashkit.hpp [new file with mode: 0644]
libhashkit/hsieh.c [deleted file]
libhashkit/hsieh.cc [new file with mode: 0644]
libhashkit/include.am
libhashkit/jenkins.c [deleted file]
libhashkit/jenkins.cc [new file with mode: 0644]
libhashkit/ketama.c [deleted file]
libhashkit/ketama.cc [new file with mode: 0644]
libhashkit/md5.c [deleted file]
libhashkit/md5.cc [new file with mode: 0644]
libhashkit/murmur.c [deleted file]
libhashkit/murmur.cc [new file with mode: 0644]
libhashkit/one_at_a_time.c [deleted file]
libhashkit/one_at_a_time.cc [new file with mode: 0644]
libhashkit/str_algorithm.c [deleted file]
libhashkit/str_algorithm.cc [new file with mode: 0644]
libhashkit/strerror.c [deleted file]
libhashkit/strerror.cc [new file with mode: 0644]
libhashkit/visibility.h
libmemcached/allocators.c [deleted file]
libmemcached/allocators.cc [new file with mode: 0644]
libmemcached/allocators.h
libmemcached/analyze.c [deleted file]
libmemcached/analyze.cc [new file with mode: 0644]
libmemcached/auto.c [deleted file]
libmemcached/auto.cc [new file with mode: 0644]
libmemcached/auto.h
libmemcached/behavior.c [deleted file]
libmemcached/behavior.cc [new file with mode: 0644]
libmemcached/byteorder.c [deleted file]
libmemcached/byteorder.cc [new file with mode: 0644]
libmemcached/byteorder.h
libmemcached/callback.c [deleted file]
libmemcached/callback.cc [new file with mode: 0644]
libmemcached/callback.h
libmemcached/common.h
libmemcached/connect.c [deleted file]
libmemcached/connect.cc [new file with mode: 0644]
libmemcached/delete.c [deleted file]
libmemcached/delete.cc [new file with mode: 0644]
libmemcached/delete.h
libmemcached/do.c [deleted file]
libmemcached/do.cc [new file with mode: 0644]
libmemcached/dump.c [deleted file]
libmemcached/dump.cc [new file with mode: 0644]
libmemcached/error.cc
libmemcached/flush.c [deleted file]
libmemcached/flush.cc [new file with mode: 0644]
libmemcached/flush.h
libmemcached/flush_buffers.c [deleted file]
libmemcached/flush_buffers.cc [new file with mode: 0644]
libmemcached/flush_buffers.h
libmemcached/get.c [deleted file]
libmemcached/get.cc [new file with mode: 0644]
libmemcached/hash.c [deleted file]
libmemcached/hash.cc [new file with mode: 0644]
libmemcached/hosts.c [deleted file]
libmemcached/hosts.cc [new file with mode: 0644]
libmemcached/include.am
libmemcached/initialize_query.cc
libmemcached/internal.h
libmemcached/io.c [deleted file]
libmemcached/io.cc [new file with mode: 0644]
libmemcached/io.h
libmemcached/key.c [deleted file]
libmemcached/key.cc [new file with mode: 0644]
libmemcached/memcached.c [deleted file]
libmemcached/memcached.cc [new file with mode: 0644]
libmemcached/memcached.h
libmemcached/memcached.hpp
libmemcached/memcached/protocol_binary.h
libmemcached/options/context.h
libmemcached/parse.c [deleted file]
libmemcached/parse.cc [new file with mode: 0644]
libmemcached/protocol/ascii_handler.c
libmemcached/protocol/ascii_handler.h
libmemcached/protocol/binary_handler.c
libmemcached/protocol/binary_handler.h
libmemcached/protocol/common.h
libmemcached/protocol/include.am [new file with mode: 0644]
libmemcached/purge.c [deleted file]
libmemcached/purge.cc [new file with mode: 0644]
libmemcached/quit.c [deleted file]
libmemcached/quit.cc [new file with mode: 0644]
libmemcached/quit.h
libmemcached/response.c [deleted file]
libmemcached/response.cc [new file with mode: 0644]
libmemcached/response.h
libmemcached/result.c [deleted file]
libmemcached/result.cc [new file with mode: 0644]
libmemcached/return.h
libmemcached/server.c [deleted file]
libmemcached/server.cc [new file with mode: 0644]
libmemcached/server_list.c [deleted file]
libmemcached/server_list.cc [new file with mode: 0644]
libmemcached/stats.c [deleted file]
libmemcached/stats.cc [new file with mode: 0644]
libmemcached/storage.c [deleted file]
libmemcached/storage.cc [new file with mode: 0644]
libmemcached/strerror.c [deleted file]
libmemcached/strerror.cc [new file with mode: 0644]
libmemcached/string.c [deleted file]
libmemcached/string.cc [new file with mode: 0644]
libmemcached/string.h
libmemcached/types.h
libmemcached/util/include.am [new file with mode: 0644]
libmemcached/util/version.cc
libmemcached/verbosity.c [deleted file]
libmemcached/verbosity.cc [new file with mode: 0644]
libmemcached/verbosity.h
libmemcached/version.c [deleted file]
libmemcached/version.cc [new file with mode: 0644]
libmemcached/version.h
libmemcached/visibility.h
libtest/test.c
libtest/test.h
tests/atomsmasher.c
tests/hash_plus.cc
tests/include.am
tests/libmemcached_world.h
tests/mem_functions.c
tests/plus.cpp
tests/string.cc

index 80b2c03eaf130b9b3d84725f0bcb0c028d5c3215..2c2760160a862144f2541861679a0054adaafcd9 100644 (file)
@@ -35,6 +35,8 @@ EXTRA_DIST= \
 
 include libtest/include.am
 include libmemcached/include.am
+include libmemcached/protocol/include.am
+include libmemcached/util/include.am
 include clients/include.am
 include libhashkit/include.am
 include tests/include.am
@@ -93,6 +95,4 @@ lcov-clean: clean
        find . -name '*.gcno' | xargs rm -f
        find . -name '*.gcda' | xargs rm -f
 
-CLEANFILES+= config/top.h
-
-
+DISTCLEANFILES+= config/top.h
diff --git a/clients/execute.c b/clients/execute.c
deleted file mode 100644 (file)
index 0beaae4..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- */
-
-/*
-  Execute a memcached_set() a set of pairs.
-  Return the number of rows set.
-*/
-
-#include "config.h"
-#include "execute.h"
-
-unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of)
-{
-  memcached_return_t rc;
-  unsigned int x;
-  unsigned int pairs_sent;
-
-  for (x= 0, pairs_sent= 0; x < number_of; x++)
-  {
-    rc= memcached_set(memc, pairs[x].key, pairs[x].key_length,
-                      pairs[x].value, pairs[x].value_length,
-                      0, 0);
-    if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
-      fprintf(stderr, "Failured on insert of %.*s\n",
-              (unsigned int)pairs[x].key_length, pairs[x].key);
-    else
-      pairs_sent++;
-  }
-
-  return pairs_sent;
-}
-
-/*
-  Execute a memcached_get() on a set of pairs.
-  Return the number of rows retrieved.
-*/
-unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of)
-{
-  memcached_return_t rc;
-  unsigned int x;
-  unsigned int retrieved;
-
-
-  for (retrieved= 0,x= 0; x < number_of; x++)
-  {
-    char *value;
-    size_t value_length;
-    uint32_t flags;
-    unsigned int fetch_key;
-
-    fetch_key= (unsigned int)((unsigned int)random() % number_of);
-
-    value= memcached_get(memc, pairs[fetch_key].key, pairs[fetch_key].key_length,
-                         &value_length, &flags, &rc);
-
-    if (rc != MEMCACHED_SUCCESS)
-      fprintf(stderr, "Failured on read of %.*s\n",
-              (unsigned int)pairs[fetch_key].key_length, pairs[fetch_key].key);
-    else
-      retrieved++;
-
-    free(value);
-  }
-
-  return retrieved;
-}
-
-/**
- * Callback function to count the number of results
- */
-static memcached_return_t callback_counter(const memcached_st *ptr,
-                                           memcached_result_st *result,
-                                           void *context)
-{
-  (void)ptr;
-  (void)result;
-  unsigned int *counter= (unsigned int *)context;
-  *counter= *counter + 1;
-
-  return MEMCACHED_SUCCESS;
-}
-
-/**
- * Try to run a large mget to get all of the keys
- * @param memc memcached handle
- * @param keys the keys to get
- * @param key_length the length of the keys
- * @param number_of the number of keys to try to get
- * @return the number of keys received
- */
-unsigned int execute_mget(memcached_st *memc,
-                          const char * const *keys,
-                          size_t *key_length,
-                          unsigned int number_of)
-{
-  unsigned int retrieved= 0;
-  memcached_execute_fn callbacks[1]= { [0]= &callback_counter };
-  memcached_return_t rc;
-  rc= memcached_mget_execute(memc, keys, key_length,
-                             (size_t)number_of, callbacks, &retrieved, 1);
-
-  if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_NOTFOUND ||
-          rc == MEMCACHED_BUFFERED || rc == MEMCACHED_END)
-  {
-    rc= memcached_fetch_execute(memc, callbacks, (void *)&retrieved, 1);
-    if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_END)
-    {
-      fprintf(stderr, "Failed to execute mget: %s\n",
-              memcached_strerror(memc, rc));
-      memcached_quit(memc);
-      return 0;
-    }
-  }
-  else
-  {
-    fprintf(stderr, "Failed to execute mget: %s\n",
-            memcached_strerror(memc, rc));
-    memcached_quit(memc);
-    return 0;
-  }
-
-  return retrieved;
-}
diff --git a/clients/execute.cc b/clients/execute.cc
new file mode 100644 (file)
index 0000000..7f89f77
--- /dev/null
@@ -0,0 +1,131 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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:
+ *
+ */
+
+/*
+  Execute a memcached_set() a set of pairs.
+  Return the number of rows set.
+*/
+
+#include "config.h"
+#include "execute.h"
+
+unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of)
+{
+  memcached_return_t rc;
+  unsigned int x;
+  unsigned int pairs_sent;
+
+  for (x= 0, pairs_sent= 0; x < number_of; x++)
+  {
+    rc= memcached_set(memc, pairs[x].key, pairs[x].key_length,
+                      pairs[x].value, pairs[x].value_length,
+                      0, 0);
+    if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
+      fprintf(stderr, "Failured on insert of %.*s\n",
+              (unsigned int)pairs[x].key_length, pairs[x].key);
+    else
+      pairs_sent++;
+  }
+
+  return pairs_sent;
+}
+
+/*
+  Execute a memcached_get() on a set of pairs.
+  Return the number of rows retrieved.
+*/
+unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of)
+{
+  memcached_return_t rc;
+  unsigned int x;
+  unsigned int retrieved;
+
+
+  for (retrieved= 0,x= 0; x < number_of; x++)
+  {
+    char *value;
+    size_t value_length;
+    uint32_t flags;
+    unsigned int fetch_key;
+
+    fetch_key= (unsigned int)((unsigned int)random() % number_of);
+
+    value= memcached_get(memc, pairs[fetch_key].key, pairs[fetch_key].key_length,
+                         &value_length, &flags, &rc);
+
+    if (rc != MEMCACHED_SUCCESS)
+      fprintf(stderr, "Failured on read of %.*s\n",
+              (unsigned int)pairs[fetch_key].key_length, pairs[fetch_key].key);
+    else
+      retrieved++;
+
+    free(value);
+  }
+
+  return retrieved;
+}
+
+/**
+ * Callback function to count the number of results
+ */
+static memcached_return_t callback_counter(const memcached_st *ptr,
+                                           memcached_result_st *result,
+                                           void *context)
+{
+  (void)ptr;
+  (void)result;
+  unsigned int *counter= (unsigned int *)context;
+  *counter= *counter + 1;
+
+  return MEMCACHED_SUCCESS;
+}
+
+/**
+ * Try to run a large mget to get all of the keys
+ * @param memc memcached handle
+ * @param keys the keys to get
+ * @param key_length the length of the keys
+ * @param number_of the number of keys to try to get
+ * @return the number of keys received
+ */
+unsigned int execute_mget(memcached_st *memc,
+                          const char * const *keys,
+                          size_t *key_length,
+                          unsigned int number_of)
+{
+  unsigned int retrieved= 0;
+  memcached_execute_fn callbacks[]= { callback_counter };
+  memcached_return_t rc;
+  rc= memcached_mget_execute(memc, keys, key_length,
+                             (size_t)number_of, callbacks, &retrieved, 1);
+
+  if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_NOTFOUND ||
+          rc == MEMCACHED_BUFFERED || rc == MEMCACHED_END)
+  {
+    rc= memcached_fetch_execute(memc, callbacks, (void *)&retrieved, 1);
+    if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_END)
+    {
+      fprintf(stderr, "Failed to execute mget: %s\n",
+              memcached_strerror(memc, rc));
+      memcached_quit(memc);
+      return 0;
+    }
+  }
+  else
+  {
+    fprintf(stderr, "Failed to execute mget: %s\n",
+            memcached_strerror(memc, rc));
+    memcached_quit(memc);
+    return 0;
+  }
+
+  return retrieved;
+}
index 176c6fff81d6ebe82aaafc318a1f92538ddae927..05678c4df27b96915f36e64ea33443842285a012 100644 (file)
@@ -9,17 +9,22 @@
  *
  */
 
-#ifndef CLIENTS_EXECUTE_H
-#define CLIENTS_EXECUTE_H
+#pragma once 
 
 #include <stdio.h>
 
 #include "libmemcached/memcached.h"
-#include "generator.h"
+#include "clients/generator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of);
 unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of);
 unsigned int execute_mget(memcached_st *memc, const char * const *keys, size_t *key_length,
                           unsigned int number_of);
-#endif
 
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/clients/generator.c b/clients/generator.c
deleted file mode 100644 (file)
index 80b398b..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "generator.h"
-
-/* Use this for string generation */
-static const char ALPHANUMERICS[]=
-  "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
-
-#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
-
-static size_t get_alpha_num(void)
-{
-  return (size_t)random() % ALPHANUMERICS_SIZE;
-}
-
-static void get_random_string(char *buffer, size_t size)
-{
-  char *buffer_ptr= buffer;
-
-  while (--size)
-    *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
-  *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
-}
-
-void pairs_free(pairs_st *pairs)
-{
-  uint32_t x;
-
-  if (! pairs)
-    return;
-
-  /* We free until we hit the null pair we stores during creation */
-  for (x= 0; pairs[x].key; x++)
-  {
-    free(pairs[x].key);
-    if (pairs[x].value)
-      free(pairs[x].value);
-  }
-
-  free(pairs);
-}
-
-pairs_st *pairs_generate(uint64_t number_of, size_t value_length)
-{
-  unsigned int x;
-  pairs_st *pairs;
-
-  pairs= (pairs_st*)calloc((size_t)number_of + 1, sizeof(pairs_st));
-
-  if (!pairs)
-    goto error;
-
-  for (x= 0; x < number_of; x++)
-  {
-    pairs[x].key= (char *)calloc(100, sizeof(char));
-    if (!pairs[x].key)
-      goto error;
-    get_random_string(pairs[x].key, 100);
-    pairs[x].key_length= 100;
-
-    if (value_length)
-    {
-      pairs[x].value= (char *)calloc(value_length, sizeof(char));
-      if (!pairs[x].value)
-        goto error;
-      get_random_string(pairs[x].value, value_length);
-      pairs[x].value_length= value_length;
-    }
-    else
-    {
-      pairs[x].value= NULL;
-      pairs[x].value_length= 0;
-    }
-  }
-
-  return pairs;
-error:
-    fprintf(stderr, "Memory Allocation failure in pairs_generate.\n");
-    exit(0);
-}
diff --git a/clients/generator.cc b/clients/generator.cc
new file mode 100644 (file)
index 0000000..80b398b
--- /dev/null
@@ -0,0 +1,96 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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:
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "generator.h"
+
+/* Use this for string generation */
+static const char ALPHANUMERICS[]=
+  "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
+
+#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
+
+static size_t get_alpha_num(void)
+{
+  return (size_t)random() % ALPHANUMERICS_SIZE;
+}
+
+static void get_random_string(char *buffer, size_t size)
+{
+  char *buffer_ptr= buffer;
+
+  while (--size)
+    *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
+  *buffer_ptr++= ALPHANUMERICS[get_alpha_num()];
+}
+
+void pairs_free(pairs_st *pairs)
+{
+  uint32_t x;
+
+  if (! pairs)
+    return;
+
+  /* We free until we hit the null pair we stores during creation */
+  for (x= 0; pairs[x].key; x++)
+  {
+    free(pairs[x].key);
+    if (pairs[x].value)
+      free(pairs[x].value);
+  }
+
+  free(pairs);
+}
+
+pairs_st *pairs_generate(uint64_t number_of, size_t value_length)
+{
+  unsigned int x;
+  pairs_st *pairs;
+
+  pairs= (pairs_st*)calloc((size_t)number_of + 1, sizeof(pairs_st));
+
+  if (!pairs)
+    goto error;
+
+  for (x= 0; x < number_of; x++)
+  {
+    pairs[x].key= (char *)calloc(100, sizeof(char));
+    if (!pairs[x].key)
+      goto error;
+    get_random_string(pairs[x].key, 100);
+    pairs[x].key_length= 100;
+
+    if (value_length)
+    {
+      pairs[x].value= (char *)calloc(value_length, sizeof(char));
+      if (!pairs[x].value)
+        goto error;
+      get_random_string(pairs[x].value, value_length);
+      pairs[x].value_length= value_length;
+    }
+    else
+    {
+      pairs[x].value= NULL;
+      pairs[x].value_length= 0;
+    }
+  }
+
+  return pairs;
+error:
+    fprintf(stderr, "Memory Allocation failure in pairs_generate.\n");
+    exit(0);
+}
index 196e71b2728c3d0cd867f00d059413948d5a9fb0..e60bfb38dc107bad274cc6d6a97ef1c15878bb33 100644 (file)
@@ -13,8 +13,7 @@
   Code to generate data to be pushed into memcached
 */
 
-#ifndef __GENERATOR_H__
-#define __GENERATOR_H__
+#pragma once
 
 typedef struct pairs_st pairs_st;
 
@@ -25,7 +24,13 @@ struct pairs_st {
   size_t value_length;
 };
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 pairs_st *pairs_generate(uint64_t number_of, size_t value_length);
 void pairs_free(pairs_st *pairs);
 
+#ifdef __cplusplus
+} // extern "C"
 #endif
index 07d49a709b4b0d8b434aa45c682a48661d9882b8..05b1ed7e32e1574238a92888a8400286a32f8069 100644 (file)
@@ -2,10 +2,10 @@
 # included from Top Level Makefile.am
 # All paths should be given relative to the root
 
-CLIENTS_LDADDS = \
-       $(LIBM) \
-       clients/libutilities.la \
-       libmemcached/libmemcached.la
+CLIENTS_LDADDS= \
+               $(LIBM) \
+               clients/libutilities.la \
+               libmemcached/libmemcached.la
 
 if HAVE_SASL
 CLIENTS_LDADDS+= $(LIBSASL)
@@ -44,53 +44,52 @@ noinst_HEADERS+= \
                clients/utilities.h
 
 noinst_LTLIBRARIES+= clients/libutilities.la
-clients_libutilities_la_SOURCES= clients/utilities.c
+clients_libutilities_la_SOURCES= clients/utilities.cc
 
 noinst_LTLIBRARIES+= clients/libgenexec.la
-clients_libgenexec_la_SOURCES= clients/generator.c clients/execute.c
+clients_libgenexec_la_SOURCES= clients/generator.cc clients/execute.cc
 
-clients_memcat_SOURCES= clients/memcat.c
+clients_memcat_SOURCES= clients/memcat.cc
 clients_memcat_LDADD= $(CLIENTS_LDADDS)
 
 clients_memparse_SOURCES= clients/memparse.cc
 clients_memparse_LDADD= $(CLIENTS_LDADDS)
 
-clients_memcp_SOURCES= clients/memcp.c
+clients_memcp_SOURCES= clients/memcp.cc
 clients_memcp_LDADD= $(CLIENTS_LDADDS)
 
-clients_memdump_SOURCES= clients/memdump.c
+clients_memdump_SOURCES= clients/memdump.cc
 clients_memdump_LDADD= $(CLIENTS_LDADDS)
 
-clients_memstat_SOURCES= clients/memstat.c
+clients_memstat_SOURCES= clients/memstat.cc
 clients_memstat_LDADD= $(CLIENTS_LDADDS)
 
-clients_memrm_SOURCES= clients/memrm.c
+clients_memrm_SOURCES= clients/memrm.cc
 clients_memrm_LDADD= $(CLIENTS_LDADDS)
 
-clients_memflush_SOURCES= clients/memflush.c
+clients_memflush_SOURCES= clients/memflush.cc
 clients_memflush_LDADD= $(CLIENTS_LDADDS)
 
-clients_memerror_SOURCES= clients/memerror.c
+clients_memerror_SOURCES= clients/memerror.cc
 clients_memerror_LDADD= $(CLIENTS_LDADDS)
 
-clients_memslap_SOURCES = clients/memslap.c
+clients_memslap_SOURCES = clients/memslap.cc
 clients_memslap_LDADD = $(PTHREAD_LIBS) clients/libgenexec.la $(CLIENTS_LDADDS)
 
 clients_memaslap_SOURCES= \
-               clients/memaslap.c \
-               clients/ms_conn.c \
-               clients/ms_setting.c \
-               clients/ms_sigsegv.c \
-               clients/ms_stats.c \
-               clients/ms_task.c \
-               clients/ms_thread.c
+                         clients/memaslap.c \
+                         clients/ms_conn.c \
+                         clients/ms_setting.c \
+                         clients/ms_sigsegv.c \
+                         clients/ms_stats.c \
+                         clients/ms_task.c \
+                         clients/ms_thread.c
 clients_memaslap_LDADD= $(LTLIBEVENT) clients/libgenexec.la $(CLIENTS_LDADDS)
 
-clients_memcapable_SOURCES= clients/memcapable.c
+clients_memcapable_SOURCES= \
+                           clients/memcapable.cc \
+                           libmemcached/byteorder.cc
 clients_memcapable_LDADD= $(CLIENTS_LDADDS)
-if BUILD_BYTEORDER
-clients_memcapable_LDADD+= libmemcached/libbyteorder.la
-endif
 
 test-start-server:
        clients/memflush --servers=localhost
diff --git a/clients/memcapable.c b/clients/memcapable.c
deleted file mode 100644 (file)
index 69d2557..0000000
+++ /dev/null
@@ -1,2087 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- */
-
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#undef NDEBUG
-#include "config.h"
-#include <pthread.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <assert.h>
-#include <string.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#include <libmemcached/memcached.h>
-#include <libmemcached/memcached/protocol_binary.h>
-#include <libmemcached/byteorder.h>
-#include "utilities.h"
-
-#ifdef linux
-/* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
- * optimize the conversion functions, but the prototypes generate warnings
- * from gcc. The conversion methods isn't the bottleneck for my app, so
- * just remove the warnings by undef'ing the optimization ..
- */
-#undef ntohs
-#undef ntohl
-#endif
-
-/* Should we generate coredumps when we enounter an error (-c) */
-static bool do_core= false;
-/* connection to the server */
-static memcached_socket_t sock;
-/* Should the output from test failures be verbose or quiet? */
-static bool verbose= false;
-
-/* The number of seconds to wait for an IO-operation */
-static int timeout= 2;
-
-/*
- * Instead of having to cast between the different datatypes we create
- * a union of all of the different types of pacages we want to send.
- * A lot of the different commands use the same packet layout, so I'll
- * just define the different types I need. The typedefs only contain
- * the header of the message, so we need some space for keys and body
- * To avoid to have to do multiple writes, lets add a chunk of memory
- * to use. 1k should be more than enough for header, key and body.
- */
-typedef union
-{
-  protocol_binary_request_no_extras plain;
-  protocol_binary_request_flush flush;
-  protocol_binary_request_incr incr;
-  protocol_binary_request_set set;
-  char bytes[1024];
-} command;
-
-typedef union
-{
-  protocol_binary_response_no_extras plain;
-  protocol_binary_response_incr incr;
-  protocol_binary_response_decr decr;
-  char bytes[1024];
-} response;
-
-enum test_return
-{
-  TEST_SKIP, TEST_PASS, TEST_PASS_RECONNECT, TEST_FAIL
-};
-
-/**
- * Try to get an addrinfo struct for a given port on a given host
- */
-static struct addrinfo *lookuphost(const char *hostname, const char *port)
-{
-  struct addrinfo *ai= 0;
-  struct addrinfo hints= {.ai_family=AF_UNSPEC,
-    .ai_protocol=IPPROTO_TCP,
-    .ai_socktype=SOCK_STREAM};
-  int error= getaddrinfo(hostname, port, &hints, &ai);
-
-  if (error != 0)
-  {
-    if (error != EAI_SYSTEM)
-      fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
-    else
-      perror("getaddrinfo()");
-  }
-
-  return ai;
-}
-
-/**
- * Set the socket in nonblocking mode
- * @return -1 if failure, the socket otherwise
- */
-static memcached_socket_t set_noblock(void)
-{
-#ifdef WIN32
-  u_long arg = 1;
-  if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
-  {
-    perror("Failed to set nonblocking io");
-    closesocket(sock);
-    return INVALID_SOCKET;
-  }
-#else
-  int flags= fcntl(sock, F_GETFL, 0);
-  if (flags == -1)
-  {
-    perror("Failed to get socket flags");
-    closesocket(sock);
-    return INVALID_SOCKET;
-  }
-
-  if ((flags & O_NONBLOCK) != O_NONBLOCK)
-  {
-    if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
-    {
-      perror("Failed to set socket to nonblocking mode");
-      closesocket(sock);
-      return INVALID_SOCKET;
-    }
-  }
-#endif
-  return sock;
-}
-
-/**
- * Try to open a connection to the server
- * @param hostname the name of the server to connect to
- * @param port the port number (or service) to connect to
- * @return positive integer if success, -1 otherwise
- */
-static memcached_socket_t connect_server(const char *hostname, const char *port)
-{
-  struct addrinfo *ai= lookuphost(hostname, port);
-  sock= INVALID_SOCKET;
-  if (ai != NULL)
-  {
-    if ((sock= socket(ai->ai_family, ai->ai_socktype,
-                      ai->ai_protocol)) != INVALID_SOCKET)
-    {
-      if (connect(sock, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR)
-      {
-        fprintf(stderr, "Failed to connect socket: %s\n",
-                strerror(get_socket_errno()));
-        closesocket(sock);
-        sock= INVALID_SOCKET;
-      }
-      else
-      {
-        sock= set_noblock();
-      }
-    }
-    else
-      fprintf(stderr, "Failed to create socket: %s\n",
-              strerror(get_socket_errno()));
-
-    freeaddrinfo(ai);
-  }
-
-  return sock;
-}
-
-static ssize_t timeout_io_op(memcached_socket_t fd, short direction, void *buf, size_t len)
-{
-  ssize_t ret;
-
-  if (direction == POLLOUT)
-     ret= send(fd, buf, len, 0);
-  else
-     ret= recv(fd, buf, len, 0);
-
-  if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK) {
-    struct pollfd fds= {
-      .events= direction,
-      .fd= fd
-    };
-
-    int err= poll(&fds, 1, timeout * 1000);
-
-    if (err == 1)
-    {
-      if (direction == POLLOUT)
-         ret= send(fd, buf, len, 0);
-      else
-         ret= recv(fd, buf, len, 0);
-    }
-    else if (err == 0)
-    {
-      errno= ETIMEDOUT;
-    }
-    else
-    {
-      perror("Failed to poll");
-      return -1;
-    }
-  }
-
-  return ret;
-}
-
-/**
- * Ensure that an expression is true. If it isn't print out a message similar
- * to assert() and create a coredump if the user wants that. If not an error
- * message is returned.
- *
- */
-static enum test_return ensure(bool val, const char *expression, const char *file, int line)
-{
-  if (!val)
-  {
-    if (verbose)
-      fprintf(stderr, "\n%s:%d: %s", file, line, expression);
-
-    if (do_core)
-      abort();
-
-    return TEST_FAIL;
-  }
-
-  return TEST_PASS;
-}
-
-#define verify(expression) do { if (ensure(expression, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
-#define execute(expression) do { if (ensure(expression == TEST_PASS, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
-
-/**
- * Send a chunk of memory over the socket (retry if the call is iterrupted
- */
-static enum test_return retry_write(const void* buf, size_t len)
-{
-  size_t offset= 0;
-  const char* ptr= buf;
-
-  do
-  {
-    size_t num_bytes= len - offset;
-    ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes);
-    if (nw == -1)
-      verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
-    else
-      offset+= (size_t)nw;
-  } while (offset < len);
-
-  return TEST_PASS;
-}
-
-/**
- * Resend a packet to the server (All fields in the command header should
- * be in network byte order)
- */
-static enum test_return resend_packet(command *cmd)
-{
-  size_t length= sizeof (protocol_binary_request_no_extras) +
-          ntohl(cmd->plain.message.header.request.bodylen);
-
-  execute(retry_write(cmd, length));
-  return TEST_PASS;
-}
-
-/**
- * Send a command to the server. The command header needs to be updated
- * to network byte order
- */
-static enum test_return send_packet(command *cmd)
-{
-  /* Fix the byteorder of the header */
-  cmd->plain.message.header.request.keylen=
-          ntohs(cmd->plain.message.header.request.keylen);
-  cmd->plain.message.header.request.bodylen=
-          ntohl(cmd->plain.message.header.request.bodylen);
-  cmd->plain.message.header.request.cas=
-          ntohll(cmd->plain.message.header.request.cas);
-
-  execute(resend_packet(cmd));
-  return TEST_PASS;
-}
-
-/**
- * Read a fixed length chunk of data from the server
- */
-static enum test_return retry_read(void *buf, size_t len)
-{
-  size_t offset= 0;
-  do
-  {
-    ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset);
-    switch (nr) {
-    case -1 :
-       fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno));
-      verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
-      break;
-    case 0:
-      return TEST_FAIL;
-    default:
-      offset+= (size_t)nr;
-    }
-  } while (offset < len);
-
-  return TEST_PASS;
-}
-
-/**
- * Receive a response from the server and conver the fields in the header
- * to local byte order
- */
-static enum test_return recv_packet(response *rsp)
-{
-  execute(retry_read(rsp, sizeof(protocol_binary_response_no_extras)));
-
-  /* Fix the byte order in the packet header */
-  rsp->plain.message.header.response.keylen=
-          ntohs(rsp->plain.message.header.response.keylen);
-  rsp->plain.message.header.response.status=
-          ntohs(rsp->plain.message.header.response.status);
-  rsp->plain.message.header.response.bodylen=
-          ntohl(rsp->plain.message.header.response.bodylen);
-  rsp->plain.message.header.response.cas=
-          ntohll(rsp->plain.message.header.response.cas);
-
-  size_t bodysz= rsp->plain.message.header.response.bodylen;
-  if (bodysz > 0)
-    execute(retry_read(rsp->bytes + sizeof (protocol_binary_response_no_extras), bodysz));
-
-  return TEST_PASS;
-}
-
-/**
- * Create a storage command (add, set, replace etc)
- *
- * @param cmd destination buffer
- * @param cc the storage command to create
- * @param key the key to store
- * @param keylen the length of the key
- * @param dta the data to store with the key
- * @param dtalen the length of the data to store with the key
- * @param flags the flags to store along with the key
- * @param exptime the expiry time for the key
- */
-static void storage_command(command *cmd,
-                            uint8_t cc,
-                            const void* key,
-                            size_t keylen,
-                            const void* dta,
-                            size_t dtalen,
-                            uint32_t flags,
-                            uint32_t exptime)
-{
-  /* all of the storage commands use the same command layout */
-  protocol_binary_request_set *request= &cmd->set;
-
-  memset(request, 0, sizeof (*request));
-  request->message.header.request.magic= PROTOCOL_BINARY_REQ;
-  request->message.header.request.opcode= cc;
-  request->message.header.request.keylen= (uint16_t)keylen;
-  request->message.header.request.extlen= 8;
-  request->message.header.request.bodylen= (uint32_t)(keylen + 8 + dtalen);
-  request->message.header.request.opaque= 0xdeadbeef;
-  request->message.body.flags= flags;
-  request->message.body.expiration= exptime;
-
-  off_t key_offset= sizeof (protocol_binary_request_no_extras) + 8;
-  memcpy(cmd->bytes + key_offset, key, keylen);
-  if (dta != NULL)
-    memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
-}
-
-/**
- * Create a basic command to send to the server
- * @param cmd destination buffer
- * @param cc the command to create
- * @param key the key to store
- * @param keylen the length of the key
- * @param dta the data to store with the key
- * @param dtalen the length of the data to store with the key
- */
-static void raw_command(command *cmd,
-                        uint8_t cc,
-                        const void* key,
-                        size_t keylen,
-                        const void* dta,
-                        size_t dtalen)
-{
-  /* all of the storage commands use the same command layout */
-  memset(cmd, 0, sizeof (*cmd));
-  cmd->plain.message.header.request.magic= PROTOCOL_BINARY_REQ;
-  cmd->plain.message.header.request.opcode= cc;
-  cmd->plain.message.header.request.keylen= (uint16_t)keylen;
-  cmd->plain.message.header.request.bodylen= (uint32_t)(keylen + dtalen);
-  cmd->plain.message.header.request.opaque= 0xdeadbeef;
-
-  off_t key_offset= sizeof (protocol_binary_request_no_extras);
-
-  if (key != NULL)
-    memcpy(cmd->bytes + key_offset, key, keylen);
-
-  if (dta != NULL)
-    memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
-}
-
-/**
- * Create the flush command
- * @param cmd destination buffer
- * @param cc the command to create (FLUSH/FLUSHQ)
- * @param exptime when to flush
- * @param use_extra to force using of the extra field?
- */
-static void flush_command(command *cmd,
-                          uint8_t cc, uint32_t exptime, bool use_extra)
-{
-  memset(cmd, 0, sizeof (cmd->flush));
-  cmd->flush.message.header.request.magic= PROTOCOL_BINARY_REQ;
-  cmd->flush.message.header.request.opcode= cc;
-  cmd->flush.message.header.request.opaque= 0xdeadbeef;
-
-  if (exptime != 0 || use_extra)
-  {
-    cmd->flush.message.header.request.extlen= 4;
-    cmd->flush.message.body.expiration= htonl(exptime);
-    cmd->flush.message.header.request.bodylen= 4;
-  }
-}
-
-/**
- * Create a incr/decr command
- * @param cc the cmd to create (FLUSH/FLUSHQ)
- * @param key the key to operate on
- * @param keylen the number of bytes in the key
- * @param delta the number to add/subtract
- * @param initial the initial value if the key doesn't exist
- * @param exptime when the key should expire if it isn't set
- */
-static void arithmetic_command(command *cmd,
-                               uint8_t cc,
-                               const void* key,
-                               size_t keylen,
-                               uint64_t delta,
-                               uint64_t initial,
-                               uint32_t exptime)
-{
-  memset(cmd, 0, sizeof (cmd->incr));
-  cmd->incr.message.header.request.magic= PROTOCOL_BINARY_REQ;
-  cmd->incr.message.header.request.opcode= cc;
-  cmd->incr.message.header.request.keylen= (uint16_t)keylen;
-  cmd->incr.message.header.request.extlen= 20;
-  cmd->incr.message.header.request.bodylen= (uint32_t)(keylen + 20);
-  cmd->incr.message.header.request.opaque= 0xdeadbeef;
-  cmd->incr.message.body.delta= htonll(delta);
-  cmd->incr.message.body.initial= htonll(initial);
-  cmd->incr.message.body.expiration= htonl(exptime);
-
-  off_t key_offset= sizeof (protocol_binary_request_no_extras) + 20;
-  memcpy(cmd->bytes + key_offset, key, keylen);
-}
-
-/**
- * Validate the response header from the server
- * @param rsp the response to check
- * @param cc the expected command
- * @param status the expected status
- */
-static enum test_return do_validate_response_header(response *rsp,
-                                                    uint8_t cc, uint16_t status)
-{
-  verify(rsp->plain.message.header.response.magic == PROTOCOL_BINARY_RES);
-  verify(rsp->plain.message.header.response.opcode == cc);
-  verify(rsp->plain.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
-  verify(rsp->plain.message.header.response.status == status);
-  verify(rsp->plain.message.header.response.opaque == 0xdeadbeef);
-
-  if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS)
-  {
-    switch (cc) {
-    case PROTOCOL_BINARY_CMD_ADDQ:
-    case PROTOCOL_BINARY_CMD_APPENDQ:
-    case PROTOCOL_BINARY_CMD_DECREMENTQ:
-    case PROTOCOL_BINARY_CMD_DELETEQ:
-    case PROTOCOL_BINARY_CMD_FLUSHQ:
-    case PROTOCOL_BINARY_CMD_INCREMENTQ:
-    case PROTOCOL_BINARY_CMD_PREPENDQ:
-    case PROTOCOL_BINARY_CMD_QUITQ:
-    case PROTOCOL_BINARY_CMD_REPLACEQ:
-    case PROTOCOL_BINARY_CMD_SETQ:
-      verify("Quiet command shouldn't return on success" == NULL);
-    default:
-      break;
-    }
-
-    switch (cc) {
-    case PROTOCOL_BINARY_CMD_ADD:
-    case PROTOCOL_BINARY_CMD_REPLACE:
-    case PROTOCOL_BINARY_CMD_SET:
-    case PROTOCOL_BINARY_CMD_APPEND:
-    case PROTOCOL_BINARY_CMD_PREPEND:
-      verify(rsp->plain.message.header.response.keylen == 0);
-      verify(rsp->plain.message.header.response.extlen == 0);
-      verify(rsp->plain.message.header.response.bodylen == 0);
-      verify(rsp->plain.message.header.response.cas != 0);
-      break;
-    case PROTOCOL_BINARY_CMD_FLUSH:
-    case PROTOCOL_BINARY_CMD_NOOP:
-    case PROTOCOL_BINARY_CMD_QUIT:
-    case PROTOCOL_BINARY_CMD_DELETE:
-      verify(rsp->plain.message.header.response.keylen == 0);
-      verify(rsp->plain.message.header.response.extlen == 0);
-      verify(rsp->plain.message.header.response.bodylen == 0);
-      verify(rsp->plain.message.header.response.cas == 0);
-      break;
-
-    case PROTOCOL_BINARY_CMD_DECREMENT:
-    case PROTOCOL_BINARY_CMD_INCREMENT:
-      verify(rsp->plain.message.header.response.keylen == 0);
-      verify(rsp->plain.message.header.response.extlen == 0);
-      verify(rsp->plain.message.header.response.bodylen == 8);
-      verify(rsp->plain.message.header.response.cas != 0);
-      break;
-
-    case PROTOCOL_BINARY_CMD_STAT:
-      verify(rsp->plain.message.header.response.extlen == 0);
-      /* key and value exists in all packets except in the terminating */
-      verify(rsp->plain.message.header.response.cas == 0);
-      break;
-
-    case PROTOCOL_BINARY_CMD_VERSION:
-      verify(rsp->plain.message.header.response.keylen == 0);
-      verify(rsp->plain.message.header.response.extlen == 0);
-      verify(rsp->plain.message.header.response.bodylen != 0);
-      verify(rsp->plain.message.header.response.cas == 0);
-      break;
-
-    case PROTOCOL_BINARY_CMD_GET:
-    case PROTOCOL_BINARY_CMD_GETQ:
-      verify(rsp->plain.message.header.response.keylen == 0);
-      verify(rsp->plain.message.header.response.extlen == 4);
-      verify(rsp->plain.message.header.response.cas != 0);
-      break;
-
-    case PROTOCOL_BINARY_CMD_GETK:
-    case PROTOCOL_BINARY_CMD_GETKQ:
-      verify(rsp->plain.message.header.response.keylen != 0);
-      verify(rsp->plain.message.header.response.extlen == 4);
-      verify(rsp->plain.message.header.response.cas != 0);
-      break;
-
-    default:
-      /* Undefined command code */
-      break;
-    }
-  }
-  else
-  {
-    verify(rsp->plain.message.header.response.cas == 0);
-    verify(rsp->plain.message.header.response.extlen == 0);
-    if (cc != PROTOCOL_BINARY_CMD_GETK)
-    {
-      verify(rsp->plain.message.header.response.keylen == 0);
-    }
-  }
-
-  return TEST_PASS;
-}
-
-/* We call verify(validate_response_header), but that macro
- * expects a boolean expression, and the function returns
- * an enum.... Let's just create a macro to avoid cluttering
- * the code with all of the == TEST_PASS ;-)
- */
-#define validate_response_header(a,b,c) \
-        do_validate_response_header(a,b,c) == TEST_PASS
-
-
-static enum test_return send_binary_noop(void)
-{
-  command cmd;
-  raw_command(&cmd, PROTOCOL_BINARY_CMD_NOOP, NULL, 0, NULL, 0);
-  execute(send_packet(&cmd));
-  return TEST_PASS;
-}
-
-static enum test_return receive_binary_noop(void)
-{
-  response rsp;
-  execute(recv_packet(&rsp));
-  verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_NOOP,
-                                  PROTOCOL_BINARY_RESPONSE_SUCCESS));
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_noop(void)
-{
-  execute(send_binary_noop());
-  execute(receive_binary_noop());
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_quit_impl(uint8_t cc)
-{
-  command cmd;
-  response rsp;
-  raw_command(&cmd, cc, NULL, 0, NULL, 0);
-
-  execute(send_packet(&cmd));
-  if (cc == PROTOCOL_BINARY_CMD_QUIT)
-  {
-    execute(recv_packet(&rsp));
-    verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_QUIT,
-                                    PROTOCOL_BINARY_RESPONSE_SUCCESS));
-  }
-
-  /* Socket should be closed now, read should return EXIT_SUCCESS */
-  verify(timeout_io_op(sock, POLLIN, rsp.bytes, sizeof(rsp.bytes)) == 0);
-
-  return TEST_PASS_RECONNECT;
-}
-
-static enum test_return test_binary_quit(void)
-{
-  return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
-}
-
-static enum test_return test_binary_quitq(void)
-{
-  return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
-}
-
-static enum test_return test_binary_set_impl(const char* key, uint8_t cc)
-{
-  command cmd;
-  response rsp;
-
-  uint64_t value= 0xdeadbeefdeadcafe;
-  storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
-
-  /* set should always work */
-  for (int ii= 0; ii < 10; ii++)
-  {
-    if (ii == 0)
-      execute(send_packet(&cmd));
-    else
-      execute(resend_packet(&cmd));
-
-    if (cc == PROTOCOL_BINARY_CMD_SET)
-    {
-      execute(recv_packet(&rsp));
-      verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
-    }
-    else
-      execute(test_binary_noop());
-  }
-
-  /*
-   * We need to get the current CAS id, and at this time we haven't
-   * verified that we have a working get
-   */
-  if (cc == PROTOCOL_BINARY_CMD_SETQ)
-  {
-    cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SET;
-    execute(resend_packet(&cmd));
-    execute(recv_packet(&rsp));
-    verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
-                                    PROTOCOL_BINARY_RESPONSE_SUCCESS));
-    cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
-  }
-
-  /* try to set with the correct CAS value */
-  cmd.plain.message.header.request.cas=
-          htonll(rsp.plain.message.header.response.cas);
-  execute(resend_packet(&cmd));
-  if (cc == PROTOCOL_BINARY_CMD_SET)
-  {
-    execute(recv_packet(&rsp));
-    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
-  }
-  else
-    execute(test_binary_noop());
-
-  /* try to set with an incorrect CAS value */
-  cmd.plain.message.header.request.cas=
-          htonll(rsp.plain.message.header.response.cas - 1);
-  execute(resend_packet(&cmd));
-  execute(send_binary_noop());
-  execute(recv_packet(&rsp));
-  verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
-  execute(receive_binary_noop());
-
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_set(void)
-{
-  return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
-}
-
-static enum test_return test_binary_setq(void)
-{
-  return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
-}
-
-static enum test_return test_binary_add_impl(const char* key, uint8_t cc)
-{
-  command cmd;
-  response rsp;
-  uint64_t value= 0xdeadbeefdeadcafe;
-  storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
-
-  /* first add should work, rest of them should fail (even with cas
-     as wildcard */
-  for (int ii=0; ii < 10; ii++)
-  {
-    if (ii == 0)
-      execute(send_packet(&cmd));
-    else
-      execute(resend_packet(&cmd));
-
-    if (cc == PROTOCOL_BINARY_CMD_ADD || ii > 0)
-    {
-      uint16_t expected_result;
-      if (ii == 0)
-        expected_result= PROTOCOL_BINARY_RESPONSE_SUCCESS;
-      else
-        expected_result= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
-
-      execute(send_binary_noop());
-      execute(recv_packet(&rsp));
-      execute(receive_binary_noop());
-      verify(validate_response_header(&rsp, cc, expected_result));
-    }
-    else
-      execute(test_binary_noop());
-  }
-
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_add(void)
-{
-  return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
-}
-
-static enum test_return test_binary_addq(void)
-{
-  return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
-}
-
-static enum test_return binary_set_item(const char *key, const char *value)
-{
-  command cmd;
-  response rsp;
-  storage_command(&cmd, PROTOCOL_BINARY_CMD_SET, key, strlen(key),
-                  value, strlen(value), 0, 0);
-  execute(send_packet(&cmd));
-  execute(recv_packet(&rsp));
-  verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
-                                  PROTOCOL_BINARY_RESPONSE_SUCCESS));
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_replace_impl(const char* key, uint8_t cc)
-{
-  command cmd;
-  response rsp;
-  uint64_t value= 0xdeadbeefdeadcafe;
-  storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
-
-  /* first replace should fail, successive should succeed (when the
-     item is added! */
-  for (int ii= 0; ii < 10; ii++)
-  {
-    if (ii == 0)
-      execute(send_packet(&cmd));
-    else
-      execute(resend_packet(&cmd));
-
-    if (cc == PROTOCOL_BINARY_CMD_REPLACE || ii == 0)
-    {
-      uint16_t expected_result;
-      if (ii == 0)
-        expected_result=PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
-      else
-        expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS;
-
-      execute(send_binary_noop());
-      execute(recv_packet(&rsp));
-      execute(receive_binary_noop());
-      verify(validate_response_header(&rsp, cc, expected_result));
-
-      if (ii == 0)
-        execute(binary_set_item(key, key));
-    }
-    else
-      execute(test_binary_noop());
-  }
-
-  /* verify that replace with CAS value works! */
-  cmd.plain.message.header.request.cas=
-          htonll(rsp.plain.message.header.response.cas);
-  execute(resend_packet(&cmd));
-
-  if (cc == PROTOCOL_BINARY_CMD_REPLACE)
-  {
-    execute(recv_packet(&rsp));
-    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
-  }
-  else
-    execute(test_binary_noop());
-
-  /* try to set with an incorrect CAS value */
-  cmd.plain.message.header.request.cas=
-          htonll(rsp.plain.message.header.response.cas - 1);
-  execute(resend_packet(&cmd));
-  execute(send_binary_noop());
-  execute(recv_packet(&rsp));
-  execute(receive_binary_noop());
-  verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
-
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_replace(void)
-{
-  return test_binary_replace_impl("test_binary_replace", PROTOCOL_BINARY_CMD_REPLACE);
-}
-
-static enum test_return test_binary_replaceq(void)
-{
-  return test_binary_replace_impl("test_binary_replaceq", PROTOCOL_BINARY_CMD_REPLACEQ);
-}
-
-static enum test_return test_binary_delete_impl(const char *key, uint8_t cc)
-{
-  command cmd;
-  response rsp;
-  raw_command(&cmd, cc, key, strlen(key), NULL, 0);
-
-  /* The delete shouldn't work the first time, because the item isn't there */
-  execute(send_packet(&cmd));
-  execute(send_binary_noop());
-  execute(recv_packet(&rsp));
-  verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
-  execute(receive_binary_noop());
-  execute(binary_set_item(key, key));
-
-  /* The item should be present now, resend*/
-  execute(resend_packet(&cmd));
-  if (cc == PROTOCOL_BINARY_CMD_DELETE)
-  {
-    execute(recv_packet(&rsp));
-    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
-  }
-
-  execute(test_binary_noop());
-
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_delete(void)
-{
-  return test_binary_delete_impl("test_binary_delete", PROTOCOL_BINARY_CMD_DELETE);
-}
-
-static enum test_return test_binary_deleteq(void)
-{
-  return test_binary_delete_impl("test_binary_deleteq", PROTOCOL_BINARY_CMD_DELETEQ);
-}
-
-static enum test_return test_binary_get_impl(const char *key, uint8_t cc)
-{
-  command cmd;
-  response rsp;
-
-  raw_command(&cmd, cc, key, strlen(key), NULL, 0);
-  execute(send_packet(&cmd));
-  execute(send_binary_noop());
-
-  if (cc == PROTOCOL_BINARY_CMD_GET || cc == PROTOCOL_BINARY_CMD_GETK)
-  {
-    execute(recv_packet(&rsp));
-    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
-  }
-
-  execute(receive_binary_noop());
-
-  execute(binary_set_item(key, key));
-  execute(resend_packet(&cmd));
-  execute(send_binary_noop());
-
-  execute(recv_packet(&rsp));
-  verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
-  execute(receive_binary_noop());
-
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_get(void)
-{
-  return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
-}
-
-static enum test_return test_binary_getk(void)
-{
-  return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
-}
-
-static enum test_return test_binary_getq(void)
-{
-  return test_binary_get_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
-}
-
-static enum test_return test_binary_getkq(void)
-{
-  return test_binary_get_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
-}
-
-static enum test_return test_binary_incr_impl(const char* key, uint8_t cc)
-{
-  command cmd;
-  response rsp;
-  arithmetic_command(&cmd, cc, key, strlen(key), 1, 0, 0);
-
-  uint64_t ii;
-  for (ii= 0; ii < 10; ++ii)
-  {
-    if (ii == 0)
-      execute(send_packet(&cmd));
-    else
-      execute(resend_packet(&cmd));
-
-    if (cc == PROTOCOL_BINARY_CMD_INCREMENT)
-    {
-      execute(recv_packet(&rsp));
-      verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
-      verify(ntohll(rsp.incr.message.body.value) == ii);
-    }
-    else
-      execute(test_binary_noop());
-  }
-
-  /* @todo add incorrect CAS */
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_incr(void)
-{
-  return test_binary_incr_impl("test_binary_incr", PROTOCOL_BINARY_CMD_INCREMENT);
-}
-
-static enum test_return test_binary_incrq(void)
-{
-  return test_binary_incr_impl("test_binary_incrq", PROTOCOL_BINARY_CMD_INCREMENTQ);
-}
-
-static enum test_return test_binary_decr_impl(const char* key, uint8_t cc)
-{
-  command cmd;
-  response rsp;
-  arithmetic_command(&cmd, cc, key, strlen(key), 1, 9, 0);
-
-  int ii;
-  for (ii= 9; ii > -1; --ii)
-  {
-    if (ii == 9)
-      execute(send_packet(&cmd));
-    else
-      execute(resend_packet(&cmd));
-
-    if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
-    {
-      execute(recv_packet(&rsp));
-      verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
-      verify(ntohll(rsp.decr.message.body.value) == (uint64_t)ii);
-    }
-    else
-      execute(test_binary_noop());
-  }
-
-  /* decr 0 should not wrap */
-  execute(resend_packet(&cmd));
-  if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
-  {
-    execute(recv_packet(&rsp));
-    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
-    verify(ntohll(rsp.decr.message.body.value) == 0);
-  }
-  else
-  {
-    /* @todo get the value and verify! */
-
-  }
-
-  /* @todo add incorrect cas */
-  execute(test_binary_noop());
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_decr(void)
-{
-  return test_binary_decr_impl("test_binary_decr",
-                               PROTOCOL_BINARY_CMD_DECREMENT);
-}
-
-static enum test_return test_binary_decrq(void)
-{
-  return test_binary_decr_impl("test_binary_decrq",
-                               PROTOCOL_BINARY_CMD_DECREMENTQ);
-}
-
-static enum test_return test_binary_version(void)
-{
-  command cmd;
-  response rsp;
-  raw_command(&cmd, PROTOCOL_BINARY_CMD_VERSION, NULL, 0, NULL, 0);
-
-  execute(send_packet(&cmd));
-  execute(recv_packet(&rsp));
-  verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_VERSION,
-                                  PROTOCOL_BINARY_RESPONSE_SUCCESS));
-
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_flush_impl(const char *key, uint8_t cc)
-{
-  command cmd;
-  response rsp;
-
-  for (int ii= 0; ii < 2; ++ii)
-  {
-    execute(binary_set_item(key, key));
-    flush_command(&cmd, cc, 0, ii == 0);
-    execute(send_packet(&cmd));
-
-    if (cc == PROTOCOL_BINARY_CMD_FLUSH)
-    {
-      execute(recv_packet(&rsp));
-      verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
-    }
-    else
-      execute(test_binary_noop());
-
-    raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
-    execute(send_packet(&cmd));
-    execute(recv_packet(&rsp));
-    verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
-                                    PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
-  }
-
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_flush(void)
-{
-  return test_binary_flush_impl("test_binary_flush", PROTOCOL_BINARY_CMD_FLUSH);
-}
-
-static enum test_return test_binary_flushq(void)
-{
-  return test_binary_flush_impl("test_binary_flushq", PROTOCOL_BINARY_CMD_FLUSHQ);
-}
-
-static enum test_return test_binary_concat_impl(const char *key, uint8_t cc)
-{
-  command cmd;
-  response rsp;
-  const char *value;
-
-  if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
-    value="hello";
-  else
-    value=" world";
-
-  execute(binary_set_item(key, value));
-
-  if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
-    value=" world";
-  else
-    value="hello";
-
-  raw_command(&cmd, cc, key, strlen(key), value, strlen(value));
-  execute(send_packet(&cmd));
-  if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_PREPEND)
-  {
-    execute(recv_packet(&rsp));
-    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
-  }
-  else
-    execute(test_binary_noop());
-
-  raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
-  execute(send_packet(&cmd));
-  execute(recv_packet(&rsp));
-  verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
-                                  PROTOCOL_BINARY_RESPONSE_SUCCESS));
-  verify(rsp.plain.message.header.response.bodylen - 4 == 11);
-  verify(memcmp(rsp.bytes + 28, "hello world", 11) == 0);
-
-  return TEST_PASS;
-}
-
-static enum test_return test_binary_append(void)
-{
-  return test_binary_concat_impl("test_binary_append", PROTOCOL_BINARY_CMD_APPEND);
-}
-
-static enum test_return test_binary_prepend(void)
-{
-  return test_binary_concat_impl("test_binary_prepend", PROTOCOL_BINARY_CMD_PREPEND);
-}
-
-static enum test_return test_binary_appendq(void)
-{
-  return test_binary_concat_impl("test_binary_appendq", PROTOCOL_BINARY_CMD_APPENDQ);
-}
-
-static enum test_return test_binary_prependq(void)
-{
-  return test_binary_concat_impl("test_binary_prependq", PROTOCOL_BINARY_CMD_PREPENDQ);
-}
-
-static enum test_return test_binary_stat(void)
-{
-  command cmd;
-  response rsp;
-
-  raw_command(&cmd, PROTOCOL_BINARY_CMD_STAT, NULL, 0, NULL, 0);
-  execute(send_packet(&cmd));
-
-  do
-  {
-    execute(recv_packet(&rsp));
-    verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_STAT,
-                                    PROTOCOL_BINARY_RESPONSE_SUCCESS));
-  } while (rsp.plain.message.header.response.keylen != 0);
-
-  return TEST_PASS;
-}
-
-static enum test_return send_string(const char *cmd)
-{
-  execute(retry_write(cmd, strlen(cmd)));
-  return TEST_PASS;
-}
-
-static enum test_return receive_line(char *buffer, size_t size)
-{
-  size_t offset= 0;
-  while (offset < size)
-  {
-    execute(retry_read(buffer + offset, 1));
-    if (buffer[offset] == '\n')
-    {
-      if (offset + 1 < size)
-      {
-        buffer[offset + 1]= '\0';
-        return TEST_PASS;
-      }
-      else
-        return TEST_FAIL;
-    }
-    ++offset;
-  }
-
-  return TEST_FAIL;
-}
-
-static enum test_return receive_response(const char *msg) {
-  char buffer[80];
-  execute(receive_line(buffer, sizeof(buffer)));
-  if (strcmp(msg, buffer) != 0) {
-      fprintf(stderr, "[%s]\n", buffer);
-  }
-  verify(strcmp(msg, buffer) == 0);
-  return TEST_PASS;
-}
-
-static enum test_return receive_error_response(void)
-{
-  char buffer[80];
-  execute(receive_line(buffer, sizeof(buffer)));
-  verify(strncmp(buffer, "ERROR", 5) == 0 ||
-         strncmp(buffer, "CLIENT_ERROR", 12) == 0 ||
-         strncmp(buffer, "SERVER_ERROR", 12) == 0);
-  return TEST_PASS;
-}
-
-static enum test_return test_ascii_quit(void)
-{
-  /* Verify that quit handles unknown options */
-  execute(send_string("quit foo bar\r\n"));
-  execute(receive_error_response());
-
-  /* quit doesn't support noreply */
-  execute(send_string("quit noreply\r\n"));
-  execute(receive_error_response());
-
-  /* Verify that quit works */
-  execute(send_string("quit\r\n"));
-
-  /* Socket should be closed now, read should return EXIT_SUCCESS */
-  char buffer[80];
-  verify(timeout_io_op(sock, POLLIN, buffer, sizeof(buffer)) == 0);
-  return TEST_PASS_RECONNECT;
-
-}
-
-static enum test_return test_ascii_version(void)
-{
-  /* Verify that version command handles unknown options */
-  execute(send_string("version foo bar\r\n"));
-  execute(receive_error_response());
-
-  /* version doesn't support noreply */
-  execute(send_string("version noreply\r\n"));
-  execute(receive_error_response());
-
-  /* Verify that verify works */
-  execute(send_string("version\r\n"));
-  char buffer[256];
-  execute(receive_line(buffer, sizeof(buffer)));
-  verify(strncmp(buffer, "VERSION ", 8) == 0);
-
-  return TEST_PASS;
-}
-
-static enum test_return test_ascii_verbosity(void)
-{
-  /* This command does not adhere to the spec! */
-  execute(send_string("verbosity foo bar my\r\n"));
-  execute(receive_error_response());
-
-  execute(send_string("verbosity noreply\r\n"));
-  execute(receive_error_response());
-
-  execute(send_string("verbosity 0 noreply\r\n"));
-  execute(test_ascii_version());
-
-  execute(send_string("verbosity\r\n"));
-  execute(receive_error_response());
-
-  execute(send_string("verbosity 1\r\n"));
-  execute(receive_response("OK\r\n"));
-
-  execute(send_string("verbosity 0\r\n"));
-  execute(receive_response("OK\r\n"));
-
-  return TEST_PASS;
-}
-
-
-
-static enum test_return test_ascii_set_impl(const char* key, bool noreply)
-{
-  /* @todo add tests for bogus format! */
-  char buffer[1024];
-  snprintf(buffer, sizeof(buffer), "set %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
-  execute(send_string(buffer));
-
-  if (!noreply)
-    execute(receive_response("STORED\r\n"));
-
-  return test_ascii_version();
-}
-
-static enum test_return test_ascii_set(void)
-{
-  return test_ascii_set_impl("test_ascii_set", false);
-}
-
-static enum test_return test_ascii_set_noreply(void)
-{
-  return test_ascii_set_impl("test_ascii_set_noreply", true);
-}
-
-static enum test_return test_ascii_add_impl(const char* key, bool noreply)
-{
-  /* @todo add tests for bogus format! */
-  char buffer[1024];
-  snprintf(buffer, sizeof(buffer), "add %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
-  execute(send_string(buffer));
-
-  if (!noreply)
-    execute(receive_response("STORED\r\n"));
-
-  execute(send_string(buffer));
-
-  if (!noreply)
-    execute(receive_response("NOT_STORED\r\n"));
-
-  return test_ascii_version();
-}
-
-static enum test_return test_ascii_add(void)
-{
-  return test_ascii_add_impl("test_ascii_add", false);
-}
-
-static enum test_return test_ascii_add_noreply(void)
-{
-  return test_ascii_add_impl("test_ascii_add_noreply", true);
-}
-
-static enum test_return ascii_get_unknown_value(char **key, char **value, ssize_t *ndata)
-{
-  char buffer[1024];
-
-  execute(receive_line(buffer, sizeof(buffer)));
-  verify(strncmp(buffer, "VALUE ", 6) == 0);
-  char *end= strchr(buffer + 6, ' ');
-  verify(end != NULL);
-  *end= '\0';
-  *key= strdup(buffer + 6);
-  verify(*key != NULL);
-  char *ptr= end + 1;
-
-  unsigned long val= strtoul(ptr, &end, 10); /* flags */
-  verify(ptr != end);
-  verify(val == 0);
-  verify(end != NULL);
-  *ndata = (ssize_t)strtoul(end, &end, 10); /* size */
-  verify(ptr != end);
-  verify(end != NULL);
-  while (*end != '\n' && isspace(*end))
-    ++end;
-  verify(*end == '\n');
-
-  *value= malloc((size_t)*ndata);
-  verify(*value != NULL);
-
-  execute(retry_read(*value, (size_t)*ndata));
-
-  execute(retry_read(buffer, 2));
-  verify(memcmp(buffer, "\r\n", 2) == 0);
-
-  return TEST_PASS;
-}
-
-static enum test_return ascii_get_value(const char *key, const char *value)
-{
-
-  char buffer[1024];
-  size_t datasize= strlen(value);
-
-  verify(datasize < sizeof(buffer));
-  execute(receive_line(buffer, sizeof(buffer)));
-  verify(strncmp(buffer, "VALUE ", 6) == 0);
-  verify(strncmp(buffer + 6, key, strlen(key)) == 0);
-  char *ptr= buffer + 6 + strlen(key) + 1;
-  char *end;
-
-  unsigned long val= strtoul(ptr, &end, 10); /* flags */
-  verify(ptr != end);
-  verify(val == 0);
-  verify(end != NULL);
-  val= strtoul(end, &end, 10); /* size */
-  verify(ptr != end);
-  verify(val == datasize);
-  verify(end != NULL);
-  while (*end != '\n' && isspace(*end))
-    ++end;
-  verify(*end == '\n');
-
-  execute(retry_read(buffer, datasize));
-  verify(memcmp(buffer, value, datasize) == 0);
-
-  execute(retry_read(buffer, 2));
-  verify(memcmp(buffer, "\r\n", 2) == 0);
-
-  return TEST_PASS;
-}
-
-static enum test_return ascii_get_item(const char *key, const char *value,
-                                       bool exist)
-{
-  char buffer[1024];
-  size_t datasize= 0;
-  if (value != NULL)
-    datasize= strlen(value);
-
-  verify(datasize < sizeof(buffer));
-  snprintf(buffer, sizeof(buffer), "get %s\r\n", key);
-  execute(send_string(buffer));
-
-  if (exist)
-    execute(ascii_get_value(key, value));
-
-  execute(retry_read(buffer, 5));
-  verify(memcmp(buffer, "END\r\n", 5) == 0);
-
-  return TEST_PASS;
-}
-
-static enum test_return ascii_gets_value(const char *key, const char *value,
-                                         unsigned long *cas)
-{
-
-  char buffer[1024];
-  size_t datasize= strlen(value);
-
-  verify(datasize < sizeof(buffer));
-  execute(receive_line(buffer, sizeof(buffer)));
-  verify(strncmp(buffer, "VALUE ", 6) == 0);
-  verify(strncmp(buffer + 6, key, strlen(key)) == 0);
-  char *ptr= buffer + 6 + strlen(key) + 1;
-  char *end;
-
-  unsigned long val= strtoul(ptr, &end, 10); /* flags */
-  verify(ptr != end);
-  verify(val == 0);
-  verify(end != NULL);
-  val= strtoul(end, &end, 10); /* size */
-  verify(ptr != end);
-  verify(val == datasize);
-  verify(end != NULL);
-  *cas= strtoul(end, &end, 10); /* cas */
-  verify(ptr != end);
-  verify(val == datasize);
-  verify(end != NULL);
-
-  while (*end != '\n' && isspace(*end))
-    ++end;
-  verify(*end == '\n');
-
-  execute(retry_read(buffer, datasize));
-  verify(memcmp(buffer, value, datasize) == 0);
-
-  execute(retry_read(buffer, 2));
-  verify(memcmp(buffer, "\r\n", 2) == 0);
-
-  return TEST_PASS;
-}
-
-static enum test_return ascii_gets_item(const char *key, const char *value,
-                                        bool exist, unsigned long *cas)
-{
-  char buffer[1024];
-  size_t datasize= 0;
-  if (value != NULL)
-    datasize= strlen(value);
-
-  verify(datasize < sizeof(buffer));
-  snprintf(buffer, sizeof(buffer), "gets %s\r\n", key);
-  execute(send_string(buffer));
-
-  if (exist)
-    execute(ascii_gets_value(key, value, cas));
-
-  execute(retry_read(buffer, 5));
-  verify(memcmp(buffer, "END\r\n", 5) == 0);
-
-  return TEST_PASS;
-}
-
-static enum test_return ascii_set_item(const char *key, const char *value)
-{
-  char buffer[300];
-  size_t len= strlen(value);
-  snprintf(buffer, sizeof(buffer), "set %s 0 0 %u\r\n", key, (unsigned int)len);
-  execute(send_string(buffer));
-  execute(retry_write(value, len));
-  execute(send_string("\r\n"));
-  execute(receive_response("STORED\r\n"));
-  return TEST_PASS;
-}
-
-static enum test_return test_ascii_replace_impl(const char* key, bool noreply)
-{
-  char buffer[1024];
-  snprintf(buffer, sizeof(buffer), "replace %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
-  execute(send_string(buffer));
-
-  if (noreply)
-    execute(test_ascii_version());
-  else
-    execute(receive_response("NOT_STORED\r\n"));
-
-  execute(ascii_set_item(key, "value"));
-  execute(ascii_get_item(key, "value", true));
-
-
-  execute(send_string(buffer));
-
-  if (noreply)
-    execute(test_ascii_version());
-  else
-    execute(receive_response("STORED\r\n"));
-
-  return test_ascii_version();
-}
-
-static enum test_return test_ascii_replace(void)
-{
-  return test_ascii_replace_impl("test_ascii_replace", false);
-}
-
-static enum test_return test_ascii_replace_noreply(void)
-{
-  return test_ascii_replace_impl("test_ascii_replace_noreply", true);
-}
-
-static enum test_return test_ascii_cas_impl(const char* key, bool noreply)
-{
-  char buffer[1024];
-  unsigned long cas;
-
-  execute(ascii_set_item(key, "value"));
-  execute(ascii_gets_item(key, "value", true, &cas));
-
-  snprintf(buffer, sizeof(buffer), "cas %s 0 0 6 %lu%s\r\nvalue2\r\n", key, cas, noreply ? " noreply" : "");
-  execute(send_string(buffer));
-
-  if (noreply)
-    execute(test_ascii_version());
-  else
-    execute(receive_response("STORED\r\n"));
-
-  /* reexecute the same command should fail due to illegal cas */
-  execute(send_string(buffer));
-
-  if (noreply)
-    execute(test_ascii_version());
-  else
-    execute(receive_response("EXISTS\r\n"));
-
-  return test_ascii_version();
-}
-
-static enum test_return test_ascii_cas(void)
-{
-  return test_ascii_cas_impl("test_ascii_cas", false);
-}
-
-static enum test_return test_ascii_cas_noreply(void)
-{
-  return test_ascii_cas_impl("test_ascii_cas_noreply", true);
-}
-
-static enum test_return test_ascii_delete_impl(const char *key, bool noreply)
-{
-  execute(ascii_set_item(key, "value"));
-
-  execute(send_string("delete\r\n"));
-  execute(receive_error_response());
-  /* BUG: the server accepts delete a b */
-  execute(send_string("delete a b c d e\r\n"));
-  execute(receive_error_response());
-
-  char buffer[1024];
-  snprintf(buffer, sizeof(buffer), "delete %s%s\r\n", key, noreply ? " noreply" : "");
-  execute(send_string(buffer));
-
-  if (noreply)
-    execute(test_ascii_version());
-  else
-    execute(receive_response("DELETED\r\n"));
-
-  execute(ascii_get_item(key, "value", false));
-  execute(send_string(buffer));
-  if (noreply)
-    execute(test_ascii_version());
-  else
-    execute(receive_response("NOT_FOUND\r\n"));
-
-  return TEST_PASS;
-}
-
-static enum test_return test_ascii_delete(void)
-{
-  return test_ascii_delete_impl("test_ascii_delete", false);
-}
-
-static enum test_return test_ascii_delete_noreply(void)
-{
-  return test_ascii_delete_impl("test_ascii_delete_noreply", true);
-}
-
-static enum test_return test_ascii_get(void)
-{
-  execute(ascii_set_item("test_ascii_get", "value"));
-
-  execute(send_string("get\r\n"));
-  execute(receive_error_response());
-  execute(ascii_get_item("test_ascii_get", "value", true));
-  execute(ascii_get_item("test_ascii_get_notfound", "value", false));
-
-  return TEST_PASS;
-}
-
-static enum test_return test_ascii_gets(void)
-{
-  execute(ascii_set_item("test_ascii_gets", "value"));
-
-  execute(send_string("gets\r\n"));
-  execute(receive_error_response());
-  unsigned long cas;
-  execute(ascii_gets_item("test_ascii_gets", "value", true, &cas));
-  execute(ascii_gets_item("test_ascii_gets_notfound", "value", false, &cas));
-
-  return TEST_PASS;
-}
-
-static enum test_return test_ascii_mget(void)
-{
-  const uint32_t nkeys= 5;
-  const char * const keys[]= {
-    "test_ascii_mget1",
-    "test_ascii_mget2",
-    /* test_ascii_mget_3 does not exist :) */
-    "test_ascii_mget4",
-    "test_ascii_mget5",
-    "test_ascii_mget6"
-  };
-
-  for (uint32_t x= 0; x < nkeys; ++x)
-    execute(ascii_set_item(keys[x], "value"));
-
-  /* Ask for a key that doesn't exist as well */
-  execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 "
-                      "test_ascii_mget4 test_ascii_mget5 "
-                      "test_ascii_mget6\r\n"));
-
-  char *returned[nkeys];
-
-  for (uint32_t x= 0; x < nkeys; ++x)
-  {
-    ssize_t nbytes = 0;
-    char *v= NULL;
-    execute(ascii_get_unknown_value(&returned[x], &v, &nbytes));
-    verify(nbytes == 5);
-    verify(memcmp(v, "value", 5) == 0);
-    free(v);
-  }
-
-  char buffer[5];
-  execute(retry_read(buffer, 5));
-  verify(memcmp(buffer, "END\r\n", 5) == 0);
-
-  /* verify that we got all the keys we expected */
-  for (uint32_t x= 0; x < nkeys; ++x)
-  {
-    bool found= false;
-    for (uint32_t y= 0; y < nkeys; ++y)
-    {
-      if (strcmp(keys[x], returned[y]) == 0)
-      {
-        found = true;
-        break;
-      }
-    }
-    verify(found);
-  }
-
-  for (uint32_t x= 0; x < nkeys; ++x)
-    free(returned[x]);
-
-  return TEST_PASS;
-}
-
-static enum test_return test_ascii_incr_impl(const char* key, bool noreply)
-{
-  char cmd[300];
-  snprintf(cmd, sizeof(cmd), "incr %s 1%s\r\n", key, noreply ? " noreply" : "");
-
-  execute(ascii_set_item(key, "0"));
-  for (int x= 1; x < 11; ++x)
-  {
-    execute(send_string(cmd));
-
-    if (noreply)
-      execute(test_ascii_version());
-    else
-    {
-      char buffer[80];
-      execute(receive_line(buffer, sizeof(buffer)));
-      int val= atoi(buffer);
-      verify(val == x);
-    }
-  }
-
-  execute(ascii_get_item(key, "10", true));
-
-  return TEST_PASS;
-}
-
-static enum test_return test_ascii_incr(void)
-{
-  return test_ascii_incr_impl("test_ascii_incr", false);
-}
-
-static enum test_return test_ascii_incr_noreply(void)
-{
-  return test_ascii_incr_impl("test_ascii_incr_noreply", true);
-}
-
-static enum test_return test_ascii_decr_impl(const char* key, bool noreply)
-{
-  char cmd[300];
-  snprintf(cmd, sizeof(cmd), "decr %s 1%s\r\n", key, noreply ? " noreply" : "");
-
-  execute(ascii_set_item(key, "9"));
-  for (int x= 8; x > -1; --x)
-  {
-    execute(send_string(cmd));
-
-    if (noreply)
-      execute(test_ascii_version());
-    else
-    {
-      char buffer[80];
-      execute(receive_line(buffer, sizeof(buffer)));
-      int val= atoi(buffer);
-      verify(val == x);
-    }
-  }
-
-  execute(ascii_get_item(key, "0", true));
-
-  /* verify that it doesn't wrap */
-  execute(send_string(cmd));
-  if (noreply)
-    execute(test_ascii_version());
-  else
-  {
-    char buffer[80];
-    execute(receive_line(buffer, sizeof(buffer)));
-  }
-  execute(ascii_get_item(key, "0", true));
-
-  return TEST_PASS;
-}
-
-static enum test_return test_ascii_decr(void)
-{
-  return test_ascii_decr_impl("test_ascii_decr", false);
-}
-
-static enum test_return test_ascii_decr_noreply(void)
-{
-  return test_ascii_decr_impl("test_ascii_decr_noreply", true);
-}
-
-
-static enum test_return test_ascii_flush_impl(const char *key, bool noreply)
-{
-#if 0
-  /* Verify that the flush_all command handles unknown options */
-  /* Bug in the current memcached server! */
-  execute(send_string("flush_all foo bar\r\n"));
-  execute(receive_error_response());
-#endif
-
-  execute(ascii_set_item(key, key));
-  execute(ascii_get_item(key, key, true));
-
-  if (noreply)
-  {
-    execute(send_string("flush_all noreply\r\n"));
-    execute(test_ascii_version());
-  }
-  else
-  {
-    execute(send_string("flush_all\r\n"));
-    execute(receive_response("OK\r\n"));
-  }
-
-  execute(ascii_get_item(key, key, false));
-
-  return TEST_PASS;
-}
-
-static enum test_return test_ascii_flush(void)
-{
-  return test_ascii_flush_impl("test_ascii_flush", false);
-}
-
-static enum test_return test_ascii_flush_noreply(void)
-{
-  return test_ascii_flush_impl("test_ascii_flush_noreply", true);
-}
-
-static enum test_return test_ascii_concat_impl(const char *key,
-                                               bool append,
-                                               bool noreply)
-{
-  const char *value;
-
-  if (append)
-    value="hello";
-  else
-    value=" world";
-
-  execute(ascii_set_item(key, value));
-
-  if (append)
-    value=" world";
-  else
-    value="hello";
-
-  char cmd[400];
-  snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n",
-           append ? "append" : "prepend",
-           key, (unsigned int)strlen(value), noreply ? " noreply" : "",
-           value);
-  execute(send_string(cmd));
-
-  if (noreply)
-    execute(test_ascii_version());
-  else
-    execute(receive_response("STORED\r\n"));
-
-  execute(ascii_get_item(key, "hello world", true));
-
-  snprintf(cmd, sizeof(cmd), "%s %s_notfound 0 0 %u%s\r\n%s\r\n",
-           append ? "append" : "prepend",
-           key, (unsigned int)strlen(value), noreply ? " noreply" : "",
-           value);
-  execute(send_string(cmd));
-
-  if (noreply)
-    execute(test_ascii_version());
-  else
-    execute(receive_response("NOT_STORED\r\n"));
-
-  return TEST_PASS;
-}
-
-static enum test_return test_ascii_append(void)
-{
-  return test_ascii_concat_impl("test_ascii_append", true, false);
-}
-
-static enum test_return test_ascii_prepend(void)
-{
-  return test_ascii_concat_impl("test_ascii_prepend", false, false);
-}
-
-static enum test_return test_ascii_append_noreply(void)
-{
-  return test_ascii_concat_impl("test_ascii_append_noreply", true, true);
-}
-
-static enum test_return test_ascii_prepend_noreply(void)
-{
-  return test_ascii_concat_impl("test_ascii_prepend_noreply", false, true);
-}
-
-static enum test_return test_ascii_stat(void)
-{
-  execute(send_string("stats noreply\r\n"));
-  execute(receive_error_response());
-  execute(send_string("stats\r\n"));
-  char buffer[1024];
-  do {
-    execute(receive_line(buffer, sizeof(buffer)));
-  } while (strcmp(buffer, "END\r\n") != 0);
-
-  return TEST_PASS_RECONNECT;
-}
-
-typedef enum test_return(*TEST_FUNC)(void);
-
-struct testcase
-{
-  const char *description;
-  TEST_FUNC function;
-};
-
-struct testcase testcases[]= {
-  { "ascii quit", test_ascii_quit },
-  { "ascii version", test_ascii_version },
-  { "ascii verbosity", test_ascii_verbosity },
-  { "ascii set", test_ascii_set },
-  { "ascii set noreply", test_ascii_set_noreply },
-  { "ascii get", test_ascii_get },
-  { "ascii gets", test_ascii_gets },
-  { "ascii mget", test_ascii_mget },
-  { "ascii flush", test_ascii_flush },
-  { "ascii flush noreply", test_ascii_flush_noreply },
-  { "ascii add", test_ascii_add },
-  { "ascii add noreply", test_ascii_add_noreply },
-  { "ascii replace", test_ascii_replace },
-  { "ascii replace noreply", test_ascii_replace_noreply },
-  { "ascii cas", test_ascii_cas },
-  { "ascii cas noreply", test_ascii_cas_noreply },
-  { "ascii delete", test_ascii_delete },
-  { "ascii delete noreply", test_ascii_delete_noreply },
-  { "ascii incr", test_ascii_incr },
-  { "ascii incr noreply", test_ascii_incr_noreply },
-  { "ascii decr", test_ascii_decr },
-  { "ascii decr noreply", test_ascii_decr_noreply },
-  { "ascii append", test_ascii_append },
-  { "ascii append noreply", test_ascii_append_noreply },
-  { "ascii prepend", test_ascii_prepend },
-  { "ascii prepend noreply", test_ascii_prepend_noreply },
-  { "ascii stat", test_ascii_stat },
-  { "binary noop", test_binary_noop },
-  { "binary quit", test_binary_quit },
-  { "binary quitq", test_binary_quitq },
-  { "binary set", test_binary_set },
-  { "binary setq", test_binary_setq },
-  { "binary flush", test_binary_flush },
-  { "binary flushq", test_binary_flushq },
-  { "binary add", test_binary_add },
-  { "binary addq", test_binary_addq },
-  { "binary replace", test_binary_replace },
-  { "binary replaceq", test_binary_replaceq },
-  { "binary delete", test_binary_delete },
-  { "binary deleteq", test_binary_deleteq },
-  { "binary get", test_binary_get },
-  { "binary getq", test_binary_getq },
-  { "binary getk", test_binary_getk },
-  { "binary getkq", test_binary_getkq },
-  { "binary incr", test_binary_incr },
-  { "binary incrq", test_binary_incrq },
-  { "binary decr", test_binary_decr },
-  { "binary decrq", test_binary_decrq },
-  { "binary version", test_binary_version },
-  { "binary append", test_binary_append },
-  { "binary appendq", test_binary_appendq },
-  { "binary prepend", test_binary_prepend },
-  { "binary prependq", test_binary_prependq },
-  { "binary stat", test_binary_stat },
-  { NULL, NULL}
-};
-
-const int ascii_tests = 1;
-const int binary_tests = 2;
-
-struct test_type_st
-{
-  bool ascii;
-  bool binary;
-};
-
-int main(int argc, char **argv)
-{
-  static const char * const status_msg[]= {"[skip]", "[pass]", "[pass]", "[FAIL]"};
-  struct test_type_st tests= { true, true };
-  int total= 0;
-  int failed= 0;
-  const char *hostname= "localhost";
-  const char *port= "11211";
-  int cmd;
-  bool prompt= false;
-  const char *testname= NULL;
-
-
-
-  while ((cmd= getopt(argc, argv, "t:vch:p:PT:?ab")) != EOF)
-  {
-    switch (cmd) {
-    case 'a':
-      tests.ascii= true;
-      tests.binary= false;
-      break;
-    case 'b':
-      tests.ascii= false;
-      tests.binary= true;
-      break;
-    case 't':
-      timeout= atoi(optarg);
-      if (timeout == 0)
-      {
-        fprintf(stderr, "Invalid timeout. Please specify a number for -t\n");
-        return EXIT_FAILURE;
-      }
-      break;
-    case 'v': verbose= true;
-      break;
-    case 'c': do_core= true;
-      break;
-    case 'h': hostname= optarg;
-      break;
-    case 'p': port= optarg;
-      break;
-    case 'P': prompt= true;
-      break;
-    case 'T': testname= optarg;
-       break;
-    default:
-      fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n] [-P] [-T testname]'\n"
-              "\t-c\tGenerate coredump if a test fails\n"
-              "\t-v\tVerbose test output (print out the assertion)\n"
-              "\t-t n\tSet the timeout for io-operations to n seconds\n"
-              "\t-P\tPrompt the user before starting a test.\n"
-              "\t\t\t\"skip\" will skip the test\n"
-              "\t\t\t\"quit\" will terminate memcapable\n"
-              "\t\t\tEverything else will start the test\n"
-              "\t-T n\tJust run the test named n\n"
-              "\t-a\tOnly test the ascii protocol\n"
-              "\t-b\tOnly test the binary protocol\n",
-              argv[0]);
-      return EXIT_FAILURE;
-    }
-  }
-
-  initialize_sockets();
-  sock= connect_server(hostname, port);
-  if (sock == INVALID_SOCKET)
-  {
-    fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
-            hostname, port, strerror(get_socket_errno()));
-    return EXIT_FAILURE;
-  }
-
-  for (int ii= 0; testcases[ii].description != NULL; ++ii)
-  {
-    if (testname != NULL && strcmp(testcases[ii].description, testname) != 0)
-       continue;
-
-    if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) ||
-        (testcases[ii].description[0] == 'b' && (tests.binary) == 0))
-    {
-      continue;
-    }
-    ++total;
-    fprintf(stdout, "%-40s", testcases[ii].description);
-    fflush(stdout);
-
-    if (prompt)
-    {
-      fprintf(stdout, "\nPress <return> when you are ready? ");
-      char buffer[80] = {0};
-      if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
-        if (strncmp(buffer, "skip", 4) == 0)
-        {
-          fprintf(stdout, "%-40s%s\n", testcases[ii].description,
-                  status_msg[TEST_SKIP]);
-          fflush(stdout);
-          continue;
-        }
-        if (strncmp(buffer, "quit", 4) == 0)
-          exit(0);
-      }
-
-      fprintf(stdout, "%-40s", testcases[ii].description);
-      fflush(stdout);
-    }
-
-    bool reconnect= false;
-    enum test_return ret= testcases[ii].function();
-    if (ret == TEST_FAIL)
-    {
-      reconnect= true;
-      ++failed;
-      if (verbose)
-        fprintf(stderr, "\n");
-    }
-    else if (ret == TEST_PASS_RECONNECT)
-      reconnect= true;
-
-    fprintf(stderr, "%s\n", status_msg[ret]);
-    if (reconnect)
-    {
-      closesocket(sock);
-      if ((sock= connect_server(hostname, port)) == INVALID_SOCKET)
-      {
-        fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
-                hostname, port, strerror(get_socket_errno()));
-        fprintf(stderr, "%d of %d tests failed\n", failed, total);
-        return EXIT_FAILURE;
-      }
-    }
-  }
-
-  closesocket(sock);
-  if (failed == 0)
-    fprintf(stdout, "All tests passed\n");
-  else
-    fprintf(stderr, "%d of %d tests failed\n", failed, total);
-
-  return (failed == 0) ? 0 : 1;
-}
diff --git a/clients/memcapable.cc b/clients/memcapable.cc
new file mode 100644 (file)
index 0000000..baac28b
--- /dev/null
@@ -0,0 +1,2098 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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:
+ *
+ */
+
+/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+#undef NDEBUG
+
+#include "config.h"
+#include <pthread.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include <libmemcached/memcached.h>
+#include <libmemcached/memcached/protocol_binary.h>
+#include <libmemcached/byteorder.h>
+#include "utilities.h"
+
+#ifdef linux
+/* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
+ * optimize the conversion functions, but the prototypes generate warnings
+ * from gcc. The conversion methods isn't the bottleneck for my app, so
+ * just remove the warnings by undef'ing the optimization ..
+ */
+#undef ntohs
+#undef ntohl
+#endif
+
+/* Should we generate coredumps when we enounter an error (-c) */
+static bool do_core= false;
+/* connection to the server */
+static memcached_socket_t sock;
+/* Should the output from test failures be verbose or quiet? */
+static bool verbose= false;
+
+/* The number of seconds to wait for an IO-operation */
+static int timeout= 2;
+
+/*
+ * Instead of having to cast between the different datatypes we create
+ * a union of all of the different types of pacages we want to send.
+ * A lot of the different commands use the same packet layout, so I'll
+ * just define the different types I need. The typedefs only contain
+ * the header of the message, so we need some space for keys and body
+ * To avoid to have to do multiple writes, lets add a chunk of memory
+ * to use. 1k should be more than enough for header, key and body.
+ */
+typedef union
+{
+  protocol_binary_request_no_extras plain;
+  protocol_binary_request_flush flush;
+  protocol_binary_request_incr incr;
+  protocol_binary_request_set set;
+  char bytes[1024];
+} command;
+
+typedef union
+{
+  protocol_binary_response_no_extras plain;
+  protocol_binary_response_incr incr;
+  protocol_binary_response_decr decr;
+  char bytes[1024];
+} response;
+
+enum test_return
+{
+  TEST_SKIP, TEST_PASS, TEST_PASS_RECONNECT, TEST_FAIL
+};
+
+/**
+ * Try to get an addrinfo struct for a given port on a given host
+ */
+static struct addrinfo *lookuphost(const char *hostname, const char *port)
+{
+  struct addrinfo *ai= 0;
+  struct addrinfo hints;
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_family=AF_UNSPEC;
+  hints.ai_protocol=IPPROTO_TCP;
+  hints.ai_socktype=SOCK_STREAM;
+
+  int error= getaddrinfo(hostname, port, &hints, &ai);
+  if (error != 0)
+  {
+    if (error != EAI_SYSTEM)
+      fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
+    else
+      perror("getaddrinfo()");
+  }
+
+  return ai;
+}
+
+/**
+ * Set the socket in nonblocking mode
+ * @return -1 if failure, the socket otherwise
+ */
+static memcached_socket_t set_noblock(void)
+{
+#ifdef WIN32
+  u_long arg = 1;
+  if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
+  {
+    perror("Failed to set nonblocking io");
+    closesocket(sock);
+    return INVALID_SOCKET;
+  }
+#else
+  int flags= fcntl(sock, F_GETFL, 0);
+  if (flags == -1)
+  {
+    perror("Failed to get socket flags");
+    closesocket(sock);
+    return INVALID_SOCKET;
+  }
+
+  if ((flags & O_NONBLOCK) != O_NONBLOCK)
+  {
+    if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
+    {
+      perror("Failed to set socket to nonblocking mode");
+      closesocket(sock);
+      return INVALID_SOCKET;
+    }
+  }
+#endif
+  return sock;
+}
+
+/**
+ * Try to open a connection to the server
+ * @param hostname the name of the server to connect to
+ * @param port the port number (or service) to connect to
+ * @return positive integer if success, -1 otherwise
+ */
+static memcached_socket_t connect_server(const char *hostname, const char *port)
+{
+  struct addrinfo *ai= lookuphost(hostname, port);
+  sock= INVALID_SOCKET;
+  if (ai != NULL)
+  {
+    if ((sock= socket(ai->ai_family, ai->ai_socktype,
+                      ai->ai_protocol)) != INVALID_SOCKET)
+    {
+      if (connect(sock, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR)
+      {
+        fprintf(stderr, "Failed to connect socket: %s\n",
+                strerror(get_socket_errno()));
+        closesocket(sock);
+        sock= INVALID_SOCKET;
+      }
+      else
+      {
+        sock= set_noblock();
+      }
+    }
+    else
+      fprintf(stderr, "Failed to create socket: %s\n",
+              strerror(get_socket_errno()));
+
+    freeaddrinfo(ai);
+  }
+
+  return sock;
+}
+
+static ssize_t timeout_io_op(memcached_socket_t fd, short direction, void *buf, size_t len)
+{
+  ssize_t ret;
+
+  if (direction == POLLOUT)
+  {
+    ret= send(fd, buf, len, 0);
+  }
+  else
+  {
+    ret= recv(fd, buf, len, 0);
+  }
+
+  if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK) 
+  {
+    struct pollfd fds;
+    memset(&fds, 0, sizeof(struct pollfd));
+    fds.events= direction;
+    fds.fd= fd;
+
+    int err= poll(&fds, 1, timeout * 1000);
+    if (err == 1)
+    {
+      if (direction == POLLOUT)
+      {
+        ret= send(fd, buf, len, 0);
+      }
+      else
+      {
+        ret= recv(fd, buf, len, 0);
+      }
+    }
+    else if (err == 0)
+    {
+      errno= ETIMEDOUT;
+    }
+    else
+    {
+      perror("Failed to poll");
+      return -1;
+    }
+  }
+
+  return ret;
+}
+
+/**
+ * Ensure that an expression is true. If it isn't print out a message similar
+ * to assert() and create a coredump if the user wants that. If not an error
+ * message is returned.
+ *
+ */
+static enum test_return ensure(bool val, const char *expression, const char *file, int line)
+{
+  if (!val)
+  {
+    if (verbose)
+      fprintf(stderr, "\n%s:%d: %s", file, line, expression);
+
+    if (do_core)
+      abort();
+
+    return TEST_FAIL;
+  }
+
+  return TEST_PASS;
+}
+
+#define verify(expression) do { if (ensure(expression, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
+#define execute(expression) do { if (ensure(expression == TEST_PASS, #expression, __FILE__, __LINE__) == TEST_FAIL) return TEST_FAIL; } while (0)
+
+/**
+ * Send a chunk of memory over the socket (retry if the call is iterrupted
+ */
+static enum test_return retry_write(const void* buf, size_t len)
+{
+  size_t offset= 0;
+  const char* ptr= static_cast<const char *>(buf);
+
+  do
+  {
+    size_t num_bytes= len - offset;
+    ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes);
+    if (nw == -1)
+      verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
+    else
+      offset+= (size_t)nw;
+  } while (offset < len);
+
+  return TEST_PASS;
+}
+
+/**
+ * Resend a packet to the server (All fields in the command header should
+ * be in network byte order)
+ */
+static enum test_return resend_packet(command *cmd)
+{
+  size_t length= sizeof (protocol_binary_request_no_extras) +
+          ntohl(cmd->plain.message.header.request.bodylen);
+
+  execute(retry_write(cmd, length));
+  return TEST_PASS;
+}
+
+/**
+ * Send a command to the server. The command header needs to be updated
+ * to network byte order
+ */
+static enum test_return send_packet(command *cmd)
+{
+  /* Fix the byteorder of the header */
+  cmd->plain.message.header.request.keylen=
+          ntohs(cmd->plain.message.header.request.keylen);
+  cmd->plain.message.header.request.bodylen=
+          ntohl(cmd->plain.message.header.request.bodylen);
+  cmd->plain.message.header.request.cas=
+          ntohll(cmd->plain.message.header.request.cas);
+
+  execute(resend_packet(cmd));
+  return TEST_PASS;
+}
+
+/**
+ * Read a fixed length chunk of data from the server
+ */
+static enum test_return retry_read(void *buf, size_t len)
+{
+  size_t offset= 0;
+  do
+  {
+    ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset);
+    switch (nr) {
+    case -1 :
+       fprintf(stderr, "Errno: %d %s\n", get_socket_errno(), strerror(errno));
+      verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
+      break;
+    case 0:
+      return TEST_FAIL;
+    default:
+      offset+= (size_t)nr;
+    }
+  } while (offset < len);
+
+  return TEST_PASS;
+}
+
+/**
+ * Receive a response from the server and conver the fields in the header
+ * to local byte order
+ */
+static enum test_return recv_packet(response *rsp)
+{
+  execute(retry_read(rsp, sizeof(protocol_binary_response_no_extras)));
+
+  /* Fix the byte order in the packet header */
+  rsp->plain.message.header.response.keylen=
+          ntohs(rsp->plain.message.header.response.keylen);
+  rsp->plain.message.header.response.status=
+          ntohs(rsp->plain.message.header.response.status);
+  rsp->plain.message.header.response.bodylen=
+          ntohl(rsp->plain.message.header.response.bodylen);
+  rsp->plain.message.header.response.cas=
+          ntohll(rsp->plain.message.header.response.cas);
+
+  size_t bodysz= rsp->plain.message.header.response.bodylen;
+  if (bodysz > 0)
+    execute(retry_read(rsp->bytes + sizeof (protocol_binary_response_no_extras), bodysz));
+
+  return TEST_PASS;
+}
+
+/**
+ * Create a storage command (add, set, replace etc)
+ *
+ * @param cmd destination buffer
+ * @param cc the storage command to create
+ * @param key the key to store
+ * @param keylen the length of the key
+ * @param dta the data to store with the key
+ * @param dtalen the length of the data to store with the key
+ * @param flags the flags to store along with the key
+ * @param exptime the expiry time for the key
+ */
+static void storage_command(command *cmd,
+                            uint8_t cc,
+                            const void* key,
+                            size_t keylen,
+                            const void* dta,
+                            size_t dtalen,
+                            uint32_t flags,
+                            uint32_t exptime)
+{
+  /* all of the storage commands use the same command layout */
+  protocol_binary_request_set *request= &cmd->set;
+
+  memset(request, 0, sizeof (*request));
+  request->message.header.request.magic= PROTOCOL_BINARY_REQ;
+  request->message.header.request.opcode= cc;
+  request->message.header.request.keylen= (uint16_t)keylen;
+  request->message.header.request.extlen= 8;
+  request->message.header.request.bodylen= (uint32_t)(keylen + 8 + dtalen);
+  request->message.header.request.opaque= 0xdeadbeef;
+  request->message.body.flags= flags;
+  request->message.body.expiration= exptime;
+
+  off_t key_offset= sizeof (protocol_binary_request_no_extras) + 8;
+  memcpy(cmd->bytes + key_offset, key, keylen);
+  if (dta != NULL)
+    memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
+}
+
+/**
+ * Create a basic command to send to the server
+ * @param cmd destination buffer
+ * @param cc the command to create
+ * @param key the key to store
+ * @param keylen the length of the key
+ * @param dta the data to store with the key
+ * @param dtalen the length of the data to store with the key
+ */
+static void raw_command(command *cmd,
+                        uint8_t cc,
+                        const void* key,
+                        size_t keylen,
+                        const void* dta,
+                        size_t dtalen)
+{
+  /* all of the storage commands use the same command layout */
+  memset(cmd, 0, sizeof (*cmd));
+  cmd->plain.message.header.request.magic= PROTOCOL_BINARY_REQ;
+  cmd->plain.message.header.request.opcode= cc;
+  cmd->plain.message.header.request.keylen= (uint16_t)keylen;
+  cmd->plain.message.header.request.bodylen= (uint32_t)(keylen + dtalen);
+  cmd->plain.message.header.request.opaque= 0xdeadbeef;
+
+  off_t key_offset= sizeof (protocol_binary_request_no_extras);
+
+  if (key != NULL)
+    memcpy(cmd->bytes + key_offset, key, keylen);
+
+  if (dta != NULL)
+    memcpy(cmd->bytes + key_offset + keylen, dta, dtalen);
+}
+
+/**
+ * Create the flush command
+ * @param cmd destination buffer
+ * @param cc the command to create (FLUSH/FLUSHQ)
+ * @param exptime when to flush
+ * @param use_extra to force using of the extra field?
+ */
+static void flush_command(command *cmd,
+                          uint8_t cc, uint32_t exptime, bool use_extra)
+{
+  memset(cmd, 0, sizeof (cmd->flush));
+  cmd->flush.message.header.request.magic= PROTOCOL_BINARY_REQ;
+  cmd->flush.message.header.request.opcode= cc;
+  cmd->flush.message.header.request.opaque= 0xdeadbeef;
+
+  if (exptime != 0 || use_extra)
+  {
+    cmd->flush.message.header.request.extlen= 4;
+    cmd->flush.message.body.expiration= htonl(exptime);
+    cmd->flush.message.header.request.bodylen= 4;
+  }
+}
+
+/**
+ * Create a incr/decr command
+ * @param cc the cmd to create (FLUSH/FLUSHQ)
+ * @param key the key to operate on
+ * @param keylen the number of bytes in the key
+ * @param delta the number to add/subtract
+ * @param initial the initial value if the key doesn't exist
+ * @param exptime when the key should expire if it isn't set
+ */
+static void arithmetic_command(command *cmd,
+                               uint8_t cc,
+                               const void* key,
+                               size_t keylen,
+                               uint64_t delta,
+                               uint64_t initial,
+                               uint32_t exptime)
+{
+  memset(cmd, 0, sizeof (cmd->incr));
+  cmd->incr.message.header.request.magic= PROTOCOL_BINARY_REQ;
+  cmd->incr.message.header.request.opcode= cc;
+  cmd->incr.message.header.request.keylen= (uint16_t)keylen;
+  cmd->incr.message.header.request.extlen= 20;
+  cmd->incr.message.header.request.bodylen= (uint32_t)(keylen + 20);
+  cmd->incr.message.header.request.opaque= 0xdeadbeef;
+  cmd->incr.message.body.delta= htonll(delta);
+  cmd->incr.message.body.initial= htonll(initial);
+  cmd->incr.message.body.expiration= htonl(exptime);
+
+  off_t key_offset= sizeof (protocol_binary_request_no_extras) + 20;
+  memcpy(cmd->bytes + key_offset, key, keylen);
+}
+
+/**
+ * Validate the response header from the server
+ * @param rsp the response to check
+ * @param cc the expected command
+ * @param status the expected status
+ */
+static enum test_return do_validate_response_header(response *rsp,
+                                                    uint8_t cc, uint16_t status)
+{
+  verify(rsp->plain.message.header.response.magic == PROTOCOL_BINARY_RES);
+  verify(rsp->plain.message.header.response.opcode == cc);
+  verify(rsp->plain.message.header.response.datatype == PROTOCOL_BINARY_RAW_BYTES);
+  verify(rsp->plain.message.header.response.status == status);
+  verify(rsp->plain.message.header.response.opaque == 0xdeadbeef);
+
+  if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS)
+  {
+    switch (cc) {
+    case PROTOCOL_BINARY_CMD_ADDQ:
+    case PROTOCOL_BINARY_CMD_APPENDQ:
+    case PROTOCOL_BINARY_CMD_DECREMENTQ:
+    case PROTOCOL_BINARY_CMD_DELETEQ:
+    case PROTOCOL_BINARY_CMD_FLUSHQ:
+    case PROTOCOL_BINARY_CMD_INCREMENTQ:
+    case PROTOCOL_BINARY_CMD_PREPENDQ:
+    case PROTOCOL_BINARY_CMD_QUITQ:
+    case PROTOCOL_BINARY_CMD_REPLACEQ:
+    case PROTOCOL_BINARY_CMD_SETQ:
+      verify("Quiet command shouldn't return on success" == NULL);
+    default:
+      break;
+    }
+
+    switch (cc) {
+    case PROTOCOL_BINARY_CMD_ADD:
+    case PROTOCOL_BINARY_CMD_REPLACE:
+    case PROTOCOL_BINARY_CMD_SET:
+    case PROTOCOL_BINARY_CMD_APPEND:
+    case PROTOCOL_BINARY_CMD_PREPEND:
+      verify(rsp->plain.message.header.response.keylen == 0);
+      verify(rsp->plain.message.header.response.extlen == 0);
+      verify(rsp->plain.message.header.response.bodylen == 0);
+      verify(rsp->plain.message.header.response.cas != 0);
+      break;
+    case PROTOCOL_BINARY_CMD_FLUSH:
+    case PROTOCOL_BINARY_CMD_NOOP:
+    case PROTOCOL_BINARY_CMD_QUIT:
+    case PROTOCOL_BINARY_CMD_DELETE:
+      verify(rsp->plain.message.header.response.keylen == 0);
+      verify(rsp->plain.message.header.response.extlen == 0);
+      verify(rsp->plain.message.header.response.bodylen == 0);
+      verify(rsp->plain.message.header.response.cas == 0);
+      break;
+
+    case PROTOCOL_BINARY_CMD_DECREMENT:
+    case PROTOCOL_BINARY_CMD_INCREMENT:
+      verify(rsp->plain.message.header.response.keylen == 0);
+      verify(rsp->plain.message.header.response.extlen == 0);
+      verify(rsp->plain.message.header.response.bodylen == 8);
+      verify(rsp->plain.message.header.response.cas != 0);
+      break;
+
+    case PROTOCOL_BINARY_CMD_STAT:
+      verify(rsp->plain.message.header.response.extlen == 0);
+      /* key and value exists in all packets except in the terminating */
+      verify(rsp->plain.message.header.response.cas == 0);
+      break;
+
+    case PROTOCOL_BINARY_CMD_VERSION:
+      verify(rsp->plain.message.header.response.keylen == 0);
+      verify(rsp->plain.message.header.response.extlen == 0);
+      verify(rsp->plain.message.header.response.bodylen != 0);
+      verify(rsp->plain.message.header.response.cas == 0);
+      break;
+
+    case PROTOCOL_BINARY_CMD_GET:
+    case PROTOCOL_BINARY_CMD_GETQ:
+      verify(rsp->plain.message.header.response.keylen == 0);
+      verify(rsp->plain.message.header.response.extlen == 4);
+      verify(rsp->plain.message.header.response.cas != 0);
+      break;
+
+    case PROTOCOL_BINARY_CMD_GETK:
+    case PROTOCOL_BINARY_CMD_GETKQ:
+      verify(rsp->plain.message.header.response.keylen != 0);
+      verify(rsp->plain.message.header.response.extlen == 4);
+      verify(rsp->plain.message.header.response.cas != 0);
+      break;
+
+    default:
+      /* Undefined command code */
+      break;
+    }
+  }
+  else
+  {
+    verify(rsp->plain.message.header.response.cas == 0);
+    verify(rsp->plain.message.header.response.extlen == 0);
+    if (cc != PROTOCOL_BINARY_CMD_GETK)
+    {
+      verify(rsp->plain.message.header.response.keylen == 0);
+    }
+  }
+
+  return TEST_PASS;
+}
+
+/* We call verify(validate_response_header), but that macro
+ * expects a boolean expression, and the function returns
+ * an enum.... Let's just create a macro to avoid cluttering
+ * the code with all of the == TEST_PASS ;-)
+ */
+#define validate_response_header(a,b,c) \
+        do_validate_response_header(a,b,c) == TEST_PASS
+
+
+static enum test_return send_binary_noop(void)
+{
+  command cmd;
+  raw_command(&cmd, PROTOCOL_BINARY_CMD_NOOP, NULL, 0, NULL, 0);
+  execute(send_packet(&cmd));
+  return TEST_PASS;
+}
+
+static enum test_return receive_binary_noop(void)
+{
+  response rsp;
+  execute(recv_packet(&rsp));
+  verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_NOOP,
+                                  PROTOCOL_BINARY_RESPONSE_SUCCESS));
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_noop(void)
+{
+  execute(send_binary_noop());
+  execute(receive_binary_noop());
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_quit_impl(uint8_t cc)
+{
+  command cmd;
+  response rsp;
+  raw_command(&cmd, cc, NULL, 0, NULL, 0);
+
+  execute(send_packet(&cmd));
+  if (cc == PROTOCOL_BINARY_CMD_QUIT)
+  {
+    execute(recv_packet(&rsp));
+    verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_QUIT,
+                                    PROTOCOL_BINARY_RESPONSE_SUCCESS));
+  }
+
+  /* Socket should be closed now, read should return EXIT_SUCCESS */
+  verify(timeout_io_op(sock, POLLIN, rsp.bytes, sizeof(rsp.bytes)) == 0);
+
+  return TEST_PASS_RECONNECT;
+}
+
+static enum test_return test_binary_quit(void)
+{
+  return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUIT);
+}
+
+static enum test_return test_binary_quitq(void)
+{
+  return test_binary_quit_impl(PROTOCOL_BINARY_CMD_QUITQ);
+}
+
+static enum test_return test_binary_set_impl(const char* key, uint8_t cc)
+{
+  command cmd;
+  response rsp;
+
+  uint64_t value= 0xdeadbeefdeadcafe;
+  storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
+
+  /* set should always work */
+  for (int ii= 0; ii < 10; ii++)
+  {
+    if (ii == 0)
+      execute(send_packet(&cmd));
+    else
+      execute(resend_packet(&cmd));
+
+    if (cc == PROTOCOL_BINARY_CMD_SET)
+    {
+      execute(recv_packet(&rsp));
+      verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+    }
+    else
+      execute(test_binary_noop());
+  }
+
+  /*
+   * We need to get the current CAS id, and at this time we haven't
+   * verified that we have a working get
+   */
+  if (cc == PROTOCOL_BINARY_CMD_SETQ)
+  {
+    cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SET;
+    execute(resend_packet(&cmd));
+    execute(recv_packet(&rsp));
+    verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
+                                    PROTOCOL_BINARY_RESPONSE_SUCCESS));
+    cmd.set.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
+  }
+
+  /* try to set with the correct CAS value */
+  cmd.plain.message.header.request.cas=
+          htonll(rsp.plain.message.header.response.cas);
+  execute(resend_packet(&cmd));
+  if (cc == PROTOCOL_BINARY_CMD_SET)
+  {
+    execute(recv_packet(&rsp));
+    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+  }
+  else
+    execute(test_binary_noop());
+
+  /* try to set with an incorrect CAS value */
+  cmd.plain.message.header.request.cas=
+          htonll(rsp.plain.message.header.response.cas - 1);
+  execute(resend_packet(&cmd));
+  execute(send_binary_noop());
+  execute(recv_packet(&rsp));
+  verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
+  execute(receive_binary_noop());
+
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_set(void)
+{
+  return test_binary_set_impl("test_binary_set", PROTOCOL_BINARY_CMD_SET);
+}
+
+static enum test_return test_binary_setq(void)
+{
+  return test_binary_set_impl("test_binary_setq", PROTOCOL_BINARY_CMD_SETQ);
+}
+
+static enum test_return test_binary_add_impl(const char* key, uint8_t cc)
+{
+  command cmd;
+  response rsp;
+  uint64_t value= 0xdeadbeefdeadcafe;
+  storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
+
+  /* first add should work, rest of them should fail (even with cas
+     as wildcard */
+  for (int ii=0; ii < 10; ii++)
+  {
+    if (ii == 0)
+      execute(send_packet(&cmd));
+    else
+      execute(resend_packet(&cmd));
+
+    if (cc == PROTOCOL_BINARY_CMD_ADD || ii > 0)
+    {
+      uint16_t expected_result;
+      if (ii == 0)
+        expected_result= PROTOCOL_BINARY_RESPONSE_SUCCESS;
+      else
+        expected_result= PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
+
+      execute(send_binary_noop());
+      execute(recv_packet(&rsp));
+      execute(receive_binary_noop());
+      verify(validate_response_header(&rsp, cc, expected_result));
+    }
+    else
+      execute(test_binary_noop());
+  }
+
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_add(void)
+{
+  return test_binary_add_impl("test_binary_add", PROTOCOL_BINARY_CMD_ADD);
+}
+
+static enum test_return test_binary_addq(void)
+{
+  return test_binary_add_impl("test_binary_addq", PROTOCOL_BINARY_CMD_ADDQ);
+}
+
+static enum test_return binary_set_item(const char *key, const char *value)
+{
+  command cmd;
+  response rsp;
+  storage_command(&cmd, PROTOCOL_BINARY_CMD_SET, key, strlen(key),
+                  value, strlen(value), 0, 0);
+  execute(send_packet(&cmd));
+  execute(recv_packet(&rsp));
+  verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_SET,
+                                  PROTOCOL_BINARY_RESPONSE_SUCCESS));
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_replace_impl(const char* key, uint8_t cc)
+{
+  command cmd;
+  response rsp;
+  uint64_t value= 0xdeadbeefdeadcafe;
+  storage_command(&cmd, cc, key, strlen(key), &value, sizeof (value), 0, 0);
+
+  /* first replace should fail, successive should succeed (when the
+     item is added! */
+  for (int ii= 0; ii < 10; ii++)
+  {
+    if (ii == 0)
+      execute(send_packet(&cmd));
+    else
+      execute(resend_packet(&cmd));
+
+    if (cc == PROTOCOL_BINARY_CMD_REPLACE || ii == 0)
+    {
+      uint16_t expected_result;
+      if (ii == 0)
+        expected_result=PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
+      else
+        expected_result=PROTOCOL_BINARY_RESPONSE_SUCCESS;
+
+      execute(send_binary_noop());
+      execute(recv_packet(&rsp));
+      execute(receive_binary_noop());
+      verify(validate_response_header(&rsp, cc, expected_result));
+
+      if (ii == 0)
+        execute(binary_set_item(key, key));
+    }
+    else
+      execute(test_binary_noop());
+  }
+
+  /* verify that replace with CAS value works! */
+  cmd.plain.message.header.request.cas=
+          htonll(rsp.plain.message.header.response.cas);
+  execute(resend_packet(&cmd));
+
+  if (cc == PROTOCOL_BINARY_CMD_REPLACE)
+  {
+    execute(recv_packet(&rsp));
+    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+  }
+  else
+    execute(test_binary_noop());
+
+  /* try to set with an incorrect CAS value */
+  cmd.plain.message.header.request.cas=
+          htonll(rsp.plain.message.header.response.cas - 1);
+  execute(resend_packet(&cmd));
+  execute(send_binary_noop());
+  execute(recv_packet(&rsp));
+  execute(receive_binary_noop());
+  verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS));
+
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_replace(void)
+{
+  return test_binary_replace_impl("test_binary_replace", PROTOCOL_BINARY_CMD_REPLACE);
+}
+
+static enum test_return test_binary_replaceq(void)
+{
+  return test_binary_replace_impl("test_binary_replaceq", PROTOCOL_BINARY_CMD_REPLACEQ);
+}
+
+static enum test_return test_binary_delete_impl(const char *key, uint8_t cc)
+{
+  command cmd;
+  response rsp;
+  raw_command(&cmd, cc, key, strlen(key), NULL, 0);
+
+  /* The delete shouldn't work the first time, because the item isn't there */
+  execute(send_packet(&cmd));
+  execute(send_binary_noop());
+  execute(recv_packet(&rsp));
+  verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
+  execute(receive_binary_noop());
+  execute(binary_set_item(key, key));
+
+  /* The item should be present now, resend*/
+  execute(resend_packet(&cmd));
+  if (cc == PROTOCOL_BINARY_CMD_DELETE)
+  {
+    execute(recv_packet(&rsp));
+    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+  }
+
+  execute(test_binary_noop());
+
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_delete(void)
+{
+  return test_binary_delete_impl("test_binary_delete", PROTOCOL_BINARY_CMD_DELETE);
+}
+
+static enum test_return test_binary_deleteq(void)
+{
+  return test_binary_delete_impl("test_binary_deleteq", PROTOCOL_BINARY_CMD_DELETEQ);
+}
+
+static enum test_return test_binary_get_impl(const char *key, uint8_t cc)
+{
+  command cmd;
+  response rsp;
+
+  raw_command(&cmd, cc, key, strlen(key), NULL, 0);
+  execute(send_packet(&cmd));
+  execute(send_binary_noop());
+
+  if (cc == PROTOCOL_BINARY_CMD_GET || cc == PROTOCOL_BINARY_CMD_GETK)
+  {
+    execute(recv_packet(&rsp));
+    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
+  }
+
+  execute(receive_binary_noop());
+
+  execute(binary_set_item(key, key));
+  execute(resend_packet(&cmd));
+  execute(send_binary_noop());
+
+  execute(recv_packet(&rsp));
+  verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+  execute(receive_binary_noop());
+
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_get(void)
+{
+  return test_binary_get_impl("test_binary_get", PROTOCOL_BINARY_CMD_GET);
+}
+
+static enum test_return test_binary_getk(void)
+{
+  return test_binary_get_impl("test_binary_getk", PROTOCOL_BINARY_CMD_GETK);
+}
+
+static enum test_return test_binary_getq(void)
+{
+  return test_binary_get_impl("test_binary_getq", PROTOCOL_BINARY_CMD_GETQ);
+}
+
+static enum test_return test_binary_getkq(void)
+{
+  return test_binary_get_impl("test_binary_getkq", PROTOCOL_BINARY_CMD_GETKQ);
+}
+
+static enum test_return test_binary_incr_impl(const char* key, uint8_t cc)
+{
+  command cmd;
+  response rsp;
+  arithmetic_command(&cmd, cc, key, strlen(key), 1, 0, 0);
+
+  uint64_t ii;
+  for (ii= 0; ii < 10; ++ii)
+  {
+    if (ii == 0)
+      execute(send_packet(&cmd));
+    else
+      execute(resend_packet(&cmd));
+
+    if (cc == PROTOCOL_BINARY_CMD_INCREMENT)
+    {
+      execute(recv_packet(&rsp));
+      verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+      verify(ntohll(rsp.incr.message.body.value) == ii);
+    }
+    else
+      execute(test_binary_noop());
+  }
+
+  /* @todo add incorrect CAS */
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_incr(void)
+{
+  return test_binary_incr_impl("test_binary_incr", PROTOCOL_BINARY_CMD_INCREMENT);
+}
+
+static enum test_return test_binary_incrq(void)
+{
+  return test_binary_incr_impl("test_binary_incrq", PROTOCOL_BINARY_CMD_INCREMENTQ);
+}
+
+static enum test_return test_binary_decr_impl(const char* key, uint8_t cc)
+{
+  command cmd;
+  response rsp;
+  arithmetic_command(&cmd, cc, key, strlen(key), 1, 9, 0);
+
+  int ii;
+  for (ii= 9; ii > -1; --ii)
+  {
+    if (ii == 9)
+      execute(send_packet(&cmd));
+    else
+      execute(resend_packet(&cmd));
+
+    if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
+    {
+      execute(recv_packet(&rsp));
+      verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+      verify(ntohll(rsp.decr.message.body.value) == (uint64_t)ii);
+    }
+    else
+      execute(test_binary_noop());
+  }
+
+  /* decr 0 should not wrap */
+  execute(resend_packet(&cmd));
+  if (cc == PROTOCOL_BINARY_CMD_DECREMENT)
+  {
+    execute(recv_packet(&rsp));
+    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+    verify(ntohll(rsp.decr.message.body.value) == 0);
+  }
+  else
+  {
+    /* @todo get the value and verify! */
+
+  }
+
+  /* @todo add incorrect cas */
+  execute(test_binary_noop());
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_decr(void)
+{
+  return test_binary_decr_impl("test_binary_decr",
+                               PROTOCOL_BINARY_CMD_DECREMENT);
+}
+
+static enum test_return test_binary_decrq(void)
+{
+  return test_binary_decr_impl("test_binary_decrq",
+                               PROTOCOL_BINARY_CMD_DECREMENTQ);
+}
+
+static enum test_return test_binary_version(void)
+{
+  command cmd;
+  response rsp;
+  raw_command(&cmd, PROTOCOL_BINARY_CMD_VERSION, NULL, 0, NULL, 0);
+
+  execute(send_packet(&cmd));
+  execute(recv_packet(&rsp));
+  verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_VERSION,
+                                  PROTOCOL_BINARY_RESPONSE_SUCCESS));
+
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_flush_impl(const char *key, uint8_t cc)
+{
+  command cmd;
+  response rsp;
+
+  for (int ii= 0; ii < 2; ++ii)
+  {
+    execute(binary_set_item(key, key));
+    flush_command(&cmd, cc, 0, ii == 0);
+    execute(send_packet(&cmd));
+
+    if (cc == PROTOCOL_BINARY_CMD_FLUSH)
+    {
+      execute(recv_packet(&rsp));
+      verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+    }
+    else
+      execute(test_binary_noop());
+
+    raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
+    execute(send_packet(&cmd));
+    execute(recv_packet(&rsp));
+    verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
+                                    PROTOCOL_BINARY_RESPONSE_KEY_ENOENT));
+  }
+
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_flush(void)
+{
+  return test_binary_flush_impl("test_binary_flush", PROTOCOL_BINARY_CMD_FLUSH);
+}
+
+static enum test_return test_binary_flushq(void)
+{
+  return test_binary_flush_impl("test_binary_flushq", PROTOCOL_BINARY_CMD_FLUSHQ);
+}
+
+static enum test_return test_binary_concat_impl(const char *key, uint8_t cc)
+{
+  command cmd;
+  response rsp;
+  const char *value;
+
+  if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
+    value="hello";
+  else
+    value=" world";
+
+  execute(binary_set_item(key, value));
+
+  if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_APPENDQ)
+    value=" world";
+  else
+    value="hello";
+
+  raw_command(&cmd, cc, key, strlen(key), value, strlen(value));
+  execute(send_packet(&cmd));
+  if (cc == PROTOCOL_BINARY_CMD_APPEND || cc == PROTOCOL_BINARY_CMD_PREPEND)
+  {
+    execute(recv_packet(&rsp));
+    verify(validate_response_header(&rsp, cc, PROTOCOL_BINARY_RESPONSE_SUCCESS));
+  }
+  else
+    execute(test_binary_noop());
+
+  raw_command(&cmd, PROTOCOL_BINARY_CMD_GET, key, strlen(key), NULL, 0);
+  execute(send_packet(&cmd));
+  execute(recv_packet(&rsp));
+  verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_GET,
+                                  PROTOCOL_BINARY_RESPONSE_SUCCESS));
+  verify(rsp.plain.message.header.response.bodylen - 4 == 11);
+  verify(memcmp(rsp.bytes + 28, "hello world", 11) == 0);
+
+  return TEST_PASS;
+}
+
+static enum test_return test_binary_append(void)
+{
+  return test_binary_concat_impl("test_binary_append", PROTOCOL_BINARY_CMD_APPEND);
+}
+
+static enum test_return test_binary_prepend(void)
+{
+  return test_binary_concat_impl("test_binary_prepend", PROTOCOL_BINARY_CMD_PREPEND);
+}
+
+static enum test_return test_binary_appendq(void)
+{
+  return test_binary_concat_impl("test_binary_appendq", PROTOCOL_BINARY_CMD_APPENDQ);
+}
+
+static enum test_return test_binary_prependq(void)
+{
+  return test_binary_concat_impl("test_binary_prependq", PROTOCOL_BINARY_CMD_PREPENDQ);
+}
+
+static enum test_return test_binary_stat(void)
+{
+  command cmd;
+  response rsp;
+
+  raw_command(&cmd, PROTOCOL_BINARY_CMD_STAT, NULL, 0, NULL, 0);
+  execute(send_packet(&cmd));
+
+  do
+  {
+    execute(recv_packet(&rsp));
+    verify(validate_response_header(&rsp, PROTOCOL_BINARY_CMD_STAT,
+                                    PROTOCOL_BINARY_RESPONSE_SUCCESS));
+  } while (rsp.plain.message.header.response.keylen != 0);
+
+  return TEST_PASS;
+}
+
+static enum test_return send_string(const char *cmd)
+{
+  execute(retry_write(cmd, strlen(cmd)));
+  return TEST_PASS;
+}
+
+static enum test_return receive_line(char *buffer, size_t size)
+{
+  size_t offset= 0;
+  while (offset < size)
+  {
+    execute(retry_read(buffer + offset, 1));
+    if (buffer[offset] == '\n')
+    {
+      if (offset + 1 < size)
+      {
+        buffer[offset + 1]= '\0';
+        return TEST_PASS;
+      }
+      else
+        return TEST_FAIL;
+    }
+    ++offset;
+  }
+
+  return TEST_FAIL;
+}
+
+static enum test_return receive_response(const char *msg) {
+  char buffer[80];
+  execute(receive_line(buffer, sizeof(buffer)));
+  if (strcmp(msg, buffer) != 0) {
+      fprintf(stderr, "[%s]\n", buffer);
+  }
+  verify(strcmp(msg, buffer) == 0);
+  return TEST_PASS;
+}
+
+static enum test_return receive_error_response(void)
+{
+  char buffer[80];
+  execute(receive_line(buffer, sizeof(buffer)));
+  verify(strncmp(buffer, "ERROR", 5) == 0 ||
+         strncmp(buffer, "CLIENT_ERROR", 12) == 0 ||
+         strncmp(buffer, "SERVER_ERROR", 12) == 0);
+  return TEST_PASS;
+}
+
+static enum test_return test_ascii_quit(void)
+{
+  /* Verify that quit handles unknown options */
+  execute(send_string("quit foo bar\r\n"));
+  execute(receive_error_response());
+
+  /* quit doesn't support noreply */
+  execute(send_string("quit noreply\r\n"));
+  execute(receive_error_response());
+
+  /* Verify that quit works */
+  execute(send_string("quit\r\n"));
+
+  /* Socket should be closed now, read should return EXIT_SUCCESS */
+  char buffer[80];
+  verify(timeout_io_op(sock, POLLIN, buffer, sizeof(buffer)) == 0);
+  return TEST_PASS_RECONNECT;
+
+}
+
+static enum test_return test_ascii_version(void)
+{
+  /* Verify that version command handles unknown options */
+  execute(send_string("version foo bar\r\n"));
+  execute(receive_error_response());
+
+  /* version doesn't support noreply */
+  execute(send_string("version noreply\r\n"));
+  execute(receive_error_response());
+
+  /* Verify that verify works */
+  execute(send_string("version\r\n"));
+  char buffer[256];
+  execute(receive_line(buffer, sizeof(buffer)));
+  verify(strncmp(buffer, "VERSION ", 8) == 0);
+
+  return TEST_PASS;
+}
+
+static enum test_return test_ascii_verbosity(void)
+{
+  /* This command does not adhere to the spec! */
+  execute(send_string("verbosity foo bar my\r\n"));
+  execute(receive_error_response());
+
+  execute(send_string("verbosity noreply\r\n"));
+  execute(receive_error_response());
+
+  execute(send_string("verbosity 0 noreply\r\n"));
+  execute(test_ascii_version());
+
+  execute(send_string("verbosity\r\n"));
+  execute(receive_error_response());
+
+  execute(send_string("verbosity 1\r\n"));
+  execute(receive_response("OK\r\n"));
+
+  execute(send_string("verbosity 0\r\n"));
+  execute(receive_response("OK\r\n"));
+
+  return TEST_PASS;
+}
+
+
+
+static enum test_return test_ascii_set_impl(const char* key, bool noreply)
+{
+  /* @todo add tests for bogus format! */
+  char buffer[1024];
+  snprintf(buffer, sizeof(buffer), "set %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
+  execute(send_string(buffer));
+
+  if (!noreply)
+    execute(receive_response("STORED\r\n"));
+
+  return test_ascii_version();
+}
+
+static enum test_return test_ascii_set(void)
+{
+  return test_ascii_set_impl("test_ascii_set", false);
+}
+
+static enum test_return test_ascii_set_noreply(void)
+{
+  return test_ascii_set_impl("test_ascii_set_noreply", true);
+}
+
+static enum test_return test_ascii_add_impl(const char* key, bool noreply)
+{
+  /* @todo add tests for bogus format! */
+  char buffer[1024];
+  snprintf(buffer, sizeof(buffer), "add %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
+  execute(send_string(buffer));
+
+  if (!noreply)
+    execute(receive_response("STORED\r\n"));
+
+  execute(send_string(buffer));
+
+  if (!noreply)
+    execute(receive_response("NOT_STORED\r\n"));
+
+  return test_ascii_version();
+}
+
+static enum test_return test_ascii_add(void)
+{
+  return test_ascii_add_impl("test_ascii_add", false);
+}
+
+static enum test_return test_ascii_add_noreply(void)
+{
+  return test_ascii_add_impl("test_ascii_add_noreply", true);
+}
+
+static enum test_return ascii_get_unknown_value(char **key, char **value, ssize_t *ndata)
+{
+  char buffer[1024];
+
+  execute(receive_line(buffer, sizeof(buffer)));
+  verify(strncmp(buffer, "VALUE ", 6) == 0);
+  char *end= strchr(buffer + 6, ' ');
+  verify(end != NULL);
+  *end= '\0';
+  *key= strdup(buffer + 6);
+  verify(*key != NULL);
+  char *ptr= end + 1;
+
+  unsigned long val= strtoul(ptr, &end, 10); /* flags */
+  verify(ptr != end);
+  verify(val == 0);
+  verify(end != NULL);
+  *ndata = (ssize_t)strtoul(end, &end, 10); /* size */
+  verify(ptr != end);
+  verify(end != NULL);
+  while (*end != '\n' && isspace(*end))
+    ++end;
+  verify(*end == '\n');
+
+  *value= static_cast<char*>(malloc((size_t)*ndata));
+  verify(*value != NULL);
+
+  execute(retry_read(*value, (size_t)*ndata));
+
+  execute(retry_read(buffer, 2));
+  verify(memcmp(buffer, "\r\n", 2) == 0);
+
+  return TEST_PASS;
+}
+
+static enum test_return ascii_get_value(const char *key, const char *value)
+{
+
+  char buffer[1024];
+  size_t datasize= strlen(value);
+
+  verify(datasize < sizeof(buffer));
+  execute(receive_line(buffer, sizeof(buffer)));
+  verify(strncmp(buffer, "VALUE ", 6) == 0);
+  verify(strncmp(buffer + 6, key, strlen(key)) == 0);
+  char *ptr= buffer + 6 + strlen(key) + 1;
+  char *end;
+
+  unsigned long val= strtoul(ptr, &end, 10); /* flags */
+  verify(ptr != end);
+  verify(val == 0);
+  verify(end != NULL);
+  val= strtoul(end, &end, 10); /* size */
+  verify(ptr != end);
+  verify(val == datasize);
+  verify(end != NULL);
+  while (*end != '\n' && isspace(*end))
+    ++end;
+  verify(*end == '\n');
+
+  execute(retry_read(buffer, datasize));
+  verify(memcmp(buffer, value, datasize) == 0);
+
+  execute(retry_read(buffer, 2));
+  verify(memcmp(buffer, "\r\n", 2) == 0);
+
+  return TEST_PASS;
+}
+
+static enum test_return ascii_get_item(const char *key, const char *value,
+                                       bool exist)
+{
+  char buffer[1024];
+  size_t datasize= 0;
+  if (value != NULL)
+    datasize= strlen(value);
+
+  verify(datasize < sizeof(buffer));
+  snprintf(buffer, sizeof(buffer), "get %s\r\n", key);
+  execute(send_string(buffer));
+
+  if (exist)
+    execute(ascii_get_value(key, value));
+
+  execute(retry_read(buffer, 5));
+  verify(memcmp(buffer, "END\r\n", 5) == 0);
+
+  return TEST_PASS;
+}
+
+static enum test_return ascii_gets_value(const char *key, const char *value,
+                                         unsigned long *cas)
+{
+
+  char buffer[1024];
+  size_t datasize= strlen(value);
+
+  verify(datasize < sizeof(buffer));
+  execute(receive_line(buffer, sizeof(buffer)));
+  verify(strncmp(buffer, "VALUE ", 6) == 0);
+  verify(strncmp(buffer + 6, key, strlen(key)) == 0);
+  char *ptr= buffer + 6 + strlen(key) + 1;
+  char *end;
+
+  unsigned long val= strtoul(ptr, &end, 10); /* flags */
+  verify(ptr != end);
+  verify(val == 0);
+  verify(end != NULL);
+  val= strtoul(end, &end, 10); /* size */
+  verify(ptr != end);
+  verify(val == datasize);
+  verify(end != NULL);
+  *cas= strtoul(end, &end, 10); /* cas */
+  verify(ptr != end);
+  verify(val == datasize);
+  verify(end != NULL);
+
+  while (*end != '\n' && isspace(*end))
+    ++end;
+  verify(*end == '\n');
+
+  execute(retry_read(buffer, datasize));
+  verify(memcmp(buffer, value, datasize) == 0);
+
+  execute(retry_read(buffer, 2));
+  verify(memcmp(buffer, "\r\n", 2) == 0);
+
+  return TEST_PASS;
+}
+
+static enum test_return ascii_gets_item(const char *key, const char *value,
+                                        bool exist, unsigned long *cas)
+{
+  char buffer[1024];
+  size_t datasize= 0;
+  if (value != NULL)
+    datasize= strlen(value);
+
+  verify(datasize < sizeof(buffer));
+  snprintf(buffer, sizeof(buffer), "gets %s\r\n", key);
+  execute(send_string(buffer));
+
+  if (exist)
+    execute(ascii_gets_value(key, value, cas));
+
+  execute(retry_read(buffer, 5));
+  verify(memcmp(buffer, "END\r\n", 5) == 0);
+
+  return TEST_PASS;
+}
+
+static enum test_return ascii_set_item(const char *key, const char *value)
+{
+  char buffer[300];
+  size_t len= strlen(value);
+  snprintf(buffer, sizeof(buffer), "set %s 0 0 %u\r\n", key, (unsigned int)len);
+  execute(send_string(buffer));
+  execute(retry_write(value, len));
+  execute(send_string("\r\n"));
+  execute(receive_response("STORED\r\n"));
+  return TEST_PASS;
+}
+
+static enum test_return test_ascii_replace_impl(const char* key, bool noreply)
+{
+  char buffer[1024];
+  snprintf(buffer, sizeof(buffer), "replace %s 0 0 5%s\r\nvalue\r\n", key, noreply ? " noreply" : "");
+  execute(send_string(buffer));
+
+  if (noreply)
+    execute(test_ascii_version());
+  else
+    execute(receive_response("NOT_STORED\r\n"));
+
+  execute(ascii_set_item(key, "value"));
+  execute(ascii_get_item(key, "value", true));
+
+
+  execute(send_string(buffer));
+
+  if (noreply)
+    execute(test_ascii_version());
+  else
+    execute(receive_response("STORED\r\n"));
+
+  return test_ascii_version();
+}
+
+static enum test_return test_ascii_replace(void)
+{
+  return test_ascii_replace_impl("test_ascii_replace", false);
+}
+
+static enum test_return test_ascii_replace_noreply(void)
+{
+  return test_ascii_replace_impl("test_ascii_replace_noreply", true);
+}
+
+static enum test_return test_ascii_cas_impl(const char* key, bool noreply)
+{
+  char buffer[1024];
+  unsigned long cas;
+
+  execute(ascii_set_item(key, "value"));
+  execute(ascii_gets_item(key, "value", true, &cas));
+
+  snprintf(buffer, sizeof(buffer), "cas %s 0 0 6 %lu%s\r\nvalue2\r\n", key, cas, noreply ? " noreply" : "");
+  execute(send_string(buffer));
+
+  if (noreply)
+    execute(test_ascii_version());
+  else
+    execute(receive_response("STORED\r\n"));
+
+  /* reexecute the same command should fail due to illegal cas */
+  execute(send_string(buffer));
+
+  if (noreply)
+    execute(test_ascii_version());
+  else
+    execute(receive_response("EXISTS\r\n"));
+
+  return test_ascii_version();
+}
+
+static enum test_return test_ascii_cas(void)
+{
+  return test_ascii_cas_impl("test_ascii_cas", false);
+}
+
+static enum test_return test_ascii_cas_noreply(void)
+{
+  return test_ascii_cas_impl("test_ascii_cas_noreply", true);
+}
+
+static enum test_return test_ascii_delete_impl(const char *key, bool noreply)
+{
+  execute(ascii_set_item(key, "value"));
+
+  execute(send_string("delete\r\n"));
+  execute(receive_error_response());
+  /* BUG: the server accepts delete a b */
+  execute(send_string("delete a b c d e\r\n"));
+  execute(receive_error_response());
+
+  char buffer[1024];
+  snprintf(buffer, sizeof(buffer), "delete %s%s\r\n", key, noreply ? " noreply" : "");
+  execute(send_string(buffer));
+
+  if (noreply)
+    execute(test_ascii_version());
+  else
+    execute(receive_response("DELETED\r\n"));
+
+  execute(ascii_get_item(key, "value", false));
+  execute(send_string(buffer));
+  if (noreply)
+    execute(test_ascii_version());
+  else
+    execute(receive_response("NOT_FOUND\r\n"));
+
+  return TEST_PASS;
+}
+
+static enum test_return test_ascii_delete(void)
+{
+  return test_ascii_delete_impl("test_ascii_delete", false);
+}
+
+static enum test_return test_ascii_delete_noreply(void)
+{
+  return test_ascii_delete_impl("test_ascii_delete_noreply", true);
+}
+
+static enum test_return test_ascii_get(void)
+{
+  execute(ascii_set_item("test_ascii_get", "value"));
+
+  execute(send_string("get\r\n"));
+  execute(receive_error_response());
+  execute(ascii_get_item("test_ascii_get", "value", true));
+  execute(ascii_get_item("test_ascii_get_notfound", "value", false));
+
+  return TEST_PASS;
+}
+
+static enum test_return test_ascii_gets(void)
+{
+  execute(ascii_set_item("test_ascii_gets", "value"));
+
+  execute(send_string("gets\r\n"));
+  execute(receive_error_response());
+  unsigned long cas;
+  execute(ascii_gets_item("test_ascii_gets", "value", true, &cas));
+  execute(ascii_gets_item("test_ascii_gets_notfound", "value", false, &cas));
+
+  return TEST_PASS;
+}
+
+static enum test_return test_ascii_mget(void)
+{
+  const uint32_t nkeys= 5;
+  const char * const keys[]= {
+    "test_ascii_mget1",
+    "test_ascii_mget2",
+    /* test_ascii_mget_3 does not exist :) */
+    "test_ascii_mget4",
+    "test_ascii_mget5",
+    "test_ascii_mget6"
+  };
+
+  for (uint32_t x= 0; x < nkeys; ++x)
+    execute(ascii_set_item(keys[x], "value"));
+
+  /* Ask for a key that doesn't exist as well */
+  execute(send_string("get test_ascii_mget1 test_ascii_mget2 test_ascii_mget3 "
+                      "test_ascii_mget4 test_ascii_mget5 "
+                      "test_ascii_mget6\r\n"));
+
+  char *returned[nkeys];
+
+  for (uint32_t x= 0; x < nkeys; ++x)
+  {
+    ssize_t nbytes = 0;
+    char *v= NULL;
+    execute(ascii_get_unknown_value(&returned[x], &v, &nbytes));
+    verify(nbytes == 5);
+    verify(memcmp(v, "value", 5) == 0);
+    free(v);
+  }
+
+  char buffer[5];
+  execute(retry_read(buffer, 5));
+  verify(memcmp(buffer, "END\r\n", 5) == 0);
+
+  /* verify that we got all the keys we expected */
+  for (uint32_t x= 0; x < nkeys; ++x)
+  {
+    bool found= false;
+    for (uint32_t y= 0; y < nkeys; ++y)
+    {
+      if (strcmp(keys[x], returned[y]) == 0)
+      {
+        found = true;
+        break;
+      }
+    }
+    verify(found);
+  }
+
+  for (uint32_t x= 0; x < nkeys; ++x)
+    free(returned[x]);
+
+  return TEST_PASS;
+}
+
+static enum test_return test_ascii_incr_impl(const char* key, bool noreply)
+{
+  char cmd[300];
+  snprintf(cmd, sizeof(cmd), "incr %s 1%s\r\n", key, noreply ? " noreply" : "");
+
+  execute(ascii_set_item(key, "0"));
+  for (int x= 1; x < 11; ++x)
+  {
+    execute(send_string(cmd));
+
+    if (noreply)
+      execute(test_ascii_version());
+    else
+    {
+      char buffer[80];
+      execute(receive_line(buffer, sizeof(buffer)));
+      int val= atoi(buffer);
+      verify(val == x);
+    }
+  }
+
+  execute(ascii_get_item(key, "10", true));
+
+  return TEST_PASS;
+}
+
+static enum test_return test_ascii_incr(void)
+{
+  return test_ascii_incr_impl("test_ascii_incr", false);
+}
+
+static enum test_return test_ascii_incr_noreply(void)
+{
+  return test_ascii_incr_impl("test_ascii_incr_noreply", true);
+}
+
+static enum test_return test_ascii_decr_impl(const char* key, bool noreply)
+{
+  char cmd[300];
+  snprintf(cmd, sizeof(cmd), "decr %s 1%s\r\n", key, noreply ? " noreply" : "");
+
+  execute(ascii_set_item(key, "9"));
+  for (int x= 8; x > -1; --x)
+  {
+    execute(send_string(cmd));
+
+    if (noreply)
+      execute(test_ascii_version());
+    else
+    {
+      char buffer[80];
+      execute(receive_line(buffer, sizeof(buffer)));
+      int val= atoi(buffer);
+      verify(val == x);
+    }
+  }
+
+  execute(ascii_get_item(key, "0", true));
+
+  /* verify that it doesn't wrap */
+  execute(send_string(cmd));
+  if (noreply)
+    execute(test_ascii_version());
+  else
+  {
+    char buffer[80];
+    execute(receive_line(buffer, sizeof(buffer)));
+  }
+  execute(ascii_get_item(key, "0", true));
+
+  return TEST_PASS;
+}
+
+static enum test_return test_ascii_decr(void)
+{
+  return test_ascii_decr_impl("test_ascii_decr", false);
+}
+
+static enum test_return test_ascii_decr_noreply(void)
+{
+  return test_ascii_decr_impl("test_ascii_decr_noreply", true);
+}
+
+
+static enum test_return test_ascii_flush_impl(const char *key, bool noreply)
+{
+#if 0
+  /* Verify that the flush_all command handles unknown options */
+  /* Bug in the current memcached server! */
+  execute(send_string("flush_all foo bar\r\n"));
+  execute(receive_error_response());
+#endif
+
+  execute(ascii_set_item(key, key));
+  execute(ascii_get_item(key, key, true));
+
+  if (noreply)
+  {
+    execute(send_string("flush_all noreply\r\n"));
+    execute(test_ascii_version());
+  }
+  else
+  {
+    execute(send_string("flush_all\r\n"));
+    execute(receive_response("OK\r\n"));
+  }
+
+  execute(ascii_get_item(key, key, false));
+
+  return TEST_PASS;
+}
+
+static enum test_return test_ascii_flush(void)
+{
+  return test_ascii_flush_impl("test_ascii_flush", false);
+}
+
+static enum test_return test_ascii_flush_noreply(void)
+{
+  return test_ascii_flush_impl("test_ascii_flush_noreply", true);
+}
+
+static enum test_return test_ascii_concat_impl(const char *key,
+                                               bool append,
+                                               bool noreply)
+{
+  const char *value;
+
+  if (append)
+    value="hello";
+  else
+    value=" world";
+
+  execute(ascii_set_item(key, value));
+
+  if (append)
+    value=" world";
+  else
+    value="hello";
+
+  char cmd[400];
+  snprintf(cmd, sizeof(cmd), "%s %s 0 0 %u%s\r\n%s\r\n",
+           append ? "append" : "prepend",
+           key, (unsigned int)strlen(value), noreply ? " noreply" : "",
+           value);
+  execute(send_string(cmd));
+
+  if (noreply)
+    execute(test_ascii_version());
+  else
+    execute(receive_response("STORED\r\n"));
+
+  execute(ascii_get_item(key, "hello world", true));
+
+  snprintf(cmd, sizeof(cmd), "%s %s_notfound 0 0 %u%s\r\n%s\r\n",
+           append ? "append" : "prepend",
+           key, (unsigned int)strlen(value), noreply ? " noreply" : "",
+           value);
+  execute(send_string(cmd));
+
+  if (noreply)
+    execute(test_ascii_version());
+  else
+    execute(receive_response("NOT_STORED\r\n"));
+
+  return TEST_PASS;
+}
+
+static enum test_return test_ascii_append(void)
+{
+  return test_ascii_concat_impl("test_ascii_append", true, false);
+}
+
+static enum test_return test_ascii_prepend(void)
+{
+  return test_ascii_concat_impl("test_ascii_prepend", false, false);
+}
+
+static enum test_return test_ascii_append_noreply(void)
+{
+  return test_ascii_concat_impl("test_ascii_append_noreply", true, true);
+}
+
+static enum test_return test_ascii_prepend_noreply(void)
+{
+  return test_ascii_concat_impl("test_ascii_prepend_noreply", false, true);
+}
+
+static enum test_return test_ascii_stat(void)
+{
+  execute(send_string("stats noreply\r\n"));
+  execute(receive_error_response());
+  execute(send_string("stats\r\n"));
+  char buffer[1024];
+  do {
+    execute(receive_line(buffer, sizeof(buffer)));
+  } while (strcmp(buffer, "END\r\n") != 0);
+
+  return TEST_PASS_RECONNECT;
+}
+
+typedef enum test_return(*TEST_FUNC)(void);
+
+struct testcase
+{
+  const char *description;
+  TEST_FUNC function;
+};
+
+struct testcase testcases[]= {
+  { "ascii quit", test_ascii_quit },
+  { "ascii version", test_ascii_version },
+  { "ascii verbosity", test_ascii_verbosity },
+  { "ascii set", test_ascii_set },
+  { "ascii set noreply", test_ascii_set_noreply },
+  { "ascii get", test_ascii_get },
+  { "ascii gets", test_ascii_gets },
+  { "ascii mget", test_ascii_mget },
+  { "ascii flush", test_ascii_flush },
+  { "ascii flush noreply", test_ascii_flush_noreply },
+  { "ascii add", test_ascii_add },
+  { "ascii add noreply", test_ascii_add_noreply },
+  { "ascii replace", test_ascii_replace },
+  { "ascii replace noreply", test_ascii_replace_noreply },
+  { "ascii cas", test_ascii_cas },
+  { "ascii cas noreply", test_ascii_cas_noreply },
+  { "ascii delete", test_ascii_delete },
+  { "ascii delete noreply", test_ascii_delete_noreply },
+  { "ascii incr", test_ascii_incr },
+  { "ascii incr noreply", test_ascii_incr_noreply },
+  { "ascii decr", test_ascii_decr },
+  { "ascii decr noreply", test_ascii_decr_noreply },
+  { "ascii append", test_ascii_append },
+  { "ascii append noreply", test_ascii_append_noreply },
+  { "ascii prepend", test_ascii_prepend },
+  { "ascii prepend noreply", test_ascii_prepend_noreply },
+  { "ascii stat", test_ascii_stat },
+  { "binary noop", test_binary_noop },
+  { "binary quit", test_binary_quit },
+  { "binary quitq", test_binary_quitq },
+  { "binary set", test_binary_set },
+  { "binary setq", test_binary_setq },
+  { "binary flush", test_binary_flush },
+  { "binary flushq", test_binary_flushq },
+  { "binary add", test_binary_add },
+  { "binary addq", test_binary_addq },
+  { "binary replace", test_binary_replace },
+  { "binary replaceq", test_binary_replaceq },
+  { "binary delete", test_binary_delete },
+  { "binary deleteq", test_binary_deleteq },
+  { "binary get", test_binary_get },
+  { "binary getq", test_binary_getq },
+  { "binary getk", test_binary_getk },
+  { "binary getkq", test_binary_getkq },
+  { "binary incr", test_binary_incr },
+  { "binary incrq", test_binary_incrq },
+  { "binary decr", test_binary_decr },
+  { "binary decrq", test_binary_decrq },
+  { "binary version", test_binary_version },
+  { "binary append", test_binary_append },
+  { "binary appendq", test_binary_appendq },
+  { "binary prepend", test_binary_prepend },
+  { "binary prependq", test_binary_prependq },
+  { "binary stat", test_binary_stat },
+  { NULL, NULL}
+};
+
+const int ascii_tests = 1;
+const int binary_tests = 2;
+
+struct test_type_st
+{
+  bool ascii;
+  bool binary;
+};
+
+int main(int argc, char **argv)
+{
+  static const char * const status_msg[]= {"[skip]", "[pass]", "[pass]", "[FAIL]"};
+  struct test_type_st tests= { true, true };
+  int total= 0;
+  int failed= 0;
+  const char *hostname= "localhost";
+  const char *port= "11211";
+  int cmd;
+  bool prompt= false;
+  const char *testname= NULL;
+
+
+
+  while ((cmd= getopt(argc, argv, "t:vch:p:PT:?ab")) != EOF)
+  {
+    switch (cmd) {
+    case 'a':
+      tests.ascii= true;
+      tests.binary= false;
+      break;
+    case 'b':
+      tests.ascii= false;
+      tests.binary= true;
+      break;
+    case 't':
+      timeout= atoi(optarg);
+      if (timeout == 0)
+      {
+        fprintf(stderr, "Invalid timeout. Please specify a number for -t\n");
+        return EXIT_FAILURE;
+      }
+      break;
+    case 'v': verbose= true;
+      break;
+    case 'c': do_core= true;
+      break;
+    case 'h': hostname= optarg;
+      break;
+    case 'p': port= optarg;
+      break;
+    case 'P': prompt= true;
+      break;
+    case 'T': testname= optarg;
+       break;
+    default:
+      fprintf(stderr, "Usage: %s [-h hostname] [-p port] [-c] [-v] [-t n] [-P] [-T testname]'\n"
+              "\t-c\tGenerate coredump if a test fails\n"
+              "\t-v\tVerbose test output (print out the assertion)\n"
+              "\t-t n\tSet the timeout for io-operations to n seconds\n"
+              "\t-P\tPrompt the user before starting a test.\n"
+              "\t\t\t\"skip\" will skip the test\n"
+              "\t\t\t\"quit\" will terminate memcapable\n"
+              "\t\t\tEverything else will start the test\n"
+              "\t-T n\tJust run the test named n\n"
+              "\t-a\tOnly test the ascii protocol\n"
+              "\t-b\tOnly test the binary protocol\n",
+              argv[0]);
+      return EXIT_FAILURE;
+    }
+  }
+
+  initialize_sockets();
+  sock= connect_server(hostname, port);
+  if (sock == INVALID_SOCKET)
+  {
+    fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
+            hostname, port, strerror(get_socket_errno()));
+    return EXIT_FAILURE;
+  }
+
+  for (int ii= 0; testcases[ii].description != NULL; ++ii)
+  {
+    if (testname != NULL && strcmp(testcases[ii].description, testname) != 0)
+       continue;
+
+    if ((testcases[ii].description[0] == 'a' && (tests.ascii) == 0) ||
+        (testcases[ii].description[0] == 'b' && (tests.binary) == 0))
+    {
+      continue;
+    }
+    ++total;
+    fprintf(stdout, "%-40s", testcases[ii].description);
+    fflush(stdout);
+
+    if (prompt)
+    {
+      fprintf(stdout, "\nPress <return> when you are ready? ");
+      char buffer[80] = {0};
+      if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
+        if (strncmp(buffer, "skip", 4) == 0)
+        {
+          fprintf(stdout, "%-40s%s\n", testcases[ii].description,
+                  status_msg[TEST_SKIP]);
+          fflush(stdout);
+          continue;
+        }
+        if (strncmp(buffer, "quit", 4) == 0)
+          exit(0);
+      }
+
+      fprintf(stdout, "%-40s", testcases[ii].description);
+      fflush(stdout);
+    }
+
+    bool reconnect= false;
+    enum test_return ret= testcases[ii].function();
+    if (ret == TEST_FAIL)
+    {
+      reconnect= true;
+      ++failed;
+      if (verbose)
+        fprintf(stderr, "\n");
+    }
+    else if (ret == TEST_PASS_RECONNECT)
+      reconnect= true;
+
+    fprintf(stderr, "%s\n", status_msg[ret]);
+    if (reconnect)
+    {
+      closesocket(sock);
+      if ((sock= connect_server(hostname, port)) == INVALID_SOCKET)
+      {
+        fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
+                hostname, port, strerror(get_socket_errno()));
+        fprintf(stderr, "%d of %d tests failed\n", failed, total);
+        return EXIT_FAILURE;
+      }
+    }
+  }
+
+  closesocket(sock);
+  if (failed == 0)
+    fprintf(stdout, "All tests passed\n");
+  else
+    fprintf(stderr, "%d of %d tests failed\n", failed, total);
+
+  return (failed == 0) ? 0 : 1;
+}
diff --git a/clients/memcat.c b/clients/memcat.c
deleted file mode 100644 (file)
index 3f0d92b..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <inttypes.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <libmemcached/memcached.h>
-
-#include "utilities.h"
-
-#define PROGRAM_NAME "memcat"
-#define PROGRAM_DESCRIPTION "Cat a set of key values to stdout."
-
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static int opt_displayflag= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static char *opt_username;
-static char *opt_passwd;
-static char *opt_file;
-
-int main(int argc, char *argv[])
-{
-  memcached_st *memc;
-  char *string;
-  size_t string_length;
-  uint32_t flags;
-  memcached_return_t rc;
-  memcached_server_st *servers;
-
-  int return_code= 0;
-
-  options_parse(argc, argv);
-  initialize_sockets();
-
-  if (!opt_servers)
-  {
-    char *temp;
-
-    if ((temp= getenv("MEMCACHED_SERVERS")))
-      opt_servers= strdup(temp);
-    else
-    {
-      fprintf(stderr, "No Servers provided\n");
-      exit(1);
-    }
-  }
-
-  memc= memcached_create(NULL);
-  process_hash_option(memc, opt_hash);
-
-  servers= memcached_servers_parse(opt_servers);
-
-  memcached_server_push(memc, servers);
-  memcached_server_list_free(servers);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
-                         (uint64_t)opt_binary);
-
-  if (!initialize_sasl(memc, opt_username, opt_passwd))
-  {
-    memcached_free(memc);
-    return EXIT_FAILURE;
-  }
-
-  while (optind < argc)
-  {
-    string= memcached_get(memc, argv[optind], strlen(argv[optind]),
-                          &string_length, &flags, &rc);
-    if (rc == MEMCACHED_SUCCESS)
-    {
-      if (opt_displayflag)
-      {
-        if (opt_verbose)
-          printf("key: %s\nflags: ", argv[optind]);
-        printf("%x\n", flags);
-      }
-      else
-      {
-        if (opt_verbose)
-        {
-          printf("key: %s\nflags: %x\nlength: %zu\nvalue: ",
-                 argv[optind], flags, string_length);
-        }
-
-        if (opt_file)
-        {
-          FILE *fp;
-          size_t written;
-
-          fp= fopen(opt_file, "w");
-          if (!fp)
-          {
-            perror("fopen");
-            return_code= -1;
-            break;
-          }
-
-          written= fwrite(string, 1, string_length, fp);
-          if (written != string_length) 
-          {
-            fprintf(stderr, "error writing file (written %zu, should be %zu)\n", written, string_length);
-            return_code= -1;
-            break;
-          }
-
-          if (fclose(fp))
-          {
-            fprintf(stderr, "error closing file\n");
-            return_code= -1;
-            break;
-          }
-        }
-        else
-        {
-            printf("%.*s\n", (int)string_length, string);
-        }
-        free(string);
-      }
-    }
-    else if (rc != MEMCACHED_NOTFOUND)
-    {
-      fprintf(stderr, "memcat: %s: memcache error %s",
-              argv[optind], memcached_strerror(memc, rc));
-      if (memcached_last_error_errno(memc))
-      {
-       fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
-      }
-      fprintf(stderr, "\n");
-
-      return_code= -1;
-      break;
-    }
-    else // Unknown Issue
-    {
-      fprintf(stderr, "memcat: %s not found\n", argv[optind]);
-      return_code= -1;
-    }
-    optind++;
-  }
-
-  memcached_free(memc);
-
-  if (opt_servers)
-    free(opt_servers);
-  if (opt_hash)
-    free(opt_hash);
-
-  shutdown_sasl();
-
-  return return_code;
-}
-
-
-void options_parse(int argc, char *argv[])
-{
-  int option_index= 0;
-  int option_rv;
-
-  memcached_programs_help_st help_options[]=
-  {
-    {0},
-  };
-
-  static struct option long_options[]=
-    {
-      {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
-      {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
-      {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
-      {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
-      {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
-      {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
-      {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
-      {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
-      {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
-      {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
-      {(OPTIONSTRING)"file", required_argument, NULL, OPT_FILE},
-      {0, 0, 0, 0},
-    };
-
-  while (1)
-  {
-    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-    if (option_rv == -1) break;
-    switch (option_rv)
-    {
-    case 0:
-      break;
-    case OPT_BINARY:
-      opt_binary = 1;
-      break;
-    case OPT_VERBOSE: /* --verbose or -v */
-      opt_verbose = OPT_VERBOSE;
-      break;
-    case OPT_DEBUG: /* --debug or -d */
-      opt_verbose = OPT_DEBUG;
-      break;
-    case OPT_VERSION: /* --version or -V */
-      version_command(PROGRAM_NAME);
-      break;
-    case OPT_HELP: /* --help or -h */
-      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
-      break;
-    case OPT_SERVERS: /* --servers or -s */
-      opt_servers= strdup(optarg);
-      break;
-    case OPT_HASH:
-      opt_hash= strdup(optarg);
-      break;
-    case OPT_USERNAME:
-      opt_username= optarg;
-      break;
-    case OPT_PASSWD:
-      opt_passwd= optarg;
-      break;
-    case OPT_FILE:
-      opt_file= optarg;
-      break;
-    case '?':
-      /* getopt_long already printed an error message. */
-      exit(1);
-    default:
-      abort();
-    }
-  }
-}
diff --git a/clients/memcat.cc b/clients/memcat.cc
new file mode 100644 (file)
index 0000000..12df347
--- /dev/null
@@ -0,0 +1,242 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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:
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <libmemcached/memcached.h>
+
+#include "utilities.h"
+
+#define PROGRAM_NAME "memcat"
+#define PROGRAM_DESCRIPTION "Cat a set of key values to stdout."
+
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static int opt_displayflag= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static char *opt_username;
+static char *opt_passwd;
+static char *opt_file;
+
+int main(int argc, char *argv[])
+{
+  memcached_st *memc;
+  char *string;
+  size_t string_length;
+  uint32_t flags;
+  memcached_return_t rc;
+  memcached_server_st *servers;
+
+  int return_code= 0;
+
+  options_parse(argc, argv);
+  initialize_sockets();
+
+  if (!opt_servers)
+  {
+    char *temp;
+
+    if ((temp= getenv("MEMCACHED_SERVERS")))
+      opt_servers= strdup(temp);
+    else
+    {
+      fprintf(stderr, "No Servers provided\n");
+      exit(1);
+    }
+  }
+
+  memc= memcached_create(NULL);
+  process_hash_option(memc, opt_hash);
+
+  servers= memcached_servers_parse(opt_servers);
+
+  memcached_server_push(memc, servers);
+  memcached_server_list_free(servers);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+                         (uint64_t)opt_binary);
+
+  if (!initialize_sasl(memc, opt_username, opt_passwd))
+  {
+    memcached_free(memc);
+    return EXIT_FAILURE;
+  }
+
+  while (optind < argc)
+  {
+    string= memcached_get(memc, argv[optind], strlen(argv[optind]),
+                          &string_length, &flags, &rc);
+    if (rc == MEMCACHED_SUCCESS)
+    {
+      if (opt_displayflag)
+      {
+        if (opt_verbose)
+          printf("key: %s\nflags: ", argv[optind]);
+        printf("%x\n", flags);
+      }
+      else
+      {
+        if (opt_verbose)
+        {
+          printf("key: %s\nflags: %x\nlength: %lu\nvalue: ",
+                 argv[optind], flags, (unsigned long)string_length);
+        }
+
+        if (opt_file)
+        {
+          FILE *fp;
+          size_t written;
+
+          fp= fopen(opt_file, "w");
+          if (!fp)
+          {
+            perror("fopen");
+            return_code= -1;
+            break;
+          }
+
+          written= fwrite(string, 1, string_length, fp);
+          if (written != string_length) 
+          {
+            fprintf(stderr, "error writing file (written %lu, should be %lu)\n", (unsigned long)written, (unsigned long)string_length);
+            return_code= -1;
+            break;
+          }
+
+          if (fclose(fp))
+          {
+            fprintf(stderr, "error closing file\n");
+            return_code= -1;
+            break;
+          }
+        }
+        else
+        {
+            printf("%.*s\n", (int)string_length, string);
+        }
+        free(string);
+      }
+    }
+    else if (rc != MEMCACHED_NOTFOUND)
+    {
+      fprintf(stderr, "memcat: %s: memcache error %s",
+              argv[optind], memcached_strerror(memc, rc));
+      if (memcached_last_error_errno(memc))
+      {
+       fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
+      }
+      fprintf(stderr, "\n");
+
+      return_code= -1;
+      break;
+    }
+    else // Unknown Issue
+    {
+      fprintf(stderr, "memcat: %s not found\n", argv[optind]);
+      return_code= -1;
+    }
+    optind++;
+  }
+
+  memcached_free(memc);
+
+  if (opt_servers)
+    free(opt_servers);
+  if (opt_hash)
+    free(opt_hash);
+
+  shutdown_sasl();
+
+  return return_code;
+}
+
+
+void options_parse(int argc, char *argv[])
+{
+  int option_index= 0;
+  int option_rv;
+
+  memcached_programs_help_st help_options[]=
+  {
+    {0},
+  };
+
+  static struct option long_options[]=
+    {
+      {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+      {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+      {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+      {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+      {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+      {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
+      {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+      {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+      {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+      {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+      {(OPTIONSTRING)"file", required_argument, NULL, OPT_FILE},
+      {0, 0, 0, 0},
+    };
+
+  while (1)
+  {
+    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+    if (option_rv == -1) break;
+    switch (option_rv)
+    {
+    case 0:
+      break;
+    case OPT_BINARY:
+      opt_binary = 1;
+      break;
+    case OPT_VERBOSE: /* --verbose or -v */
+      opt_verbose = OPT_VERBOSE;
+      break;
+    case OPT_DEBUG: /* --debug or -d */
+      opt_verbose = OPT_DEBUG;
+      break;
+    case OPT_VERSION: /* --version or -V */
+      version_command(PROGRAM_NAME);
+      break;
+    case OPT_HELP: /* --help or -h */
+      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+      break;
+    case OPT_SERVERS: /* --servers or -s */
+      opt_servers= strdup(optarg);
+      break;
+    case OPT_HASH:
+      opt_hash= strdup(optarg);
+      break;
+    case OPT_USERNAME:
+      opt_username= optarg;
+      break;
+    case OPT_PASSWD:
+      opt_passwd= optarg;
+      break;
+    case OPT_FILE:
+      opt_file= optarg;
+      break;
+    case '?':
+      /* getopt_long already printed an error message. */
+      exit(1);
+    default:
+      abort();
+    }
+  }
+}
diff --git a/clients/memcp.c b/clients/memcp.c
deleted file mode 100644 (file)
index bf3828a..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <strings.h>
-#include <string.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <limits.h>
-
-
-#include <libmemcached/memcached.h>
-
-#include "client_options.h"
-#include "utilities.h"
-
-#define PROGRAM_NAME "memcp"
-#define PROGRAM_DESCRIPTION "Copy a set of files to a memcached cluster."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-
-static int opt_binary=0;
-static int opt_verbose= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static int opt_method= OPT_SET;
-static uint32_t opt_flags= 0;
-static time_t opt_expires= 0;
-static char *opt_username;
-static char *opt_passwd;
-
-static long strtol_wrapper(const char *nptr, int base, bool *error)
-{
-  long val;
-  char *endptr;
-
-  errno= 0;    /* To distinguish success/failure after call */
-  val= strtol(nptr, &endptr, base);
-
-  /* Check for various possible errors */
-
-  if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
-      || (errno != 0 && val == 0))
-  {
-    *error= true;
-    return EXIT_SUCCESS;
-  }
-
-  if (endptr == nptr)
-  {
-    *error= true;
-    return EXIT_SUCCESS;
-  }
-
-  *error= false;
-  return val;
-}
-
-int main(int argc, char *argv[])
-{
-  memcached_st *memc;
-  memcached_return_t rc;
-  memcached_server_st *servers;
-
-  int return_code= 0;
-
-  options_parse(argc, argv);
-  initialize_sockets();
-
-  memc= memcached_create(NULL);
-  process_hash_option(memc, opt_hash);
-
-  if (!opt_servers)
-  {
-    char *temp;
-
-    if ((temp= getenv("MEMCACHED_SERVERS")))
-    {
-      opt_servers= strdup(temp);
-    }
-    else
-    {
-      fprintf(stderr, "No Servers provided\n");
-      exit(1);
-    }
-  }
-
-  if (opt_servers)
-    servers= memcached_servers_parse(opt_servers);
-  else
-    servers= memcached_servers_parse(argv[--argc]);
-
-  memcached_server_push(memc, servers);
-  memcached_server_list_free(servers);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
-                         (uint64_t)opt_binary);
-  if (!initialize_sasl(memc, opt_username, opt_passwd))
-  {
-    memcached_free(memc);
-    return EXIT_FAILURE;
-  }
-
-  while (optind < argc)
-  {
-    struct stat sbuf;
-    int fd;
-    char *ptr;
-    ssize_t read_length;
-    char *file_buffer_ptr;
-
-    fd= open(argv[optind], O_RDONLY);
-    if (fd < 0)
-    {
-      fprintf(stderr, "memcp: %s: %s\n", argv[optind], strerror(errno));
-      optind++;
-      continue;
-    }
-
-    (void)fstat(fd, &sbuf);
-
-    ptr= rindex(argv[optind], '/');
-    if (ptr)
-      ptr++;
-    else
-      ptr= argv[optind];
-
-    if (opt_verbose)
-    {
-      static const char *opstr[] = { "set", "add", "replace" };
-      printf("op: %s\nsource file: %s\nlength: %zu\n"
-            "key: %s\nflags: %x\nexpires: %llu\n",
-            opstr[opt_method - OPT_SET], argv[optind], (size_t)sbuf.st_size,
-            ptr, opt_flags, (unsigned long long)opt_expires);
-    }
-
-    if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL)
-    {
-      fprintf(stderr, "malloc: %s\n", strerror(errno));
-      exit(1);
-    }
-
-    if ((read_length= read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1)
-    {
-      fprintf(stderr, "read: %s\n", strerror(errno));
-      exit(1);
-    }
-
-    if (read_length != sbuf.st_size)
-    {
-      fprintf(stderr, "Failure reading from file\n");
-      exit(1);
-    }
-
-    if (opt_method == OPT_ADD)
-      rc= memcached_add(memc, ptr, strlen(ptr),
-                        file_buffer_ptr, (size_t)sbuf.st_size,
-                       opt_expires, opt_flags);
-    else if (opt_method == OPT_REPLACE)
-      rc= memcached_replace(memc, ptr, strlen(ptr),
-                           file_buffer_ptr, (size_t)sbuf.st_size,
-                           opt_expires, opt_flags);
-    else
-      rc= memcached_set(memc, ptr, strlen(ptr),
-                        file_buffer_ptr, (size_t)sbuf.st_size,
-                        opt_expires, opt_flags);
-
-    if (rc != MEMCACHED_SUCCESS)
-    {
-      fprintf(stderr, "memcp: %s: memcache error %s",
-             ptr, memcached_strerror(memc, rc));
-      if (memcached_last_error_errno(memc))
-       fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
-      fprintf(stderr, "\n");
-
-      return_code= -1;
-    }
-
-    free(file_buffer_ptr);
-    close(fd);
-    optind++;
-  }
-
-  memcached_free(memc);
-
-  if (opt_servers)
-    free(opt_servers);
-  if (opt_hash)
-    free(opt_hash);
-  shutdown_sasl();
-
-  return return_code;
-}
-
-static void options_parse(int argc, char *argv[])
-{
-  int option_index= 0;
-  int option_rv;
-
-  memcached_programs_help_st help_options[]=
-  {
-    {0},
-  };
-
-  static struct option long_options[]=
-    {
-      {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
-      {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
-      {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
-      {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
-      {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
-      {(OPTIONSTRING)"flag", required_argument, NULL, OPT_FLAG},
-      {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
-      {(OPTIONSTRING)"set",  no_argument, NULL, OPT_SET},
-      {(OPTIONSTRING)"add",  no_argument, NULL, OPT_ADD},
-      {(OPTIONSTRING)"replace",  no_argument, NULL, OPT_REPLACE},
-      {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
-      {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
-      {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
-      {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
-      {0, 0, 0, 0},
-    };
-
-  while (1)
-  {
-    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-
-    if (option_rv == -1) break;
-
-    switch (option_rv)
-    {
-    case 0:
-      break;
-    case OPT_BINARY:
-      opt_binary = 1;
-      break;
-    case OPT_VERBOSE: /* --verbose or -v */
-      opt_verbose = OPT_VERBOSE;
-      break;
-    case OPT_DEBUG: /* --debug or -d */
-      opt_verbose = OPT_DEBUG;
-      break;
-    case OPT_VERSION: /* --version or -V */
-      version_command(PROGRAM_NAME);
-      break;
-    case OPT_HELP: /* --help or -h */
-      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
-      break;
-    case OPT_SERVERS: /* --servers or -s */
-      opt_servers= strdup(optarg);
-      break;
-    case OPT_FLAG: /* --flag */
-      {
-        bool strtol_error;
-        opt_flags= (uint32_t)strtol_wrapper(optarg, 16, &strtol_error);
-        if (strtol_error == true)
-        {
-          fprintf(stderr, "Bad value passed via --flag\n");
-          exit(1);
-        }
-        break;
-      }
-    case OPT_EXPIRE: /* --expire */
-      {
-        bool strtol_error;
-        opt_expires= (time_t)strtol_wrapper(optarg, 16, &strtol_error);
-        if (strtol_error == true)
-        {
-          fprintf(stderr, "Bad value passed via --flag\n");
-          exit(1);
-        }
-      }
-    case OPT_SET:
-      opt_method= OPT_SET;
-      break;
-    case OPT_REPLACE:
-      opt_method= OPT_REPLACE;
-      break;
-    case OPT_ADD:
-      opt_method= OPT_ADD;
-      break;
-    case OPT_HASH:
-      opt_hash= strdup(optarg);
-      break;
-    case OPT_USERNAME:
-      opt_username= optarg;
-      break;
-    case OPT_PASSWD:
-      opt_passwd= optarg;
-      break;
-   case '?':
-      /* getopt_long already printed an error message. */
-      exit(1);
-    default:
-      abort();
-    }
-  }
-}
diff --git a/clients/memcp.cc b/clients/memcp.cc
new file mode 100644 (file)
index 0000000..3869242
--- /dev/null
@@ -0,0 +1,317 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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:
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <limits.h>
+
+
+#include <libmemcached/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+
+#define PROGRAM_NAME "memcp"
+#define PROGRAM_DESCRIPTION "Copy a set of files to a memcached cluster."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+
+static int opt_binary=0;
+static int opt_verbose= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static int opt_method= OPT_SET;
+static uint32_t opt_flags= 0;
+static time_t opt_expires= 0;
+static char *opt_username;
+static char *opt_passwd;
+
+static long strtol_wrapper(const char *nptr, int base, bool *error)
+{
+  long val;
+  char *endptr;
+
+  errno= 0;    /* To distinguish success/failure after call */
+  val= strtol(nptr, &endptr, base);
+
+  /* Check for various possible errors */
+
+  if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+      || (errno != 0 && val == 0))
+  {
+    *error= true;
+    return EXIT_SUCCESS;
+  }
+
+  if (endptr == nptr)
+  {
+    *error= true;
+    return EXIT_SUCCESS;
+  }
+
+  *error= false;
+  return val;
+}
+
+int main(int argc, char *argv[])
+{
+  memcached_st *memc;
+  memcached_return_t rc;
+  memcached_server_st *servers;
+
+  int return_code= 0;
+
+  options_parse(argc, argv);
+  initialize_sockets();
+
+  memc= memcached_create(NULL);
+  process_hash_option(memc, opt_hash);
+
+  if (!opt_servers)
+  {
+    char *temp;
+
+    if ((temp= getenv("MEMCACHED_SERVERS")))
+    {
+      opt_servers= strdup(temp);
+    }
+    else
+    {
+      fprintf(stderr, "No Servers provided\n");
+      exit(1);
+    }
+  }
+
+  if (opt_servers)
+    servers= memcached_servers_parse(opt_servers);
+  else
+    servers= memcached_servers_parse(argv[--argc]);
+
+  memcached_server_push(memc, servers);
+  memcached_server_list_free(servers);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+                         (uint64_t)opt_binary);
+  if (!initialize_sasl(memc, opt_username, opt_passwd))
+  {
+    memcached_free(memc);
+    return EXIT_FAILURE;
+  }
+
+  while (optind < argc)
+  {
+    struct stat sbuf;
+    int fd;
+    char *ptr;
+    ssize_t read_length;
+    char *file_buffer_ptr;
+
+    fd= open(argv[optind], O_RDONLY);
+    if (fd < 0)
+    {
+      fprintf(stderr, "memcp: %s: %s\n", argv[optind], strerror(errno));
+      optind++;
+      continue;
+    }
+
+    (void)fstat(fd, &sbuf);
+
+    ptr= rindex(argv[optind], '/');
+    if (ptr)
+      ptr++;
+    else
+      ptr= argv[optind];
+
+    if (opt_verbose)
+    {
+      static const char *opstr[] = { "set", "add", "replace" };
+      printf("op: %s\nsource file: %s\nlength: %lu\n"
+            "key: %s\nflags: %x\nexpires: %lu\n",
+            opstr[opt_method - OPT_SET], argv[optind], (unsigned long)sbuf.st_size,
+            ptr, opt_flags, (unsigned long)opt_expires);
+    }
+
+    if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL)
+    {
+      fprintf(stderr, "malloc: %s\n", strerror(errno));
+      exit(1);
+    }
+
+    if ((read_length= read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1)
+    {
+      fprintf(stderr, "read: %s\n", strerror(errno));
+      exit(1);
+    }
+
+    if (read_length != sbuf.st_size)
+    {
+      fprintf(stderr, "Failure reading from file\n");
+      exit(1);
+    }
+
+    if (opt_method == OPT_ADD)
+      rc= memcached_add(memc, ptr, strlen(ptr),
+                        file_buffer_ptr, (size_t)sbuf.st_size,
+                       opt_expires, opt_flags);
+    else if (opt_method == OPT_REPLACE)
+      rc= memcached_replace(memc, ptr, strlen(ptr),
+                           file_buffer_ptr, (size_t)sbuf.st_size,
+                           opt_expires, opt_flags);
+    else
+      rc= memcached_set(memc, ptr, strlen(ptr),
+                        file_buffer_ptr, (size_t)sbuf.st_size,
+                        opt_expires, opt_flags);
+
+    if (rc != MEMCACHED_SUCCESS)
+    {
+      fprintf(stderr, "memcp: %s: memcache error %s",
+             ptr, memcached_strerror(memc, rc));
+      if (memcached_last_error_errno(memc))
+       fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
+      fprintf(stderr, "\n");
+
+      return_code= -1;
+    }
+
+    free(file_buffer_ptr);
+    close(fd);
+    optind++;
+  }
+
+  memcached_free(memc);
+
+  if (opt_servers)
+    free(opt_servers);
+  if (opt_hash)
+    free(opt_hash);
+  shutdown_sasl();
+
+  return return_code;
+}
+
+static void options_parse(int argc, char *argv[])
+{
+  int option_index= 0;
+  int option_rv;
+
+  memcached_programs_help_st help_options[]=
+  {
+    {0},
+  };
+
+  static struct option long_options[]=
+    {
+      {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+      {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+      {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+      {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+      {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+      {(OPTIONSTRING)"flag", required_argument, NULL, OPT_FLAG},
+      {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
+      {(OPTIONSTRING)"set",  no_argument, NULL, OPT_SET},
+      {(OPTIONSTRING)"add",  no_argument, NULL, OPT_ADD},
+      {(OPTIONSTRING)"replace",  no_argument, NULL, OPT_REPLACE},
+      {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+      {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+      {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+      {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+      {0, 0, 0, 0},
+    };
+
+  while (1)
+  {
+    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+
+    if (option_rv == -1) break;
+
+    switch (option_rv)
+    {
+    case 0:
+      break;
+    case OPT_BINARY:
+      opt_binary = 1;
+      break;
+    case OPT_VERBOSE: /* --verbose or -v */
+      opt_verbose = OPT_VERBOSE;
+      break;
+    case OPT_DEBUG: /* --debug or -d */
+      opt_verbose = OPT_DEBUG;
+      break;
+    case OPT_VERSION: /* --version or -V */
+      version_command(PROGRAM_NAME);
+      break;
+    case OPT_HELP: /* --help or -h */
+      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+      break;
+    case OPT_SERVERS: /* --servers or -s */
+      opt_servers= strdup(optarg);
+      break;
+    case OPT_FLAG: /* --flag */
+      {
+        bool strtol_error;
+        opt_flags= (uint32_t)strtol_wrapper(optarg, 16, &strtol_error);
+        if (strtol_error == true)
+        {
+          fprintf(stderr, "Bad value passed via --flag\n");
+          exit(1);
+        }
+        break;
+      }
+    case OPT_EXPIRE: /* --expire */
+      {
+        bool strtol_error;
+        opt_expires= (time_t)strtol_wrapper(optarg, 16, &strtol_error);
+        if (strtol_error == true)
+        {
+          fprintf(stderr, "Bad value passed via --flag\n");
+          exit(1);
+        }
+      }
+    case OPT_SET:
+      opt_method= OPT_SET;
+      break;
+    case OPT_REPLACE:
+      opt_method= OPT_REPLACE;
+      break;
+    case OPT_ADD:
+      opt_method= OPT_ADD;
+      break;
+    case OPT_HASH:
+      opt_hash= strdup(optarg);
+      break;
+    case OPT_USERNAME:
+      opt_username= optarg;
+      break;
+    case OPT_PASSWD:
+      opt_passwd= optarg;
+      break;
+   case '?':
+      /* getopt_long already printed an error message. */
+      exit(1);
+    default:
+      abort();
+    }
+  }
+}
diff --git a/clients/memdump.c b/clients/memdump.c
deleted file mode 100644 (file)
index 0e81dad..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <strings.h>
-#include <string.h>
-
-#include <libmemcached/memcached.h>
-
-#include "client_options.h"
-#include "utilities.h"
-
-#define PROGRAM_NAME "memdump"
-#define PROGRAM_DESCRIPTION "Dump all values from one or many servers."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-
-static int opt_binary=0;
-static int opt_verbose= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-/* Print the keys and counter how many were found */
-static memcached_return_t key_printer(const memcached_st *ptr,
-                                      const char *key, size_t key_length,
-                                      void *context)
-{
-  (void)ptr;(void)context;
-  printf("%.*s\n", (uint32_t)key_length, key);
-
-  return MEMCACHED_SUCCESS;
-}
-
-int main(int argc, char *argv[])
-{
-  memcached_st *memc;
-  memcached_return_t rc;
-  memcached_server_st *servers;
-  memcached_dump_fn callbacks[1];
-
-  callbacks[0]= &key_printer;
-
-  options_parse(argc, argv);
-
-  memc= memcached_create(NULL);
-  process_hash_option(memc, opt_hash);
-
-  if (!opt_servers)
-  {
-    char *temp;
-
-    if ((temp= getenv("MEMCACHED_SERVERS")))
-      opt_servers= strdup(temp);
-    else
-    {
-      fprintf(stderr, "No Servers provided\n");
-      exit(1);
-    }
-  }
-
-  if (opt_servers)
-    servers= memcached_servers_parse(opt_servers);
-  else
-    servers= memcached_servers_parse(argv[--argc]);
-
-  memcached_server_push(memc, servers);
-  memcached_server_list_free(servers);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
-                         (uint64_t)opt_binary);
-  if (!initialize_sasl(memc, opt_username, opt_passwd))
-  {
-    memcached_free(memc);
-    return EXIT_FAILURE;
-  }
-
-  rc= memcached_dump(memc, callbacks, NULL, 1);
-
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    fprintf(stderr, "memdump: memcache error %s", memcached_strerror(memc, rc));
-    if (memcached_last_error_errno(memc))
-      fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
-    fprintf(stderr, "\n");
-  }
-
-  memcached_free(memc);
-
-  if (opt_servers)
-    free(opt_servers);
-  if (opt_hash)
-    free(opt_hash);
-
-  shutdown_sasl();
-
-  return EXIT_SUCCESS;
-}
-
-static void options_parse(int argc, char *argv[])
-{
-  int option_index= 0;
-  int option_rv;
-
-  static struct option long_options[]=
-    {
-      {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
-      {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
-      {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
-      {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
-      {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
-      {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
-      {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
-      {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
-      {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
-      {0, 0, 0, 0}
-    };
-
-  while (1)
-  {
-    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-
-    if (option_rv == -1) break;
-
-    switch (option_rv)
-    {
-    case 0:
-      break;
-    case OPT_BINARY:
-      opt_binary = 1;
-      break;
-    case OPT_VERBOSE: /* --verbose or -v */
-      opt_verbose = OPT_VERBOSE;
-      break;
-    case OPT_DEBUG: /* --debug or -d */
-      opt_verbose = OPT_DEBUG;
-      break;
-    case OPT_VERSION: /* --version or -V */
-      version_command(PROGRAM_NAME);
-      break;
-    case OPT_HELP: /* --help or -h */
-      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL);
-      break;
-    case OPT_SERVERS: /* --servers or -s */
-      opt_servers= strdup(optarg);
-      break;
-    case OPT_HASH:
-      opt_hash= strdup(optarg);
-      break;
-    case OPT_USERNAME:
-       opt_username= optarg;
-       break;
-    case OPT_PASSWD:
-       opt_passwd= optarg;
-       break;
-    case '?':
-      /* getopt_long already printed an error message. */
-      exit(1);
-    default:
-      abort();
-    }
-  }
-}
diff --git a/clients/memdump.cc b/clients/memdump.cc
new file mode 100644 (file)
index 0000000..0e81dad
--- /dev/null
@@ -0,0 +1,183 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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:
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <string.h>
+
+#include <libmemcached/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+
+#define PROGRAM_NAME "memdump"
+#define PROGRAM_DESCRIPTION "Dump all values from one or many servers."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+
+static int opt_binary=0;
+static int opt_verbose= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+/* Print the keys and counter how many were found */
+static memcached_return_t key_printer(const memcached_st *ptr,
+                                      const char *key, size_t key_length,
+                                      void *context)
+{
+  (void)ptr;(void)context;
+  printf("%.*s\n", (uint32_t)key_length, key);
+
+  return MEMCACHED_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+  memcached_st *memc;
+  memcached_return_t rc;
+  memcached_server_st *servers;
+  memcached_dump_fn callbacks[1];
+
+  callbacks[0]= &key_printer;
+
+  options_parse(argc, argv);
+
+  memc= memcached_create(NULL);
+  process_hash_option(memc, opt_hash);
+
+  if (!opt_servers)
+  {
+    char *temp;
+
+    if ((temp= getenv("MEMCACHED_SERVERS")))
+      opt_servers= strdup(temp);
+    else
+    {
+      fprintf(stderr, "No Servers provided\n");
+      exit(1);
+    }
+  }
+
+  if (opt_servers)
+    servers= memcached_servers_parse(opt_servers);
+  else
+    servers= memcached_servers_parse(argv[--argc]);
+
+  memcached_server_push(memc, servers);
+  memcached_server_list_free(servers);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+                         (uint64_t)opt_binary);
+  if (!initialize_sasl(memc, opt_username, opt_passwd))
+  {
+    memcached_free(memc);
+    return EXIT_FAILURE;
+  }
+
+  rc= memcached_dump(memc, callbacks, NULL, 1);
+
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    fprintf(stderr, "memdump: memcache error %s", memcached_strerror(memc, rc));
+    if (memcached_last_error_errno(memc))
+      fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
+    fprintf(stderr, "\n");
+  }
+
+  memcached_free(memc);
+
+  if (opt_servers)
+    free(opt_servers);
+  if (opt_hash)
+    free(opt_hash);
+
+  shutdown_sasl();
+
+  return EXIT_SUCCESS;
+}
+
+static void options_parse(int argc, char *argv[])
+{
+  int option_index= 0;
+  int option_rv;
+
+  static struct option long_options[]=
+    {
+      {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+      {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+      {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+      {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+      {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+      {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+      {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+      {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+      {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+      {0, 0, 0, 0}
+    };
+
+  while (1)
+  {
+    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+
+    if (option_rv == -1) break;
+
+    switch (option_rv)
+    {
+    case 0:
+      break;
+    case OPT_BINARY:
+      opt_binary = 1;
+      break;
+    case OPT_VERBOSE: /* --verbose or -v */
+      opt_verbose = OPT_VERBOSE;
+      break;
+    case OPT_DEBUG: /* --debug or -d */
+      opt_verbose = OPT_DEBUG;
+      break;
+    case OPT_VERSION: /* --version or -V */
+      version_command(PROGRAM_NAME);
+      break;
+    case OPT_HELP: /* --help or -h */
+      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, NULL);
+      break;
+    case OPT_SERVERS: /* --servers or -s */
+      opt_servers= strdup(optarg);
+      break;
+    case OPT_HASH:
+      opt_hash= strdup(optarg);
+      break;
+    case OPT_USERNAME:
+       opt_username= optarg;
+       break;
+    case OPT_PASSWD:
+       opt_passwd= optarg;
+       break;
+    case '?':
+      /* getopt_long already printed an error message. */
+      exit(1);
+    default:
+      abort();
+    }
+  }
+}
diff --git a/clients/memerror.c b/clients/memerror.c
deleted file mode 100644 (file)
index c30dd2e..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <inttypes.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <libmemcached/memcached.h>
-
-#include "utilities.h"
-
-#define PROGRAM_NAME "memerror"
-#define PROGRAM_DESCRIPTION "Translate a memcached errror code into a string."
-
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-
-static int opt_verbose= 0;
-
-int main(int argc, char *argv[])
-{
-  unsigned long value;
-  options_parse(argc, argv);
-
-  if (argc != 2)
-    return EXIT_FAILURE;
-
-  value= strtoul(argv[1], (char **) NULL, 10);
-
-  if (value < MEMCACHED_MAXIMUM_RETURN)
-  {
-    printf("%s\n", memcached_strerror(NULL, (memcached_return_t)value));
-  }
-  else
-  {
-    fprintf(stderr, "Unknown Error Code\n");
-    return EXIT_FAILURE;
-  }
-
-  return EXIT_SUCCESS;
-}
-
-
-void options_parse(int argc, char *argv[])
-{
-  int option_index= 0;
-  int option_rv;
-
-  memcached_programs_help_st help_options[]=
-  {
-    {0},
-  };
-
-  static struct option long_options[]=
-    {
-      {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
-      {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
-      {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
-      {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
-      {0, 0, 0, 0},
-    };
-
-  while (1) 
-  {
-    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-    if (option_rv == -1) break;
-    switch (option_rv)
-    {
-    case 0:
-      break;
-    case OPT_VERBOSE: /* --verbose or -v */
-      opt_verbose = OPT_VERBOSE;
-      break;
-    case OPT_DEBUG: /* --debug or -d */
-      opt_verbose = OPT_DEBUG;
-      break;
-    case OPT_VERSION: /* --version or -V */
-      version_command(PROGRAM_NAME);
-      break;
-    case OPT_HELP: /* --help or -h */
-      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
-      break;
-    case '?':
-      /* getopt_long already printed an error message. */
-      exit(1);
-    default:
-      abort();
-    }
-  }
-}
diff --git a/clients/memerror.cc b/clients/memerror.cc
new file mode 100644 (file)
index 0000000..c30dd2e
--- /dev/null
@@ -0,0 +1,102 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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:
+ *
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <libmemcached/memcached.h>
+
+#include "utilities.h"
+
+#define PROGRAM_NAME "memerror"
+#define PROGRAM_DESCRIPTION "Translate a memcached errror code into a string."
+
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+
+static int opt_verbose= 0;
+
+int main(int argc, char *argv[])
+{
+  unsigned long value;
+  options_parse(argc, argv);
+
+  if (argc != 2)
+    return EXIT_FAILURE;
+
+  value= strtoul(argv[1], (char **) NULL, 10);
+
+  if (value < MEMCACHED_MAXIMUM_RETURN)
+  {
+    printf("%s\n", memcached_strerror(NULL, (memcached_return_t)value));
+  }
+  else
+  {
+    fprintf(stderr, "Unknown Error Code\n");
+    return EXIT_FAILURE;
+  }
+
+  return EXIT_SUCCESS;
+}
+
+
+void options_parse(int argc, char *argv[])
+{
+  int option_index= 0;
+  int option_rv;
+
+  memcached_programs_help_st help_options[]=
+  {
+    {0},
+  };
+
+  static struct option long_options[]=
+    {
+      {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+      {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+      {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+      {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+      {0, 0, 0, 0},
+    };
+
+  while (1) 
+  {
+    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+    if (option_rv == -1) break;
+    switch (option_rv)
+    {
+    case 0:
+      break;
+    case OPT_VERBOSE: /* --verbose or -v */
+      opt_verbose = OPT_VERBOSE;
+      break;
+    case OPT_DEBUG: /* --debug or -d */
+      opt_verbose = OPT_DEBUG;
+      break;
+    case OPT_VERSION: /* --version or -V */
+      version_command(PROGRAM_NAME);
+      break;
+    case OPT_HELP: /* --help or -h */
+      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+      break;
+    case '?':
+      /* getopt_long already printed an error message. */
+      exit(1);
+    default:
+      abort();
+    }
+  }
+}
diff --git a/clients/memflush.c b/clients/memflush.c
deleted file mode 100644 (file)
index 848bc1e..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <getopt.h>
-#include <libmemcached/memcached.h>
-#include "client_options.h"
-#include "utilities.h"
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static time_t opt_expire= 0;
-static char *opt_servers= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-#define PROGRAM_NAME "memflush"
-#define PROGRAM_DESCRIPTION "Erase all data in a server of memcached servers."
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-
-int main(int argc, char *argv[])
-{
-  memcached_st *memc;
-  memcached_return_t rc;
-  memcached_server_st *servers;
-
-  options_parse(argc, argv);
-
-  if (!opt_servers)
-  {
-    char *temp;
-
-    if ((temp= getenv("MEMCACHED_SERVERS")))
-      opt_servers= strdup(temp);
-    else
-    {
-      fprintf(stderr, "No Servers provided\n");
-      exit(1);
-    }
-  }
-
-  memc= memcached_create(NULL);
-
-  servers= memcached_servers_parse(opt_servers);
-  memcached_server_push(memc, servers);
-  memcached_server_list_free(servers);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
-                         (uint64_t) opt_binary);
-
-  if (!initialize_sasl(memc, opt_username, opt_passwd))
-  {
-    memcached_free(memc);
-    return EXIT_FAILURE;
-  }
-
-  rc = memcached_flush(memc, opt_expire);
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    fprintf(stderr, "memflush: memcache error %s",
-           memcached_strerror(memc, rc));
-    if (memcached_last_error_errno(memc))
-      fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
-    fprintf(stderr, "\n");
-  }
-
-  memcached_free(memc);
-
-  free(opt_servers);
-
-  shutdown_sasl();
-
-  return EXIT_SUCCESS;
-}
-
-
-void options_parse(int argc, char *argv[])
-{
-  memcached_programs_help_st help_options[]=
-  {
-    {0},
-  };
-
-  static struct option long_options[]=
-  {
-    {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
-    {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
-    {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
-    {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
-    {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
-    {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
-    {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
-    {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
-    {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
-    {0, 0, 0, 0},
-  };
-  int option_index= 0;
-  int option_rv;
-
-  while (1)
-  {
-    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-    if (option_rv == -1) break;
-    switch (option_rv)
-    {
-    case 0:
-      break;
-    case OPT_BINARY:
-      opt_binary = 1;
-      break;
-    case OPT_VERBOSE: /* --verbose or -v */
-      opt_verbose = OPT_VERBOSE;
-      break;
-    case OPT_DEBUG: /* --debug or -d */
-      opt_verbose = OPT_DEBUG;
-      break;
-    case OPT_VERSION: /* --version or -V */
-      version_command(PROGRAM_NAME);
-      break;
-    case OPT_HELP: /* --help or -h */
-      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
-      break;
-    case OPT_SERVERS: /* --servers or -s */
-      opt_servers= strdup(optarg);
-      break;
-    case OPT_EXPIRE: /* --expire */
-      opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
-      break;
-    case OPT_USERNAME:
-      opt_username= optarg;
-      break;
-    case OPT_PASSWD:
-      opt_passwd= optarg;
-      break;
-    case '?':
-      /* getopt_long already printed an error message. */
-      exit(1);
-    default:
-      abort();
-    }
-  }
-}
diff --git a/clients/memflush.cc b/clients/memflush.cc
new file mode 100644 (file)
index 0000000..848bc1e
--- /dev/null
@@ -0,0 +1,154 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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:
+ *
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <libmemcached/memcached.h>
+#include "client_options.h"
+#include "utilities.h"
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static time_t opt_expire= 0;
+static char *opt_servers= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+#define PROGRAM_NAME "memflush"
+#define PROGRAM_DESCRIPTION "Erase all data in a server of memcached servers."
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+
+int main(int argc, char *argv[])
+{
+  memcached_st *memc;
+  memcached_return_t rc;
+  memcached_server_st *servers;
+
+  options_parse(argc, argv);
+
+  if (!opt_servers)
+  {
+    char *temp;
+
+    if ((temp= getenv("MEMCACHED_SERVERS")))
+      opt_servers= strdup(temp);
+    else
+    {
+      fprintf(stderr, "No Servers provided\n");
+      exit(1);
+    }
+  }
+
+  memc= memcached_create(NULL);
+
+  servers= memcached_servers_parse(opt_servers);
+  memcached_server_push(memc, servers);
+  memcached_server_list_free(servers);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+                         (uint64_t) opt_binary);
+
+  if (!initialize_sasl(memc, opt_username, opt_passwd))
+  {
+    memcached_free(memc);
+    return EXIT_FAILURE;
+  }
+
+  rc = memcached_flush(memc, opt_expire);
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    fprintf(stderr, "memflush: memcache error %s",
+           memcached_strerror(memc, rc));
+    if (memcached_last_error_errno(memc))
+      fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
+    fprintf(stderr, "\n");
+  }
+
+  memcached_free(memc);
+
+  free(opt_servers);
+
+  shutdown_sasl();
+
+  return EXIT_SUCCESS;
+}
+
+
+void options_parse(int argc, char *argv[])
+{
+  memcached_programs_help_st help_options[]=
+  {
+    {0},
+  };
+
+  static struct option long_options[]=
+  {
+    {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+    {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+    {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+    {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+    {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+    {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
+    {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+    {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+    {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+    {0, 0, 0, 0},
+  };
+  int option_index= 0;
+  int option_rv;
+
+  while (1)
+  {
+    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+    if (option_rv == -1) break;
+    switch (option_rv)
+    {
+    case 0:
+      break;
+    case OPT_BINARY:
+      opt_binary = 1;
+      break;
+    case OPT_VERBOSE: /* --verbose or -v */
+      opt_verbose = OPT_VERBOSE;
+      break;
+    case OPT_DEBUG: /* --debug or -d */
+      opt_verbose = OPT_DEBUG;
+      break;
+    case OPT_VERSION: /* --version or -V */
+      version_command(PROGRAM_NAME);
+      break;
+    case OPT_HELP: /* --help or -h */
+      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+      break;
+    case OPT_SERVERS: /* --servers or -s */
+      opt_servers= strdup(optarg);
+      break;
+    case OPT_EXPIRE: /* --expire */
+      opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
+      break;
+    case OPT_USERNAME:
+      opt_username= optarg;
+      break;
+    case OPT_PASSWD:
+      opt_passwd= optarg;
+      break;
+    case '?':
+      /* getopt_long already printed an error message. */
+      exit(1);
+    default:
+      abort();
+    }
+  }
+}
diff --git a/clients/memrm.c b/clients/memrm.c
deleted file mode 100644 (file)
index d4d93c2..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <libmemcached/memcached.h>
-#include <string.h>
-#include "client_options.h"
-#include "utilities.h"
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static time_t opt_expire= 0;
-static char *opt_servers= NULL;
-static char *opt_hash= NULL;
-static char *opt_username;
-static char *opt_passwd;
-
-#define PROGRAM_NAME "memrm"
-#define PROGRAM_DESCRIPTION "Erase a key or set of keys from a memcached cluster."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-
-int main(int argc, char *argv[])
-{
-  memcached_st *memc;
-  memcached_return_t rc;
-  memcached_server_st *servers;
-
-  int return_code= 0;
-
-  options_parse(argc, argv);
-  initialize_sockets();
-
-  if (!opt_servers)
-  {
-    char *temp;
-
-    if ((temp= getenv("MEMCACHED_SERVERS")))
-      opt_servers= strdup(temp);
-    else
-    {
-      fprintf(stderr, "No Servers provided\n");
-      exit(1);
-    }
-  }
-
-  memc= memcached_create(NULL);
-  process_hash_option(memc, opt_hash);
-
-  servers= memcached_servers_parse(opt_servers);
-  memcached_server_push(memc, servers);
-  memcached_server_list_free(servers);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
-                         (uint64_t) opt_binary);
-
-  if (!initialize_sasl(memc, opt_username, opt_passwd))
-  {
-    memcached_free(memc);
-    return EXIT_FAILURE;
-  }
-
-  while (optind < argc)
-  {
-    if (opt_verbose)
-      printf("key: %s\nexpires: %llu\n", argv[optind], (unsigned long long)opt_expire);
-    rc = memcached_delete(memc, argv[optind], strlen(argv[optind]), opt_expire);
-
-    if (rc != MEMCACHED_SUCCESS)
-    {
-      fprintf(stderr, "memrm: %s: memcache error %s",
-             argv[optind], memcached_strerror(memc, rc));
-      if (memcached_last_error_errno(memc))
-       fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
-      fprintf(stderr, "\n");
-
-      return_code= -1;
-    }
-
-    optind++;
-  }
-
-  memcached_free(memc);
-
-  if (opt_servers)
-    free(opt_servers);
-
-  if (opt_hash)
-    free(opt_hash);
-
-  shutdown_sasl();
-
-  return return_code;
-}
-
-
-static void options_parse(int argc, char *argv[])
-{
-  memcached_programs_help_st help_options[]=
-  {
-    {0},
-  };
-
-  static struct option long_options[]=
-  {
-    {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
-    {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
-    {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
-    {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
-    {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
-    {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
-    {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
-    {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
-    {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
-    {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
-    {0, 0, 0, 0},
-  };
-  int option_index= 0;
-  int option_rv;
-
-  while (1)
-  {
-    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-    if (option_rv == -1) break;
-    switch (option_rv)
-    {
-    case 0:
-      break;
-    case OPT_BINARY:
-      opt_binary = 1;
-      break;
-    case OPT_VERBOSE: /* --verbose or -v */
-      opt_verbose = OPT_VERBOSE;
-      break;
-    case OPT_DEBUG: /* --debug or -d */
-      opt_verbose = OPT_DEBUG;
-      break;
-    case OPT_VERSION: /* --version or -V */
-      version_command(PROGRAM_NAME);
-      break;
-    case OPT_HELP: /* --help or -h */
-      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
-      break;
-    case OPT_SERVERS: /* --servers or -s */
-      opt_servers= strdup(optarg);
-      break;
-    case OPT_EXPIRE: /* --expire */
-      opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
-      break;
-    case OPT_HASH:
-      opt_hash= strdup(optarg);
-      break;
-    case OPT_USERNAME:
-      opt_username= optarg;
-      break;
-    case OPT_PASSWD:
-      opt_passwd= optarg;
-      break;
-    case '?':
-      /* getopt_long already printed an error message. */
-      exit(1);
-    default:
-      abort();
-    }
-  }
-}
diff --git a/clients/memrm.cc b/clients/memrm.cc
new file mode 100644 (file)
index 0000000..d4d93c2
--- /dev/null
@@ -0,0 +1,177 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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:
+ *
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <libmemcached/memcached.h>
+#include <string.h>
+#include "client_options.h"
+#include "utilities.h"
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static time_t opt_expire= 0;
+static char *opt_servers= NULL;
+static char *opt_hash= NULL;
+static char *opt_username;
+static char *opt_passwd;
+
+#define PROGRAM_NAME "memrm"
+#define PROGRAM_DESCRIPTION "Erase a key or set of keys from a memcached cluster."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+
+int main(int argc, char *argv[])
+{
+  memcached_st *memc;
+  memcached_return_t rc;
+  memcached_server_st *servers;
+
+  int return_code= 0;
+
+  options_parse(argc, argv);
+  initialize_sockets();
+
+  if (!opt_servers)
+  {
+    char *temp;
+
+    if ((temp= getenv("MEMCACHED_SERVERS")))
+      opt_servers= strdup(temp);
+    else
+    {
+      fprintf(stderr, "No Servers provided\n");
+      exit(1);
+    }
+  }
+
+  memc= memcached_create(NULL);
+  process_hash_option(memc, opt_hash);
+
+  servers= memcached_servers_parse(opt_servers);
+  memcached_server_push(memc, servers);
+  memcached_server_list_free(servers);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+                         (uint64_t) opt_binary);
+
+  if (!initialize_sasl(memc, opt_username, opt_passwd))
+  {
+    memcached_free(memc);
+    return EXIT_FAILURE;
+  }
+
+  while (optind < argc)
+  {
+    if (opt_verbose)
+      printf("key: %s\nexpires: %llu\n", argv[optind], (unsigned long long)opt_expire);
+    rc = memcached_delete(memc, argv[optind], strlen(argv[optind]), opt_expire);
+
+    if (rc != MEMCACHED_SUCCESS)
+    {
+      fprintf(stderr, "memrm: %s: memcache error %s",
+             argv[optind], memcached_strerror(memc, rc));
+      if (memcached_last_error_errno(memc))
+       fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
+      fprintf(stderr, "\n");
+
+      return_code= -1;
+    }
+
+    optind++;
+  }
+
+  memcached_free(memc);
+
+  if (opt_servers)
+    free(opt_servers);
+
+  if (opt_hash)
+    free(opt_hash);
+
+  shutdown_sasl();
+
+  return return_code;
+}
+
+
+static void options_parse(int argc, char *argv[])
+{
+  memcached_programs_help_st help_options[]=
+  {
+    {0},
+  };
+
+  static struct option long_options[]=
+  {
+    {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+    {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+    {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+    {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+    {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+    {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
+    {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
+    {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+    {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
+    {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
+    {0, 0, 0, 0},
+  };
+  int option_index= 0;
+  int option_rv;
+
+  while (1)
+  {
+    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+    if (option_rv == -1) break;
+    switch (option_rv)
+    {
+    case 0:
+      break;
+    case OPT_BINARY:
+      opt_binary = 1;
+      break;
+    case OPT_VERBOSE: /* --verbose or -v */
+      opt_verbose = OPT_VERBOSE;
+      break;
+    case OPT_DEBUG: /* --debug or -d */
+      opt_verbose = OPT_DEBUG;
+      break;
+    case OPT_VERSION: /* --version or -V */
+      version_command(PROGRAM_NAME);
+      break;
+    case OPT_HELP: /* --help or -h */
+      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+      break;
+    case OPT_SERVERS: /* --servers or -s */
+      opt_servers= strdup(optarg);
+      break;
+    case OPT_EXPIRE: /* --expire */
+      opt_expire= (time_t)strtoll(optarg, (char **)NULL, 10);
+      break;
+    case OPT_HASH:
+      opt_hash= strdup(optarg);
+      break;
+    case OPT_USERNAME:
+      opt_username= optarg;
+      break;
+    case OPT_PASSWD:
+      opt_passwd= optarg;
+      break;
+    case '?':
+      /* getopt_long already printed an error message. */
+      exit(1);
+    default:
+      abort();
+    }
+  }
+}
diff --git a/clients/memslap.c b/clients/memslap.c
deleted file mode 100644 (file)
index 0d77fd6..0000000
+++ /dev/null
@@ -1,495 +0,0 @@
-/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- * 
- *  Libmemcached library
- *
- *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *  Copyright (C) 2006-2009 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 <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <getopt.h>
-#include <pthread.h>
-#include <assert.h>
-
-#include <libmemcached/memcached.h>
-
-#include "client_options.h"
-#include "utilities.h"
-#include "generator.h"
-#include "execute.h"
-
-#define DEFAULT_INITIAL_LOAD 10000
-#define DEFAULT_EXECUTE_NUMBER 10000
-#define DEFAULT_CONCURRENCY 1
-
-#define PROGRAM_NAME "memslap"
-#define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers."
-
-/* Global Thread counter */
-volatile unsigned int thread_counter;
-pthread_mutex_t counter_mutex;
-pthread_cond_t count_threshhold;
-volatile unsigned int master_wakeup;
-pthread_mutex_t sleeper_mutex;
-pthread_cond_t sleep_threshhold;
-
-void *run_task(void *p);
-
-/* Types */
-typedef struct conclusions_st conclusions_st;
-typedef struct thread_context_st thread_context_st;
-typedef enum {
-  SET_TEST,
-  GET_TEST,
-  MGET_TEST
-} test_type;
-
-struct thread_context_st {
-  unsigned int key_count;
-  pairs_st *initial_pairs;
-  unsigned int initial_number;
-  pairs_st *execute_pairs;
-  unsigned int execute_number;
-  char **keys;
-  size_t *key_lengths;
-  test_type test;
-  memcached_st *memc;
-};
-
-struct conclusions_st {
-  long int load_time;
-  long int read_time;
-  unsigned int rows_loaded;
-  unsigned int rows_read;
-};
-
-/* Prototypes */
-void options_parse(int argc, char *argv[]);
-void conclusions_print(conclusions_st *conclusion);
-void scheduler(memcached_server_st *servers, conclusions_st *conclusion);
-pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
-                           unsigned int *actual_loaded);
-void flush_all(memcached_st *memc);
-
-static int opt_binary= 0;
-static int opt_verbose= 0;
-static int opt_flush= 0;
-static int opt_non_blocking_io= 0;
-static int opt_tcp_nodelay= 0;
-static unsigned int opt_execute_number= 0;
-static unsigned int opt_createial_load= 0;
-static unsigned int opt_concurrency= 0;
-static int opt_displayflag= 0;
-static char *opt_servers= NULL;
-static int opt_udp_io= 0;
-test_type opt_test= SET_TEST;
-
-int main(int argc, char *argv[])
-{
-  conclusions_st conclusion;
-  memcached_server_st *servers;
-
-  memset(&conclusion, 0, sizeof(conclusions_st));
-
-  srandom((unsigned int)time(NULL));
-  options_parse(argc, argv);
-
-  if (!opt_servers)
-  {
-    char *temp;
-
-    if ((temp= getenv("MEMCACHED_SERVERS")))
-      opt_servers= strdup(temp);
-    else
-    {
-      fprintf(stderr, "No Servers provided\n");
-      exit(1);
-    }
-  }
-
-  servers= memcached_servers_parse(opt_servers);
-
-  pthread_mutex_init(&counter_mutex, NULL);
-  pthread_cond_init(&count_threshhold, NULL);
-  pthread_mutex_init(&sleeper_mutex, NULL);
-  pthread_cond_init(&sleep_threshhold, NULL);
-
-  scheduler(servers, &conclusion);
-
-  free(opt_servers);
-
-  (void)pthread_mutex_destroy(&counter_mutex);
-  (void)pthread_cond_destroy(&count_threshhold);
-  (void)pthread_mutex_destroy(&sleeper_mutex);
-  (void)pthread_cond_destroy(&sleep_threshhold);
-  conclusions_print(&conclusion);
-  memcached_server_list_free(servers);
-
-  return 0;
-}
-
-void scheduler(memcached_server_st *servers, conclusions_st *conclusion)
-{
-  unsigned int actual_loaded= 0; /* Fix warning */
-  memcached_st *memc;
-
-  struct timeval start_time, end_time;
-  pthread_t mainthread;            /* Thread descriptor */
-  pthread_attr_t attr;          /* Thread attributes */
-  pairs_st *pairs= NULL;
-
-  pthread_attr_init(&attr);
-  pthread_attr_setdetachstate(&attr,
-                              PTHREAD_CREATE_DETACHED);
-
-  memc= memcached_create(NULL);
-
-  /* We need to set udp behavior before adding servers to the client */
-  if (opt_udp_io)
-  {
-    memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP,
-                           (uint64_t)opt_udp_io);
-    for (uint32_t x= 0; x < memcached_server_list_count(servers); x++ )
-    {
-      servers[x].type= MEMCACHED_CONNECTION_UDP;
-    }
-  }
-  memcached_server_push(memc, servers);
-
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
-                         (uint64_t)opt_binary);
-
-  if (opt_flush)
-    flush_all(memc);
-  if (opt_createial_load)
-    pairs= load_create_data(memc, opt_createial_load, &actual_loaded);
-
-  char **keys= calloc(actual_loaded, sizeof(char*));
-  size_t *key_lengths= calloc(actual_loaded, sizeof(size_t));
-
-  if (keys == NULL || key_lengths == NULL)
-  {
-    free(keys);
-    free(key_lengths);
-    keys= NULL;
-    key_lengths= NULL;
-  }
-  else
-  {
-    for (uint32_t x= 0; x < actual_loaded; ++x)
-    {
-      keys[x]= pairs[x].key;
-      key_lengths[x]= pairs[x].key_length;
-    }
-  }
-
-  /* We set this after we have loaded */
-  {
-    if (opt_non_blocking_io)
-      memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1);
-    if (opt_tcp_nodelay)
-      memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);
-  }
-
-  pthread_mutex_lock(&counter_mutex);
-  thread_counter= 0;
-
-  pthread_mutex_lock(&sleeper_mutex);
-  master_wakeup= 1;
-  pthread_mutex_unlock(&sleeper_mutex);
-
-  for (uint32_t x= 0; x < opt_concurrency; x++)
-  {
-    thread_context_st *context;
-    context= (thread_context_st *)calloc(1, sizeof(thread_context_st));
-
-    context->memc= memcached_clone(NULL, memc);
-    context->test= opt_test;
-
-    context->initial_pairs= pairs;
-    context->initial_number= actual_loaded;
-    context->keys= keys;
-    context->key_lengths= key_lengths;
-
-    if (opt_test == SET_TEST)
-    {
-      context->execute_pairs= pairs_generate(opt_execute_number, 400);
-      context->execute_number= opt_execute_number;
-    }
-
-    /* now you create the thread */
-    if (pthread_create(&mainthread, &attr, run_task,
-                       (void *)context) != 0)
-    {
-      fprintf(stderr,"Could not create thread\n");
-      exit(1);
-    }
-    thread_counter++;
-  }
-
-  pthread_mutex_unlock(&counter_mutex);
-  pthread_attr_destroy(&attr);
-
-  pthread_mutex_lock(&sleeper_mutex);
-  master_wakeup= 0;
-  pthread_mutex_unlock(&sleeper_mutex);
-  pthread_cond_broadcast(&sleep_threshhold);
-
-  gettimeofday(&start_time, NULL);
-  /*
-    We loop until we know that all children have cleaned up.
-  */
-  pthread_mutex_lock(&counter_mutex);
-  while (thread_counter)
-    pthread_cond_wait(&count_threshhold, &counter_mutex);
-  pthread_mutex_unlock(&counter_mutex);
-
-  gettimeofday(&end_time, NULL);
-
-  conclusion->load_time= timedif(end_time, start_time);
-  conclusion->read_time= timedif(end_time, start_time);
-  free(keys);
-  free(key_lengths);
-  pairs_free(pairs);
-  memcached_free(memc);
-}
-
-void options_parse(int argc, char *argv[])
-{
-  memcached_programs_help_st help_options[]=
-  {
-    {0},
-  };
-
-  static struct option long_options[]=
-    {
-      {(OPTIONSTRING)"concurrency", required_argument, NULL, OPT_SLAP_CONCURRENCY},
-      {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
-      {(OPTIONSTRING)"execute-number", required_argument, NULL, OPT_SLAP_EXECUTE_NUMBER},
-      {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
-      {(OPTIONSTRING)"flush", no_argument, &opt_flush, OPT_FLUSH},
-      {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
-      {(OPTIONSTRING)"initial-load", required_argument, NULL, OPT_SLAP_INITIAL_LOAD}, /* Number to load initially */
-      {(OPTIONSTRING)"non-blocking", no_argument, &opt_non_blocking_io, OPT_SLAP_NON_BLOCK},
-      {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
-      {(OPTIONSTRING)"tcp-nodelay", no_argument, &opt_tcp_nodelay, OPT_SLAP_TCP_NODELAY},
-      {(OPTIONSTRING)"test", required_argument, NULL, OPT_SLAP_TEST},
-      {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
-      {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
-      {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
-      {(OPTIONSTRING)"udp", no_argument, NULL, OPT_UDP},
-      {0, 0, 0, 0},
-    };
-
-  int option_index= 0;
-  int option_rv;
-
-  while (1)
-  {
-    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
-    if (option_rv == -1) break;
-    switch (option_rv)
-    {
-    case 0:
-      break;
-    case OPT_UDP:
-      if (opt_test == GET_TEST)
-      {
-        fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
-                  "does not currently support get ops.\n");
-        exit(1);
-      }
-      opt_udp_io= 1;
-      break;
-    case OPT_BINARY:
-      opt_binary = 1;
-      break;
-    case OPT_VERBOSE: /* --verbose or -v */
-      opt_verbose = OPT_VERBOSE;
-      break;
-    case OPT_DEBUG: /* --debug or -d */
-      opt_verbose = OPT_DEBUG;
-      break;
-    case OPT_VERSION: /* --version or -V */
-      version_command(PROGRAM_NAME);
-      break;
-    case OPT_HELP: /* --help or -h */
-      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
-      break;
-    case OPT_SERVERS: /* --servers or -s */
-      opt_servers= strdup(optarg);
-      break;
-    case OPT_SLAP_TEST:
-      if (!strcmp(optarg, "get"))
-      {
-        if (opt_udp_io == 1)
-        {
-          fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
-                  "does not currently support get ops.\n");
-          exit(1);
-        }
-        opt_test= GET_TEST ;
-      }
-      else if (!strcmp(optarg, "set"))
-        opt_test= SET_TEST;
-      else if (!strcmp(optarg, "mget"))
-      {
-        opt_test= MGET_TEST;
-      }
-      else
-      {
-        fprintf(stderr, "Your test, %s, is not a known test\n", optarg);
-        exit(1);
-      }
-      break;
-    case OPT_SLAP_CONCURRENCY:
-      opt_concurrency= (unsigned int)strtoul(optarg, (char **)NULL, 10);
-      break;
-    case OPT_SLAP_EXECUTE_NUMBER:
-      opt_execute_number= (unsigned int)strtoul(optarg, (char **)NULL, 10);
-      break;
-    case OPT_SLAP_INITIAL_LOAD:
-      opt_createial_load= (unsigned int)strtoul(optarg, (char **)NULL, 10);
-      break;
-    case '?':
-      /* getopt_long already printed an error message. */
-      exit(1);
-    default:
-      abort();
-    }
-  }
-
-  if ((opt_test == GET_TEST || opt_test == MGET_TEST) && opt_createial_load == 0)
-    opt_createial_load= DEFAULT_INITIAL_LOAD;
-
-  if (opt_execute_number == 0)
-    opt_execute_number= DEFAULT_EXECUTE_NUMBER;
-
-  if (opt_concurrency == 0)
-    opt_concurrency= DEFAULT_CONCURRENCY;
-}
-
-void conclusions_print(conclusions_st *conclusion)
-{
-  printf("\tThreads connecting to servers %u\n", opt_concurrency);
-#ifdef NOT_FINISHED
-  printf("\tLoaded %u rows\n", conclusion->rows_loaded);
-  printf("\tRead %u rows\n", conclusion->rows_read);
-#endif
-  if (opt_test == SET_TEST)
-    printf("\tTook %ld.%03ld seconds to load data\n", conclusion->load_time / 1000,
-           conclusion->load_time % 1000);
-  else
-    printf("\tTook %ld.%03ld seconds to read data\n", conclusion->read_time / 1000,
-           conclusion->read_time % 1000);
-}
-
-void *run_task(void *p)
-{
-  thread_context_st *context= (thread_context_st *)p;
-  memcached_st *memc;
-
-  memc= context->memc;
-
-  pthread_mutex_lock(&sleeper_mutex);
-  while (master_wakeup)
-  {
-    pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
-  }
-  pthread_mutex_unlock(&sleeper_mutex);
-
-  /* Do Stuff */
-  switch (context->test)
-  {
-  case SET_TEST:
-    assert(context->execute_pairs);
-    execute_set(memc, context->execute_pairs, context->execute_number);
-    break;
-  case GET_TEST:
-    execute_get(memc, context->initial_pairs, context->initial_number);
-    break;
-  case MGET_TEST:
-    execute_mget(memc, (const char*const*)context->keys, context->key_lengths,
-                 context->initial_number);
-    break;
-  default:
-    WATCHPOINT_ASSERT(context->test);
-    break;
-  }
-
-  memcached_free(memc);
-
-  if (context->execute_pairs)
-    pairs_free(context->execute_pairs);
-
-  free(context);
-
-  pthread_mutex_lock(&counter_mutex);
-  thread_counter--;
-  pthread_cond_signal(&count_threshhold);
-  pthread_mutex_unlock(&counter_mutex);
-
-  return NULL;
-}
-
-void flush_all(memcached_st *memc)
-{
-  memcached_flush(memc, 0);
-}
-
-pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
-                           unsigned int *actual_loaded)
-{
-  memcached_st *memc_clone;
-  pairs_st *pairs;
-
-  memc_clone= memcached_clone(NULL, memc);
-  /* We always used non-blocking IO for load since it is faster */
-  memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
-
-  pairs= pairs_generate(number_of, 400);
-  *actual_loaded= execute_set(memc_clone, pairs, number_of);
-
-  memcached_free(memc_clone);
-
-  return pairs;
-}
diff --git a/clients/memslap.cc b/clients/memslap.cc
new file mode 100644 (file)
index 0000000..d8927e7
--- /dev/null
@@ -0,0 +1,495 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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 <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <assert.h>
+
+#include <libmemcached/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+#include "generator.h"
+#include "execute.h"
+
+#define DEFAULT_INITIAL_LOAD 10000
+#define DEFAULT_EXECUTE_NUMBER 10000
+#define DEFAULT_CONCURRENCY 1
+
+#define PROGRAM_NAME "memslap"
+#define PROGRAM_DESCRIPTION "Generates a load against a memcached custer of servers."
+
+/* Global Thread counter */
+volatile unsigned int thread_counter;
+pthread_mutex_t counter_mutex;
+pthread_cond_t count_threshhold;
+volatile unsigned int master_wakeup;
+pthread_mutex_t sleeper_mutex;
+pthread_cond_t sleep_threshhold;
+
+void *run_task(void *p);
+
+/* Types */
+typedef struct conclusions_st conclusions_st;
+typedef struct thread_context_st thread_context_st;
+typedef enum {
+  SET_TEST,
+  GET_TEST,
+  MGET_TEST
+} test_type;
+
+struct thread_context_st {
+  unsigned int key_count;
+  pairs_st *initial_pairs;
+  unsigned int initial_number;
+  pairs_st *execute_pairs;
+  unsigned int execute_number;
+  char **keys;
+  size_t *key_lengths;
+  test_type test;
+  memcached_st *memc;
+};
+
+struct conclusions_st {
+  long int load_time;
+  long int read_time;
+  unsigned int rows_loaded;
+  unsigned int rows_read;
+};
+
+/* Prototypes */
+void options_parse(int argc, char *argv[]);
+void conclusions_print(conclusions_st *conclusion);
+void scheduler(memcached_server_st *servers, conclusions_st *conclusion);
+pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
+                           unsigned int *actual_loaded);
+void flush_all(memcached_st *memc);
+
+static int opt_binary= 0;
+static int opt_verbose= 0;
+static int opt_flush= 0;
+static int opt_non_blocking_io= 0;
+static int opt_tcp_nodelay= 0;
+static unsigned int opt_execute_number= 0;
+static unsigned int opt_createial_load= 0;
+static unsigned int opt_concurrency= 0;
+static int opt_displayflag= 0;
+static char *opt_servers= NULL;
+static int opt_udp_io= 0;
+test_type opt_test= SET_TEST;
+
+int main(int argc, char *argv[])
+{
+  conclusions_st conclusion;
+  memcached_server_st *servers;
+
+  memset(&conclusion, 0, sizeof(conclusions_st));
+
+  srandom((unsigned int)time(NULL));
+  options_parse(argc, argv);
+
+  if (!opt_servers)
+  {
+    char *temp;
+
+    if ((temp= getenv("MEMCACHED_SERVERS")))
+      opt_servers= strdup(temp);
+    else
+    {
+      fprintf(stderr, "No Servers provided\n");
+      exit(1);
+    }
+  }
+
+  servers= memcached_servers_parse(opt_servers);
+
+  pthread_mutex_init(&counter_mutex, NULL);
+  pthread_cond_init(&count_threshhold, NULL);
+  pthread_mutex_init(&sleeper_mutex, NULL);
+  pthread_cond_init(&sleep_threshhold, NULL);
+
+  scheduler(servers, &conclusion);
+
+  free(opt_servers);
+
+  (void)pthread_mutex_destroy(&counter_mutex);
+  (void)pthread_cond_destroy(&count_threshhold);
+  (void)pthread_mutex_destroy(&sleeper_mutex);
+  (void)pthread_cond_destroy(&sleep_threshhold);
+  conclusions_print(&conclusion);
+  memcached_server_list_free(servers);
+
+  return 0;
+}
+
+void scheduler(memcached_server_st *servers, conclusions_st *conclusion)
+{
+  unsigned int actual_loaded= 0; /* Fix warning */
+  memcached_st *memc;
+
+  struct timeval start_time, end_time;
+  pthread_t mainthread;            /* Thread descriptor */
+  pthread_attr_t attr;          /* Thread attributes */
+  pairs_st *pairs= NULL;
+
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr,
+                              PTHREAD_CREATE_DETACHED);
+
+  memc= memcached_create(NULL);
+
+  /* We need to set udp behavior before adding servers to the client */
+  if (opt_udp_io)
+  {
+    memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP,
+                           (uint64_t)opt_udp_io);
+    for (uint32_t x= 0; x < memcached_server_list_count(servers); x++ )
+    {
+      servers[x].type= MEMCACHED_CONNECTION_UDP;
+    }
+  }
+  memcached_server_push(memc, servers);
+
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+                         (uint64_t)opt_binary);
+
+  if (opt_flush)
+    flush_all(memc);
+  if (opt_createial_load)
+    pairs= load_create_data(memc, opt_createial_load, &actual_loaded);
+
+  char **keys= static_cast<char **>(calloc(actual_loaded, sizeof(char*)));
+  size_t *key_lengths= static_cast<size_t *>(calloc(actual_loaded, sizeof(size_t)));
+
+  if (keys == NULL || key_lengths == NULL)
+  {
+    free(keys);
+    free(key_lengths);
+    keys= NULL;
+    key_lengths= NULL;
+  }
+  else
+  {
+    for (uint32_t x= 0; x < actual_loaded; ++x)
+    {
+      keys[x]= pairs[x].key;
+      key_lengths[x]= pairs[x].key_length;
+    }
+  }
+
+  /* We set this after we have loaded */
+  {
+    if (opt_non_blocking_io)
+      memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1);
+    if (opt_tcp_nodelay)
+      memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);
+  }
+
+  pthread_mutex_lock(&counter_mutex);
+  thread_counter= 0;
+
+  pthread_mutex_lock(&sleeper_mutex);
+  master_wakeup= 1;
+  pthread_mutex_unlock(&sleeper_mutex);
+
+  for (uint32_t x= 0; x < opt_concurrency; x++)
+  {
+    thread_context_st *context;
+    context= (thread_context_st *)calloc(1, sizeof(thread_context_st));
+
+    context->memc= memcached_clone(NULL, memc);
+    context->test= opt_test;
+
+    context->initial_pairs= pairs;
+    context->initial_number= actual_loaded;
+    context->keys= keys;
+    context->key_lengths= key_lengths;
+
+    if (opt_test == SET_TEST)
+    {
+      context->execute_pairs= pairs_generate(opt_execute_number, 400);
+      context->execute_number= opt_execute_number;
+    }
+
+    /* now you create the thread */
+    if (pthread_create(&mainthread, &attr, run_task,
+                       (void *)context) != 0)
+    {
+      fprintf(stderr,"Could not create thread\n");
+      exit(1);
+    }
+    thread_counter++;
+  }
+
+  pthread_mutex_unlock(&counter_mutex);
+  pthread_attr_destroy(&attr);
+
+  pthread_mutex_lock(&sleeper_mutex);
+  master_wakeup= 0;
+  pthread_mutex_unlock(&sleeper_mutex);
+  pthread_cond_broadcast(&sleep_threshhold);
+
+  gettimeofday(&start_time, NULL);
+  /*
+    We loop until we know that all children have cleaned up.
+  */
+  pthread_mutex_lock(&counter_mutex);
+  while (thread_counter)
+    pthread_cond_wait(&count_threshhold, &counter_mutex);
+  pthread_mutex_unlock(&counter_mutex);
+
+  gettimeofday(&end_time, NULL);
+
+  conclusion->load_time= timedif(end_time, start_time);
+  conclusion->read_time= timedif(end_time, start_time);
+  free(keys);
+  free(key_lengths);
+  pairs_free(pairs);
+  memcached_free(memc);
+}
+
+void options_parse(int argc, char *argv[])
+{
+  memcached_programs_help_st help_options[]=
+  {
+    {0},
+  };
+
+  static struct option long_options[]=
+    {
+      {(OPTIONSTRING)"concurrency", required_argument, NULL, OPT_SLAP_CONCURRENCY},
+      {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+      {(OPTIONSTRING)"execute-number", required_argument, NULL, OPT_SLAP_EXECUTE_NUMBER},
+      {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
+      {(OPTIONSTRING)"flush", no_argument, &opt_flush, OPT_FLUSH},
+      {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+      {(OPTIONSTRING)"initial-load", required_argument, NULL, OPT_SLAP_INITIAL_LOAD}, /* Number to load initially */
+      {(OPTIONSTRING)"non-blocking", no_argument, &opt_non_blocking_io, OPT_SLAP_NON_BLOCK},
+      {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+      {(OPTIONSTRING)"tcp-nodelay", no_argument, &opt_tcp_nodelay, OPT_SLAP_TCP_NODELAY},
+      {(OPTIONSTRING)"test", required_argument, NULL, OPT_SLAP_TEST},
+      {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+      {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+      {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
+      {(OPTIONSTRING)"udp", no_argument, NULL, OPT_UDP},
+      {0, 0, 0, 0},
+    };
+
+  int option_index= 0;
+  int option_rv;
+
+  while (1)
+  {
+    option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
+    if (option_rv == -1) break;
+    switch (option_rv)
+    {
+    case 0:
+      break;
+    case OPT_UDP:
+      if (opt_test == GET_TEST)
+      {
+        fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
+                  "does not currently support get ops.\n");
+        exit(1);
+      }
+      opt_udp_io= 1;
+      break;
+    case OPT_BINARY:
+      opt_binary = 1;
+      break;
+    case OPT_VERBOSE: /* --verbose or -v */
+      opt_verbose = OPT_VERBOSE;
+      break;
+    case OPT_DEBUG: /* --debug or -d */
+      opt_verbose = OPT_DEBUG;
+      break;
+    case OPT_VERSION: /* --version or -V */
+      version_command(PROGRAM_NAME);
+      break;
+    case OPT_HELP: /* --help or -h */
+      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+      break;
+    case OPT_SERVERS: /* --servers or -s */
+      opt_servers= strdup(optarg);
+      break;
+    case OPT_SLAP_TEST:
+      if (!strcmp(optarg, "get"))
+      {
+        if (opt_udp_io == 1)
+        {
+          fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
+                  "does not currently support get ops.\n");
+          exit(1);
+        }
+        opt_test= GET_TEST ;
+      }
+      else if (!strcmp(optarg, "set"))
+        opt_test= SET_TEST;
+      else if (!strcmp(optarg, "mget"))
+      {
+        opt_test= MGET_TEST;
+      }
+      else
+      {
+        fprintf(stderr, "Your test, %s, is not a known test\n", optarg);
+        exit(1);
+      }
+      break;
+    case OPT_SLAP_CONCURRENCY:
+      opt_concurrency= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+      break;
+    case OPT_SLAP_EXECUTE_NUMBER:
+      opt_execute_number= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+      break;
+    case OPT_SLAP_INITIAL_LOAD:
+      opt_createial_load= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+      break;
+    case '?':
+      /* getopt_long already printed an error message. */
+      exit(1);
+    default:
+      abort();
+    }
+  }
+
+  if ((opt_test == GET_TEST || opt_test == MGET_TEST) && opt_createial_load == 0)
+    opt_createial_load= DEFAULT_INITIAL_LOAD;
+
+  if (opt_execute_number == 0)
+    opt_execute_number= DEFAULT_EXECUTE_NUMBER;
+
+  if (opt_concurrency == 0)
+    opt_concurrency= DEFAULT_CONCURRENCY;
+}
+
+void conclusions_print(conclusions_st *conclusion)
+{
+  printf("\tThreads connecting to servers %u\n", opt_concurrency);
+#ifdef NOT_FINISHED
+  printf("\tLoaded %u rows\n", conclusion->rows_loaded);
+  printf("\tRead %u rows\n", conclusion->rows_read);
+#endif
+  if (opt_test == SET_TEST)
+    printf("\tTook %ld.%03ld seconds to load data\n", conclusion->load_time / 1000,
+           conclusion->load_time % 1000);
+  else
+    printf("\tTook %ld.%03ld seconds to read data\n", conclusion->read_time / 1000,
+           conclusion->read_time % 1000);
+}
+
+void *run_task(void *p)
+{
+  thread_context_st *context= (thread_context_st *)p;
+  memcached_st *memc;
+
+  memc= context->memc;
+
+  pthread_mutex_lock(&sleeper_mutex);
+  while (master_wakeup)
+  {
+    pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
+  }
+  pthread_mutex_unlock(&sleeper_mutex);
+
+  /* Do Stuff */
+  switch (context->test)
+  {
+  case SET_TEST:
+    assert(context->execute_pairs);
+    execute_set(memc, context->execute_pairs, context->execute_number);
+    break;
+  case GET_TEST:
+    execute_get(memc, context->initial_pairs, context->initial_number);
+    break;
+  case MGET_TEST:
+    execute_mget(memc, (const char*const*)context->keys, context->key_lengths,
+                 context->initial_number);
+    break;
+  default:
+    WATCHPOINT_ASSERT(context->test);
+    break;
+  }
+
+  memcached_free(memc);
+
+  if (context->execute_pairs)
+    pairs_free(context->execute_pairs);
+
+  free(context);
+
+  pthread_mutex_lock(&counter_mutex);
+  thread_counter--;
+  pthread_cond_signal(&count_threshhold);
+  pthread_mutex_unlock(&counter_mutex);
+
+  return NULL;
+}
+
+void flush_all(memcached_st *memc)
+{
+  memcached_flush(memc, 0);
+}
+
+pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
+                           unsigned int *actual_loaded)
+{
+  memcached_st *memc_clone;
+  pairs_st *pairs;
+
+  memc_clone= memcached_clone(NULL, memc);
+  /* We always used non-blocking IO for load since it is faster */
+  memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
+
+  pairs= pairs_generate(number_of, 400);
+  *actual_loaded= execute_set(memc_clone, pairs, number_of);
+
+  memcached_free(memc_clone);
+
+  return pairs;
+}
diff --git a/clients/memstat.c b/clients/memstat.c
deleted file mode 100644 (file)
index d351845..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- * Authors: 
- *          Brian Aker
- *          Toru Maesaka
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <string.h>
-#include <getopt.h>
-#include <sys/time.h>
-
-#include <libmemcached/memcached.h>
-
-#include "client_options.h"
-#include "utilities.h"
-
-#define PROGRAM_NAME "memstat"
-#define PROGRAM_DESCRIPTION "Output the state of a memcached cluster."
-
-/* Prototypes */
-static void options_parse(int argc, char *argv[]);
-static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat);
-static void print_analysis_report(memcached_st *memc,
-                                  memcached_analysis_st *report);
-
-static int opt_verbose= 0;
-static int opt_displayflag= 0;
-static int opt_analyze= 0;
-static char *opt_servers= NULL;
-static char *stat_args= NULL;
-static char *analyze_mode= NULL;
-
-static struct option long_options[]=
-{
-  {(OPTIONSTRING)"args", required_argument, NULL, OPT_STAT_ARGS},
-  {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
-  {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
-  {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
-  {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
-  {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
-  {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
-  {(OPTIONSTRING)"analyze", optional_argument, NULL, OPT_ANALYZE},
-  {0, 0, 0, 0},
-};
-
-
-static memcached_return_t stat_printer(memcached_server_instance_st instance,
-                                       const char *key, size_t key_length,
-                                       const char *value, size_t value_length,
-                                       void *context)
-{
-  static memcached_server_instance_st last= NULL;
-  (void)context;
-
-  if (last != instance)
-  {
-    printf("Server: %s (%u)\n", memcached_server_name(instance),
-           (uint32_t)memcached_server_port(instance));
-    last= instance;
-  }
-
-  printf("\t %.*s: %.*s\n", (int)key_length, key, (int)value_length, value);
-
-  return MEMCACHED_SUCCESS;
-}
-
-int main(int argc, char *argv[])
-{
-  options_parse(argc, argv);
-  initialize_sockets();
-
-  if (! opt_servers)
-  {
-    char *temp;
-
-    if ((temp= getenv("MEMCACHED_SERVERS")))
-      opt_servers= strdup(temp);
-    else
-    {
-      fprintf(stderr, "No Servers provided\n\n");
-      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, 0);
-      exit(1);
-    }
-  }
-
-  memcached_st *memc= memcached_create(NULL);
-
-  memcached_server_st *servers= memcached_servers_parse(opt_servers);
-  free(opt_servers);
-
-  memcached_return_t rc= memcached_server_push(memc, servers);
-  memcached_server_list_free(servers);
-
-  if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS)
-  {
-    printf("Failure to communicate with servers (%s)\n",
-           memcached_strerror(memc, rc));
-    exit(1);
-  }
-
-  if (opt_analyze)
-  {
-    memcached_stat_st *memc_stat;
-
-    memc_stat= memcached_stat(memc, NULL, &rc);
-
-    if (! memc_stat)
-      exit(-1);
-
-    run_analyzer(memc, memc_stat);
-
-    memcached_stat_free(memc, memc_stat);
-  }
-  else
-  {
-    rc= memcached_stat_execute(memc, stat_args, stat_printer, NULL);
-  }
-
-  memcached_free(memc);
-
-  return rc == MEMCACHED_SUCCESS ? EXIT_SUCCESS: EXIT_FAILURE;
-}
-
-static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat)
-{
-  memcached_return_t rc;
-
-  if (analyze_mode == NULL)
-  {
-    memcached_analysis_st *report;
-    report= memcached_analyze(memc, memc_stat, &rc);
-    if (rc != MEMCACHED_SUCCESS || report == NULL)
-    {
-      printf("Failure to analyze servers (%s)\n",
-             memcached_strerror(memc, rc));
-      exit(1);
-    }
-    print_analysis_report(memc, report);
-    free(report);
-  }
-  else if (strcmp(analyze_mode, "latency") == 0)
-  {
-    memcached_st **servers;
-    uint32_t flags, server_count= memcached_server_count(memc);
-    uint32_t num_of_tests= 32;
-    const char *test_key= "libmemcached_test_key";
-
-    servers= malloc(sizeof(memcached_st*) * server_count);
-    if (!servers)
-    {
-      fprintf(stderr, "Failed to allocate memory\n");
-      return;
-    }
-
-    for (uint32_t x= 0; x < server_count; x++)
-    {
-      memcached_server_instance_st instance=
-        memcached_server_instance_by_position(memc, x);
-
-      if ((servers[x]= memcached_create(NULL)) == NULL)
-      {
-        fprintf(stderr, "Failed to memcached_create()\n");
-        if (x > 0)
-          memcached_free(servers[0]);
-        x--;
-        for (; x > 0; x--)
-          memcached_free(servers[x]);
-
-        free(servers);
-        return;
-      }
-      memcached_server_add(servers[x],
-                           memcached_server_name(instance),
-                           memcached_server_port(instance));
-    }
-
-    printf("Network Latency Test:\n\n");
-    struct timeval start_time, end_time;
-    uint32_t slowest_server= 0;
-    long elapsed_time, slowest_time= 0;
-
-    for (uint32_t x= 0; x < server_count; x++)
-    {
-      memcached_server_instance_st instance=
-        memcached_server_instance_by_position(memc, x);
-      gettimeofday(&start_time, NULL);
-
-      for (uint32_t y= 0; y < num_of_tests; y++)
-      {
-        size_t vlen;
-        char *val= memcached_get(servers[x], test_key, strlen(test_key),
-                                 &vlen, &flags, &rc);
-        if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
-          break;
-        free(val);
-      }
-      gettimeofday(&end_time, NULL);
-
-      elapsed_time= (long) timedif(end_time, start_time);
-      elapsed_time /= (long) num_of_tests;
-
-      if (elapsed_time > slowest_time)
-      {
-        slowest_server= x;
-        slowest_time= elapsed_time;
-      }
-
-      if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
-      {
-        printf("\t %s (%d)  =>  failed to reach the server\n",
-               memcached_server_name(instance),
-               memcached_server_port(instance));
-      }
-      else
-      {
-        printf("\t %s (%d)  =>  %ld.%ld seconds\n",
-               memcached_server_name(instance),
-               memcached_server_port(instance),
-               elapsed_time / 1000, elapsed_time % 1000);
-      }
-    }
-
-    if (server_count > 1 && slowest_time > 0)
-    {
-      memcached_server_instance_st slowest=
-        memcached_server_instance_by_position(memc, slowest_server);
-
-      printf("---\n");
-      printf("Slowest Server: %s (%d) => %ld.%ld seconds\n",
-             memcached_server_name(slowest),
-             memcached_server_port(slowest),
-             slowest_time / 1000, slowest_time % 1000);
-    }
-    printf("\n");
-
-    for (uint32_t x= 0; x < server_count; x++)
-      memcached_free(servers[x]);
-
-    free(servers);
-    free(analyze_mode);
-  }
-  else
-  {
-    fprintf(stderr, "Invalid Analyzer Option provided\n");
-    free(analyze_mode);
-  }
-}
-
-static void print_analysis_report(memcached_st *memc,
-                                  memcached_analysis_st *report)
-                                  
-{
-  uint32_t server_count= memcached_server_count(memc);
-  memcached_server_instance_st most_consumed_server= memcached_server_instance_by_position(memc, report->most_consumed_server);
-  memcached_server_instance_st least_free_server= memcached_server_instance_by_position(memc, report->least_free_server);
-  memcached_server_instance_st oldest_server= memcached_server_instance_by_position(memc, report->oldest_server);
-
-  printf("Memcached Cluster Analysis Report\n\n");
-
-  printf("\tNumber of Servers Analyzed         : %u\n", server_count);
-  printf("\tAverage Item Size (incl/overhead)  : %u bytes\n",
-         report->average_item_size);
-
-  if (server_count == 1)
-  {
-    printf("\nFor a detailed report, you must supply multiple servers.\n");
-    return;
-  }
-
-  printf("\n");
-  printf("\tNode with most memory consumption  : %s:%u (%llu bytes)\n",
-         memcached_server_name(most_consumed_server),
-         (uint32_t)memcached_server_port(most_consumed_server),
-         (unsigned long long)report->most_used_bytes);
-  printf("\tNode with least free space         : %s:%u (%llu bytes remaining)\n",
-         memcached_server_name(least_free_server),
-         (uint32_t)memcached_server_port(least_free_server),
-         (unsigned long long)report->least_remaining_bytes);
-  printf("\tNode with longest uptime           : %s:%u (%us)\n",
-         memcached_server_name(oldest_server),
-         (uint32_t)memcached_server_port(oldest_server),
-         report->longest_uptime);
-  printf("\tPool-wide Hit Ratio                : %1.f%%\n", report->pool_hit_ratio);
-  printf("\n");
-}
-
-static void options_parse(int argc, char *argv[])
-{
-  memcached_programs_help_st help_options[]=
-  {
-    {0},
-  };
-
-  int option_index= 0;
-  int option_rv;
-
-  while (1) 
-  {
-    option_rv= getopt_long(argc, argv, "Vhvds:a", long_options, &option_index);
-    if (option_rv == -1) break;
-    switch (option_rv)
-    {
-    case 0:
-      break;
-    case OPT_VERBOSE: /* --verbose or -v */
-      opt_verbose = OPT_VERBOSE;
-      break;
-    case OPT_DEBUG: /* --debug or -d */
-      opt_verbose = OPT_DEBUG;
-      break;
-    case OPT_VERSION: /* --version or -V */
-      version_command(PROGRAM_NAME);
-      break;
-    case OPT_HELP: /* --help or -h */
-      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
-      break;
-    case OPT_SERVERS: /* --servers or -s */
-      opt_servers= strdup(optarg);
-      break;
-    case OPT_STAT_ARGS:
-      stat_args= strdup(optarg);
-      break;
-    case OPT_ANALYZE: /* --analyze or -a */
-      opt_analyze= OPT_ANALYZE;
-      analyze_mode= (optarg) ? strdup(optarg) : NULL;
-      break;
-    case '?':
-      /* getopt_long already printed an error message. */
-      exit(1);
-    default:
-      abort();
-    }
-  }
-}
diff --git a/clients/memstat.cc b/clients/memstat.cc
new file mode 100644 (file)
index 0000000..a3b8510
--- /dev/null
@@ -0,0 +1,349 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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:
+ *
+ * Authors: 
+ *          Brian Aker
+ *          Toru Maesaka
+ */
+#include "config.h"
+
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/types.h>
+
+#include <libmemcached/memcached.h>
+
+#include "client_options.h"
+#include "utilities.h"
+
+#define PROGRAM_NAME "memstat"
+#define PROGRAM_DESCRIPTION "Output the state of a memcached cluster."
+
+/* Prototypes */
+static void options_parse(int argc, char *argv[]);
+static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat);
+static void print_analysis_report(memcached_st *memc,
+                                  memcached_analysis_st *report);
+
+static int opt_verbose= 0;
+static int opt_displayflag= 0;
+static int opt_analyze= 0;
+static char *opt_servers= NULL;
+static char *stat_args= NULL;
+static char *analyze_mode= NULL;
+
+static struct option long_options[]=
+{
+  {(OPTIONSTRING)"args", required_argument, NULL, OPT_STAT_ARGS},
+  {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
+  {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
+  {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
+  {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
+  {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
+  {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
+  {(OPTIONSTRING)"analyze", optional_argument, NULL, OPT_ANALYZE},
+  {0, 0, 0, 0},
+};
+
+
+static memcached_return_t stat_printer(memcached_server_instance_st instance,
+                                       const char *key, size_t key_length,
+                                       const char *value, size_t value_length,
+                                       void *context)
+{
+  static memcached_server_instance_st last= NULL;
+  (void)context;
+
+  if (last != instance)
+  {
+    printf("Server: %s (%u)\n", memcached_server_name(instance),
+           (uint32_t)memcached_server_port(instance));
+    last= instance;
+  }
+
+  printf("\t %.*s: %.*s\n", (int)key_length, key, (int)value_length, value);
+
+  return MEMCACHED_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+  options_parse(argc, argv);
+  initialize_sockets();
+
+  if (! opt_servers)
+  {
+    char *temp;
+
+    if ((temp= getenv("MEMCACHED_SERVERS")))
+      opt_servers= strdup(temp);
+    else
+    {
+      fprintf(stderr, "No Servers provided\n\n");
+      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, 0);
+      exit(1);
+    }
+  }
+
+  memcached_st *memc= memcached_create(NULL);
+
+  memcached_server_st *servers= memcached_servers_parse(opt_servers);
+  free(opt_servers);
+
+  memcached_return_t rc= memcached_server_push(memc, servers);
+  memcached_server_list_free(servers);
+
+  if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS)
+  {
+    printf("Failure to communicate with servers (%s)\n",
+           memcached_strerror(memc, rc));
+    exit(1);
+  }
+
+  if (opt_analyze)
+  {
+    memcached_stat_st *memc_stat;
+
+    memc_stat= memcached_stat(memc, NULL, &rc);
+
+    if (! memc_stat)
+      exit(-1);
+
+    run_analyzer(memc, memc_stat);
+
+    memcached_stat_free(memc, memc_stat);
+  }
+  else
+  {
+    rc= memcached_stat_execute(memc, stat_args, stat_printer, NULL);
+  }
+
+  memcached_free(memc);
+
+  return rc == MEMCACHED_SUCCESS ? EXIT_SUCCESS: EXIT_FAILURE;
+}
+
+static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat)
+{
+  memcached_return_t rc;
+
+  if (analyze_mode == NULL)
+  {
+    memcached_analysis_st *report;
+    report= memcached_analyze(memc, memc_stat, &rc);
+    if (rc != MEMCACHED_SUCCESS || report == NULL)
+    {
+      printf("Failure to analyze servers (%s)\n",
+             memcached_strerror(memc, rc));
+      exit(1);
+    }
+    print_analysis_report(memc, report);
+    free(report);
+  }
+  else if (strcmp(analyze_mode, "latency") == 0)
+  {
+    uint32_t flags, server_count= memcached_server_count(memc);
+    uint32_t num_of_tests= 32;
+    const char *test_key= "libmemcached_test_key";
+
+    memcached_st **servers;
+    servers= static_cast<memcached_st**>(malloc(sizeof(memcached_st*) * server_count));
+    if (not servers)
+    {
+      fprintf(stderr, "Failed to allocate memory\n");
+      return;
+    }
+
+    for (uint32_t x= 0; x < server_count; x++)
+    {
+      memcached_server_instance_st instance=
+        memcached_server_instance_by_position(memc, x);
+
+      if ((servers[x]= memcached_create(NULL)) == NULL)
+      {
+        fprintf(stderr, "Failed to memcached_create()\n");
+        if (x > 0)
+          memcached_free(servers[0]);
+        x--;
+
+        for (; x > 0; x--)
+          memcached_free(servers[x]);
+
+        free(servers);
+        return;
+      }
+      memcached_server_add(servers[x],
+                           memcached_server_name(instance),
+                           memcached_server_port(instance));
+    }
+
+    printf("Network Latency Test:\n\n");
+    struct timeval start_time, end_time;
+    uint32_t slowest_server= 0;
+    long elapsed_time, slowest_time= 0;
+
+    for (uint32_t x= 0; x < server_count; x++)
+    {
+      memcached_server_instance_st instance=
+        memcached_server_instance_by_position(memc, x);
+      gettimeofday(&start_time, NULL);
+
+      for (uint32_t y= 0; y < num_of_tests; y++)
+      {
+        size_t vlen;
+        char *val= memcached_get(servers[x], test_key, strlen(test_key),
+                                 &vlen, &flags, &rc);
+        if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
+          break;
+        free(val);
+      }
+      gettimeofday(&end_time, NULL);
+
+      elapsed_time= (long) timedif(end_time, start_time);
+      elapsed_time /= (long) num_of_tests;
+
+      if (elapsed_time > slowest_time)
+      {
+        slowest_server= x;
+        slowest_time= elapsed_time;
+      }
+
+      if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
+      {
+        printf("\t %s (%d)  =>  failed to reach the server\n",
+               memcached_server_name(instance),
+               memcached_server_port(instance));
+      }
+      else
+      {
+        printf("\t %s (%d)  =>  %ld.%ld seconds\n",
+               memcached_server_name(instance),
+               memcached_server_port(instance),
+               elapsed_time / 1000, elapsed_time % 1000);
+      }
+    }
+
+    if (server_count > 1 && slowest_time > 0)
+    {
+      memcached_server_instance_st slowest=
+        memcached_server_instance_by_position(memc, slowest_server);
+
+      printf("---\n");
+      printf("Slowest Server: %s (%d) => %ld.%ld seconds\n",
+             memcached_server_name(slowest),
+             memcached_server_port(slowest),
+             slowest_time / 1000, slowest_time % 1000);
+    }
+    printf("\n");
+
+    for (uint32_t x= 0; x < server_count; x++)
+      memcached_free(servers[x]);
+
+    free(servers);
+    free(analyze_mode);
+  }
+  else
+  {
+    fprintf(stderr, "Invalid Analyzer Option provided\n");
+    free(analyze_mode);
+  }
+}
+
+static void print_analysis_report(memcached_st *memc,
+                                  memcached_analysis_st *report)
+                                  
+{
+  uint32_t server_count= memcached_server_count(memc);
+  memcached_server_instance_st most_consumed_server= memcached_server_instance_by_position(memc, report->most_consumed_server);
+  memcached_server_instance_st least_free_server= memcached_server_instance_by_position(memc, report->least_free_server);
+  memcached_server_instance_st oldest_server= memcached_server_instance_by_position(memc, report->oldest_server);
+
+  printf("Memcached Cluster Analysis Report\n\n");
+
+  printf("\tNumber of Servers Analyzed         : %u\n", server_count);
+  printf("\tAverage Item Size (incl/overhead)  : %u bytes\n",
+         report->average_item_size);
+
+  if (server_count == 1)
+  {
+    printf("\nFor a detailed report, you must supply multiple servers.\n");
+    return;
+  }
+
+  printf("\n");
+  printf("\tNode with most memory consumption  : %s:%u (%llu bytes)\n",
+         memcached_server_name(most_consumed_server),
+         (uint32_t)memcached_server_port(most_consumed_server),
+         (unsigned long long)report->most_used_bytes);
+  printf("\tNode with least free space         : %s:%u (%llu bytes remaining)\n",
+         memcached_server_name(least_free_server),
+         (uint32_t)memcached_server_port(least_free_server),
+         (unsigned long long)report->least_remaining_bytes);
+  printf("\tNode with longest uptime           : %s:%u (%us)\n",
+         memcached_server_name(oldest_server),
+         (uint32_t)memcached_server_port(oldest_server),
+         report->longest_uptime);
+  printf("\tPool-wide Hit Ratio                : %1.f%%\n", report->pool_hit_ratio);
+  printf("\n");
+}
+
+static void options_parse(int argc, char *argv[])
+{
+  memcached_programs_help_st help_options[]=
+  {
+    {0},
+  };
+
+  int option_index= 0;
+  int option_rv;
+
+  while (1) 
+  {
+    option_rv= getopt_long(argc, argv, "Vhvds:a", long_options, &option_index);
+    if (option_rv == -1) break;
+    switch (option_rv)
+    {
+    case 0:
+      break;
+    case OPT_VERBOSE: /* --verbose or -v */
+      opt_verbose = OPT_VERBOSE;
+      break;
+    case OPT_DEBUG: /* --debug or -d */
+      opt_verbose = OPT_DEBUG;
+      break;
+    case OPT_VERSION: /* --version or -V */
+      version_command(PROGRAM_NAME);
+      break;
+    case OPT_HELP: /* --help or -h */
+      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+      break;
+    case OPT_SERVERS: /* --servers or -s */
+      opt_servers= strdup(optarg);
+      break;
+    case OPT_STAT_ARGS:
+      stat_args= strdup(optarg);
+      break;
+    case OPT_ANALYZE: /* --analyze or -a */
+      opt_analyze= OPT_ANALYZE;
+      analyze_mode= (optarg) ? strdup(optarg) : NULL;
+      break;
+    case '?':
+      /* getopt_long already printed an error message. */
+      exit(1);
+    default:
+      abort();
+    }
+  }
+}
index cf1e8c0fc9c71dace61c4e10aab87a4dc7cb7b71..b915888d95d6b9cb420834e55172e719c2745d6b 100644 (file)
@@ -60,7 +60,7 @@ enum conn_states
 {
   conn_read,         /* reading in a command line */
   conn_write,        /* writing out a simple response */
-  conn_closing,      /* closing this connection */
+  conn_closing      /* closing this connection */
 };
 
 /* returned states of memcached command */
@@ -78,7 +78,7 @@ enum mcd_ret
   MCD_NOTFOUND,                     /* server not find the object */
   MCD_END,                          /* end of the response of get command */
   MCD_DELETED,                      /* server delete the object successfully */
-  MCD_STAT,                         /* response of stats command */
+  MCD_STAT                         /* response of stats command */
 };
 
 /* used to store the current or previous running command state */
@@ -103,7 +103,7 @@ typedef struct udppkt
 enum protocol
 {
   ascii_prot = 3,           /* ASCII protocol */
-  binary_prot,              /* binary protocol */
+  binary_prot              /* binary protocol */
 };
 
 /**
index dc0844d82ff2496eb03ca86a61fea5f59d9784cd..1c1b29ebe7f38163ab84f745aad80710bdb6bc35 100644 (file)
@@ -55,7 +55,7 @@ typedef enum
   OPT_BINARY_PROTOCOL= 'B',
   OPT_OVERWRITE= 'o',
   OPT_TPS= 'P',
-  OPT_REP_WRITE_SRV= 'p',
+  OPT_REP_WRITE_SRV= 'p'
 } ms_options_t;
 
 /* global statistic of response time */
index d8ccf8bbf42a753730c2bc8b0beffba3664a571c..964dc40077284295db661cbf8285fd604f2030ce 100644 (file)
@@ -88,7 +88,7 @@ typedef enum cmd_type
 {
   CMD_SET,
   CMD_GET,
-  CMD_NULL,
+  CMD_NULL
 } ms_cmd_type_t;
 
 /* types in the configuration file */
@@ -97,7 +97,7 @@ typedef enum conf_type
   CONF_KEY,
   CONF_VALUE,
   CONF_CMD,
-  CONF_NULL,
+  CONF_NULL
 } ms_conf_type_t;
 
 /* information of command distribution */
diff --git a/clients/utilities.c b/clients/utilities.c
deleted file mode 100644 (file)
index 9298747..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include "utilities.h"
-
-
-long int timedif(struct timeval a, struct timeval b)
-{
-  long us, s;
-
-  us = (int)(a.tv_usec - b.tv_usec);
-  us /= 1000;
-  s = (int)(a.tv_sec - b.tv_sec);
-  s *= 1000;
-  return s + us;
-}
-
-void version_command(const char *command_name)
-{
-  printf("%s v%u.%u\n", command_name, 1U, 0U);
-  exit(0);
-}
-
-static const char *lookup_help(memcached_options option)
-{
-  switch (option)
-  {
-  case OPT_SERVERS: return("List which servers you wish to connect to.");
-  case OPT_VERSION: return("Display the version of the application and then exit.");
-  case OPT_HELP: return("Display this message and then exit.");
-  case OPT_VERBOSE: return("Give more details on the progression of the application.");
-  case OPT_DEBUG: return("Provide output only useful for debugging.");
-  case OPT_FLAG: return("Provide flag information for storage operation.");
-  case OPT_EXPIRE: return("Set the expire option for the object.");
-  case OPT_SET: return("Use set command with memcached when storing.");
-  case OPT_REPLACE: return("Use replace command with memcached when storing.");
-  case OPT_ADD: return("Use add command with memcached when storing.");
-  case OPT_SLAP_EXECUTE_NUMBER: return("Number of times to execute the given test.");
-  case OPT_SLAP_INITIAL_LOAD: return("Number of key pairs to load before executing tests.");
-  case OPT_SLAP_TEST: return("Test to run (currently \"get\" or \"set\").");
-  case OPT_SLAP_CONCURRENCY: return("Number of users to simulate with load.");
-  case OPT_SLAP_NON_BLOCK: return("Set TCP up to use non-blocking IO.");
-  case OPT_SLAP_TCP_NODELAY: return("Set TCP socket up to use nodelay.");
-  case OPT_FLUSH: return("Flush servers before running tests.");
-  case OPT_HASH: return("Select hash type.");
-  case OPT_BINARY: return("Switch to binary protocol.");
-  case OPT_ANALYZE: return("Analyze the provided servers.");
-  case OPT_UDP: return("Use UDP protocol when communicating with server.");
-  case OPT_USERNAME: return "Username to use for SASL authentication";
-  case OPT_PASSWD: return "Password to use for SASL authentication";
-  case OPT_FILE: return "Path to file in which to save result";
-  case OPT_STAT_ARGS: return "Argument for statistics";
-  default: WATCHPOINT_ASSERT(0);
-  };
-
-  WATCHPOINT_ASSERT(0);
-  return "forgot to document this function :)";
-}
-
-void help_command(const char *command_name, const char *description,
-                  const struct option *long_options,
-                  memcached_programs_help_st *options)
-{
-  unsigned int x;
-  (void)options;
-
-  printf("%s v%u.%u\n\n", command_name, 1U, 0U);
-  printf("\t%s\n\n", description);
-  printf("Current options. A '=' means the option takes a value.\n\n");
-
-  for (x= 0; long_options[x].name; x++)
-  {
-    const char *help_message;
-
-    printf("\t --%s%c\n", long_options[x].name,
-           long_options[x].has_arg ? '=' : ' ');
-    if ((help_message= lookup_help(long_options[x].val)))
-      printf("\t\t%s\n", help_message);
-  }
-
-  printf("\n");
-  exit(0);
-}
-
-void process_hash_option(memcached_st *memc, char *opt_hash)
-{
-  uint64_t set;
-  memcached_return_t rc;
-
-  if (opt_hash == NULL)
-    return;
-
-  set= MEMCACHED_HASH_DEFAULT; /* Just here to solve warning */
-  if (!strcasecmp(opt_hash, "CRC"))
-    set= MEMCACHED_HASH_CRC;
-  else if (!strcasecmp(opt_hash, "FNV1_64"))
-    set= MEMCACHED_HASH_FNV1_64;
-  else if (!strcasecmp(opt_hash, "FNV1A_64"))
-    set= MEMCACHED_HASH_FNV1A_64;
-  else if (!strcasecmp(opt_hash, "FNV1_32"))
-    set= MEMCACHED_HASH_FNV1_32;
-  else if (!strcasecmp(opt_hash, "FNV1A_32"))
-    set= MEMCACHED_HASH_FNV1A_32;
-  else
-  {
-    fprintf(stderr, "hash: type not recognized %s\n", opt_hash);
-    exit(1);
-  }
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    fprintf(stderr, "hash: memcache error %s\n", memcached_strerror(memc, rc));
-    exit(1);
-  }
-}
-
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
-static char *username;
-static char *passwd;
-
-static int get_username(void *context, int id, const char **result,
-                        unsigned int *len)
-{
-  (void)context;
-  if (!result || (id != SASL_CB_USER && id != SASL_CB_AUTHNAME))
-    return SASL_BADPARAM;
-
-  *result= username;
-  if (len)
-     *len= (username == NULL) ? 0 : (unsigned int)strlen(username);
-
-  return SASL_OK;
-}
-
-static int get_password(sasl_conn_t *conn, void *context, int id,
-                        sasl_secret_t **psecret)
-{
-  (void)context;
-  static sasl_secret_t* ptr;
-
-  if (!conn || ! psecret || id != SASL_CB_PASS)
-    return SASL_BADPARAM;
-
-  if (passwd == NULL)
-  {
-     *psecret= NULL;
-     return SASL_OK;
-  }
-
-  size_t len= strlen(passwd);
-  ptr= malloc(sizeof(sasl_secret_t) + len +1);
-  if (! ptr)
-    return SASL_NOMEM;
-
-  ptr->len= len;
-  memcpy(ptr->data, passwd, len);
-  ptr->data[len]= 0;
-
-  *psecret= ptr;
-  return SASL_OK;
-}
-
-/* callbacks we support */
-static sasl_callback_t sasl_callbacks[] = {
-  {
-    SASL_CB_USER, &get_username, NULL
-  }, {
-    SASL_CB_AUTHNAME, &get_username, NULL
-  }, {
-    SASL_CB_PASS, &get_password, NULL
-  }, {
-    SASL_CB_LIST_END, NULL, NULL
-  }
-};
-#endif
-
-bool initialize_sasl(memcached_st *memc, char *user, char *password)
-{
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
-  if (user != NULL && password != NULL)
-  {
-    username= user;
-    passwd= password;
-
-    if (sasl_client_init(NULL) != SASL_OK)
-    {
-      fprintf(stderr, "Failed to initialize sasl library!\n");
-      return false;
-    }
-    memcached_set_sasl_callbacks(memc, sasl_callbacks);
-  }
-#else
-  (void)memc;
-  (void)user;
-  (void)password;
-#endif
-
-  return true;
-}
-
-void shutdown_sasl(void)
-{
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
-  if (username != NULL || passwd != NULL)
-    sasl_done();
-#endif
-}
-
-void initialize_sockets(void)
-{
-  /* Define the function for all platforms to avoid #ifdefs in each program */
-#ifdef WIN32
-  WSADATA wsaData;
-  if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0)
-  {
-    fprintf(stderr, "Socket Initialization Error. Program aborted\n");
-    exit(EXIT_FAILURE);
-  }
-#endif
-}
diff --git a/clients/utilities.cc b/clients/utilities.cc
new file mode 100644 (file)
index 0000000..ca109ad
--- /dev/null
@@ -0,0 +1,229 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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:
+ *
+ */
+#include "config.h"
+
+#include <clients/utilities.h>
+#include <cstdio>
+#include <cstring>
+#include <ctype.h>
+
+
+long int timedif(struct timeval a, struct timeval b)
+{
+  long us, s;
+
+  us = (int)(a.tv_usec - b.tv_usec);
+  us /= 1000;
+  s = (int)(a.tv_sec - b.tv_sec);
+  s *= 1000;
+  return s + us;
+}
+
+void version_command(const char *command_name)
+{
+  printf("%s v%u.%u\n", command_name, 1U, 0U);
+  exit(0);
+}
+
+static const char *lookup_help(memcached_options option)
+{
+  switch (option)
+  {
+  case OPT_SERVERS: return("List which servers you wish to connect to.");
+  case OPT_VERSION: return("Display the version of the application and then exit.");
+  case OPT_HELP: return("Display this message and then exit.");
+  case OPT_VERBOSE: return("Give more details on the progression of the application.");
+  case OPT_DEBUG: return("Provide output only useful for debugging.");
+  case OPT_FLAG: return("Provide flag information for storage operation.");
+  case OPT_EXPIRE: return("Set the expire option for the object.");
+  case OPT_SET: return("Use set command with memcached when storing.");
+  case OPT_REPLACE: return("Use replace command with memcached when storing.");
+  case OPT_ADD: return("Use add command with memcached when storing.");
+  case OPT_SLAP_EXECUTE_NUMBER: return("Number of times to execute the given test.");
+  case OPT_SLAP_INITIAL_LOAD: return("Number of key pairs to load before executing tests.");
+  case OPT_SLAP_TEST: return("Test to run (currently \"get\" or \"set\").");
+  case OPT_SLAP_CONCURRENCY: return("Number of users to simulate with load.");
+  case OPT_SLAP_NON_BLOCK: return("Set TCP up to use non-blocking IO.");
+  case OPT_SLAP_TCP_NODELAY: return("Set TCP socket up to use nodelay.");
+  case OPT_FLUSH: return("Flush servers before running tests.");
+  case OPT_HASH: return("Select hash type.");
+  case OPT_BINARY: return("Switch to binary protocol.");
+  case OPT_ANALYZE: return("Analyze the provided servers.");
+  case OPT_UDP: return("Use UDP protocol when communicating with server.");
+  case OPT_USERNAME: return "Username to use for SASL authentication";
+  case OPT_PASSWD: return "Password to use for SASL authentication";
+  case OPT_FILE: return "Path to file in which to save result";
+  case OPT_STAT_ARGS: return "Argument for statistics";
+  default: WATCHPOINT_ASSERT(0);
+  };
+
+  WATCHPOINT_ASSERT(0);
+  return "forgot to document this function :)";
+}
+
+void help_command(const char *command_name, const char *description,
+                  const struct option *long_options,
+                  memcached_programs_help_st *options)
+{
+  unsigned int x;
+  (void)options;
+
+  printf("%s v%u.%u\n\n", command_name, 1U, 0U);
+  printf("\t%s\n\n", description);
+  printf("Current options. A '=' means the option takes a value.\n\n");
+
+  for (x= 0; long_options[x].name; x++)
+  {
+    const char *help_message;
+
+    printf("\t --%s%c\n", long_options[x].name,
+           long_options[x].has_arg ? '=' : ' ');
+    if ((help_message= lookup_help(memcached_options(long_options[x].val))))
+      printf("\t\t%s\n", help_message);
+  }
+
+  printf("\n");
+  exit(0);
+}
+
+void process_hash_option(memcached_st *memc, char *opt_hash)
+{
+  uint64_t set;
+  memcached_return_t rc;
+
+  if (opt_hash == NULL)
+    return;
+
+  set= MEMCACHED_HASH_DEFAULT; /* Just here to solve warning */
+  if (!strcasecmp(opt_hash, "CRC"))
+    set= MEMCACHED_HASH_CRC;
+  else if (!strcasecmp(opt_hash, "FNV1_64"))
+    set= MEMCACHED_HASH_FNV1_64;
+  else if (!strcasecmp(opt_hash, "FNV1A_64"))
+    set= MEMCACHED_HASH_FNV1A_64;
+  else if (!strcasecmp(opt_hash, "FNV1_32"))
+    set= MEMCACHED_HASH_FNV1_32;
+  else if (!strcasecmp(opt_hash, "FNV1A_32"))
+    set= MEMCACHED_HASH_FNV1A_32;
+  else
+  {
+    fprintf(stderr, "hash: type not recognized %s\n", opt_hash);
+    exit(1);
+  }
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    fprintf(stderr, "hash: memcache error %s\n", memcached_strerror(memc, rc));
+    exit(1);
+  }
+}
+
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+static char *username;
+static char *passwd;
+
+static int get_username(void *context, int id, const char **result, unsigned int *len)
+{
+  (void)context;
+  if (!result || (id != SASL_CB_USER && id != SASL_CB_AUTHNAME))
+    return SASL_BADPARAM;
+
+  *result= username;
+  if (len)
+     *len= (username == NULL) ? 0 : (unsigned int)strlen(username);
+
+  return SASL_OK;
+}
+
+static int get_password(sasl_conn_t *conn, void *context, int id,
+                        sasl_secret_t **psecret)
+{
+  (void)context;
+  static sasl_secret_t* ptr;
+
+  if (!conn || ! psecret || id != SASL_CB_PASS)
+    return SASL_BADPARAM;
+
+  if (passwd == NULL)
+  {
+     *psecret= NULL;
+     return SASL_OK;
+  }
+
+  size_t len= strlen(passwd);
+  ptr= (sasl_secret_t *)malloc(sizeof(sasl_secret_t) + len +1);
+  if (not ptr)
+    return SASL_NOMEM;
+
+  ptr->len= len;
+  memcpy(ptr->data, passwd, len);
+  ptr->data[len]= 0;
+
+  *psecret= ptr;
+  return SASL_OK;
+}
+
+typedef int (*local_sasl_fn)(void);
+
+/* callbacks we support */
+static sasl_callback_t sasl_callbacks[] = {
+  { SASL_CB_USER, (local_sasl_fn)get_username, NULL },
+  { SASL_CB_AUTHNAME, (local_sasl_fn)get_username, NULL },
+  { SASL_CB_PASS, (local_sasl_fn)get_password, NULL },
+  { SASL_CB_LIST_END, NULL, NULL }
+};
+#endif
+
+bool initialize_sasl(memcached_st *memc, char *user, char *password)
+{
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+  if (user != NULL && password != NULL)
+  {
+    username= user;
+    passwd= password;
+
+    if (sasl_client_init(NULL) != SASL_OK)
+    {
+      fprintf(stderr, "Failed to initialize sasl library!\n");
+      return false;
+    }
+    memcached_set_sasl_callbacks(memc, sasl_callbacks);
+  }
+#else
+  (void)memc;
+  (void)user;
+  (void)password;
+#endif
+
+  return true;
+}
+
+void shutdown_sasl(void)
+{
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+  if (username != NULL || passwd != NULL)
+    sasl_done();
+#endif
+}
+
+void initialize_sockets(void)
+{
+  /* Define the function for all platforms to avoid #ifdefs in each program */
+#ifdef WIN32
+  WSADATA wsaData;
+  if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0)
+  {
+    fprintf(stderr, "Socket Initialization Error. Program aborted\n");
+    exit(EXIT_FAILURE);
+  }
+#endif
+}
index a998773b97f9342e2a3ba2f4dfc757b3082fc0be..685be6a5443d07d693ff3b1c5f6838b72446791f 100644 (file)
@@ -9,6 +9,8 @@
  *
  */
 
+#pragma once
+
 #include <getopt.h>
 #include <libmemcached/memcached.h>
 #include "libmemcached/watchpoint.h"
@@ -41,6 +43,10 @@ struct memcached_programs_help_st
   char *not_used_yet;
 };
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 char *strdup_cleanup(const char *str);
 void cleanup(void);
 long int timedif(struct timeval a, struct timeval b);
@@ -52,3 +58,7 @@ void process_hash_option(memcached_st *memc, char *opt_hash);
 bool initialize_sasl(memcached_st *memc, char *user, char *password);
 void shutdown_sasl(void);
 void initialize_sockets(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
index ea9933587fee89f5bd190bae298344b28d4f36df..9b8a82c581c3a0241ed5b3403eb008430a198cfc 100644 (file)
@@ -9,7 +9,7 @@
 
 AC_PREREQ(2.59)
 AC_INIT([libmemcached],[0.49],[http://libmemcached.org/])
-AC_CONFIG_SRCDIR([libmemcached/memcached.c])
+AC_CONFIG_SRCDIR([libmemcached/memcached.cc])
 AC_CONFIG_AUX_DIR(config)
 
 PANDORA_CANONICAL_TARGET(no-vc-changelog)
index ae9bae936c699435a7d1cf053358c2f4010ade79..561eebc8d7f2a249f3b65f7de813e62828ce3b61 100644 (file)
@@ -10,16 +10,13 @@ example_memcached_light_SOURCES= \
                                 example/interface_v0.c \
                                 example/interface_v1.c \
                                 example/memcached_light.c \
+                                libmemcached/byteorder.cc \
                                 example/memcached_light.h \
                                 example/storage.h
 
 example_memcached_light_LDADD= libmemcached/libmemcachedprotocol.la \
                                $(LIBINNODB) $(LTLIBEVENT)
 
-if BUILD_BYTEORDER
-example_memcached_light_LDADD+= libmemcached/libbyteorder.la
-endif
-
 if HAVE_LIBINNODB
 example_memcached_light_SOURCES+= example/storage_innodb.c
 else
diff --git a/libhashkit/algorithm.c b/libhashkit/algorithm.c
deleted file mode 100644 (file)
index de00081..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/* HashKit
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-
-uint32_t libhashkit_one_at_a_time(const char *key, size_t key_length)
-{
-  return hashkit_one_at_a_time(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1_64(const char *key, size_t key_length)
-{
-  return hashkit_fnv1_64(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1a_64(const char *key, size_t key_length)
-{
-  return hashkit_fnv1a_64(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1_32(const char *key, size_t key_length)
-{
-  return hashkit_fnv1_32(key, key_length, NULL);
-}
-
-uint32_t libhashkit_fnv1a_32(const char *key, size_t key_length)
-{
-  return hashkit_fnv1a_32(key, key_length, NULL);
-}
-
-uint32_t libhashkit_crc32(const char *key, size_t key_length)
-{
-  return hashkit_crc32(key, key_length, NULL);
-}
-
-#ifdef HAVE_HSIEH_HASH
-uint32_t libhashkit_hsieh(const char *key, size_t key_length)
-{
-  return hashkit_hsieh(key, key_length, NULL);
-}
-#endif
-
-#ifdef HAVE_MURMUR_HASH
-uint32_t libhashkit_murmur(const char *key, size_t key_length)
-{
-  return hashkit_murmur(key, key_length, NULL);
-}
-#endif
-
-uint32_t libhashkit_jenkins(const char *key, size_t key_length)
-{
-  return hashkit_jenkins(key, key_length, NULL);
-}
-
-uint32_t libhashkit_md5(const char *key, size_t key_length)
-{
-  return hashkit_md5(key, key_length, NULL);
-}
-
-void libhashkit_md5_signature(const unsigned char *key, size_t length, unsigned char *result)
-{
-  md5_signature(key, (uint32_t)length, result);
-}
-
diff --git a/libhashkit/algorithm.cc b/libhashkit/algorithm.cc
new file mode 100644 (file)
index 0000000..de00081
--- /dev/null
@@ -0,0 +1,69 @@
+/* HashKit
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+
+uint32_t libhashkit_one_at_a_time(const char *key, size_t key_length)
+{
+  return hashkit_one_at_a_time(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1_64(const char *key, size_t key_length)
+{
+  return hashkit_fnv1_64(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1a_64(const char *key, size_t key_length)
+{
+  return hashkit_fnv1a_64(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1_32(const char *key, size_t key_length)
+{
+  return hashkit_fnv1_32(key, key_length, NULL);
+}
+
+uint32_t libhashkit_fnv1a_32(const char *key, size_t key_length)
+{
+  return hashkit_fnv1a_32(key, key_length, NULL);
+}
+
+uint32_t libhashkit_crc32(const char *key, size_t key_length)
+{
+  return hashkit_crc32(key, key_length, NULL);
+}
+
+#ifdef HAVE_HSIEH_HASH
+uint32_t libhashkit_hsieh(const char *key, size_t key_length)
+{
+  return hashkit_hsieh(key, key_length, NULL);
+}
+#endif
+
+#ifdef HAVE_MURMUR_HASH
+uint32_t libhashkit_murmur(const char *key, size_t key_length)
+{
+  return hashkit_murmur(key, key_length, NULL);
+}
+#endif
+
+uint32_t libhashkit_jenkins(const char *key, size_t key_length)
+{
+  return hashkit_jenkins(key, key_length, NULL);
+}
+
+uint32_t libhashkit_md5(const char *key, size_t key_length)
+{
+  return hashkit_md5(key, key_length, NULL);
+}
+
+void libhashkit_md5_signature(const unsigned char *key, size_t length, unsigned char *result)
+{
+  md5_signature(key, (uint32_t)length, result);
+}
+
diff --git a/libhashkit/behavior.c b/libhashkit/behavior.c
deleted file mode 100644 (file)
index ee0efcf..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* HashKit
- * Copyright (C) 2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
diff --git a/libhashkit/behavior.cc b/libhashkit/behavior.cc
new file mode 100644 (file)
index 0000000..ee0efcf
--- /dev/null
@@ -0,0 +1,9 @@
+/* HashKit
+ * Copyright (C) 2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
index 73b198f589aa05c5ce640c9e5b6377b00125e206..5cf8b9f53e47cad78724be2180257fcf173ab2d0 100644 (file)
@@ -6,8 +6,7 @@
  * the COPYING file in the parent directory for full text.
  */
 
-#ifndef HASHKIT_COMMON_H
-#define HASHKIT_COMMON_H
+#pragma once
 
 #include <config.h>
 
@@ -32,5 +31,3 @@ int update_continuum(hashkit_st *hashkit);
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* HASHKIT_COMMON_H */
diff --git a/libhashkit/crc32.c b/libhashkit/crc32.c
deleted file mode 100644 (file)
index f07958c..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/* The crc32 functions and data was originally written by Spencer
- * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source
- * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at
- * src/usr.bin/cksum/crc32.c.
- */
-
-#include <libhashkit/common.h>
-
-static const uint32_t crc32tab[256] = {
-  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
-  0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
-  0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
-  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
-  0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
-  0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
-  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
-  0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
-  0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
-  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
-  0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
-  0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
-  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
-  0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
-  0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
-  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
-  0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
-  0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
-  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
-  0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
-  0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
-  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
-  0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
-  0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
-  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
-  0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
-  0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
-  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
-  0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
-  0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
-  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
-  0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
-  0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
-  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
-  0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
-  0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
-  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
-  0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
-  0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
-  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
-  0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
-  0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
-  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
-  0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
-  0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
-  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
-  0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
-  0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
-  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
-  0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
-  0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
-  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
-  0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
-  0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
-  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
-  0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
-  0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
-  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
-  0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
-  0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
-  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
-  0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
-  0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
-  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
-};
-
-uint32_t hashkit_crc32(const char *key, size_t key_length, void *context)
-{
-  uint64_t x;
-  uint32_t crc= UINT32_MAX;
-  (void)context;
-
-  for (x= 0; x < key_length; x++)
-     crc= (crc >> 8) ^ crc32tab[(crc ^ (uint64_t)key[x]) & 0xff];
-
-  return ((~crc) >> 16) & 0x7fff;
-}
diff --git a/libhashkit/crc32.cc b/libhashkit/crc32.cc
new file mode 100644 (file)
index 0000000..f07958c
--- /dev/null
@@ -0,0 +1,86 @@
+/* The crc32 functions and data was originally written by Spencer
+ * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source
+ * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at
+ * src/usr.bin/cksum/crc32.c.
+ */
+
+#include <libhashkit/common.h>
+
+static const uint32_t crc32tab[256] = {
+  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+  0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+  0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+  0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+  0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+  0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+  0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+  0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+  0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+  0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+  0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+  0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+  0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+  0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+  0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+  0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+  0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+  0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+  0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+  0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+  0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+  0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+  0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+  0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+  0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+  0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+  0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+  0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+  0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+  0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+  0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+  0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+  0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+  0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+  0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+  0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+  0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+  0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+  0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+  0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+  0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+  0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+  0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+uint32_t hashkit_crc32(const char *key, size_t key_length, void *context)
+{
+  uint64_t x;
+  uint32_t crc= UINT32_MAX;
+  (void)context;
+
+  for (x= 0; x < key_length; x++)
+     crc= (crc >> 8) ^ crc32tab[(crc ^ (uint64_t)key[x]) & 0xff];
+
+  return ((~crc) >> 16) & 0x7fff;
+}
diff --git a/libhashkit/digest.c b/libhashkit/digest.c
deleted file mode 100644 (file)
index e155981..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/* HashKit
- * 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.
- */
-
-#include <libhashkit/common.h>
-
-uint32_t hashkit_digest(const hashkit_st *self, const char *key, size_t key_length)
-{
-  return self->base_hash.function(key, key_length, self->base_hash.context);
-}
-
-uint32_t libhashkit_digest(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm)
-{
-  switch (hash_algorithm)
-  {
-  case HASHKIT_HASH_DEFAULT:
-    return libhashkit_one_at_a_time(key, key_length);
-  case HASHKIT_HASH_MD5:
-    return libhashkit_md5(key, key_length);
-  case HASHKIT_HASH_CRC:
-    return libhashkit_crc32(key, key_length);
-  case HASHKIT_HASH_FNV1_64:
-    return libhashkit_fnv1_64(key, key_length);
-  case HASHKIT_HASH_FNV1A_64:
-    return libhashkit_fnv1a_64(key, key_length);
-  case HASHKIT_HASH_FNV1_32:
-    return libhashkit_fnv1_32(key, key_length);
-  case HASHKIT_HASH_FNV1A_32:
-    return libhashkit_fnv1a_32(key, key_length);
-  case HASHKIT_HASH_HSIEH:
-#ifdef HAVE_HSIEH_HASH
-    return libhashkit_hsieh(key, key_length);
-#else
-    return 1;
-#endif
-  case HASHKIT_HASH_MURMUR:
-#ifdef HAVE_MURMUR_HASH
-    return libhashkit_murmur(key, key_length);
-#else
-    return 1;
-#endif
-  case HASHKIT_HASH_JENKINS:
-    return libhashkit_jenkins(key, key_length);
-  case HASHKIT_HASH_CUSTOM:
-  case HASHKIT_HASH_MAX:
-  default:
-#ifdef HAVE_DEBUG
-    fprintf(stderr, "hashkit_hash_t was extended but libhashkit_generate_value was not updated\n");
-    fflush(stderr);
-    assert(0);
-#endif
-    break;
-  }
-
-  return 1;
-}
diff --git a/libhashkit/digest.cc b/libhashkit/digest.cc
new file mode 100644 (file)
index 0000000..e155981
--- /dev/null
@@ -0,0 +1,60 @@
+/* HashKit
+ * 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.
+ */
+
+#include <libhashkit/common.h>
+
+uint32_t hashkit_digest(const hashkit_st *self, const char *key, size_t key_length)
+{
+  return self->base_hash.function(key, key_length, self->base_hash.context);
+}
+
+uint32_t libhashkit_digest(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm)
+{
+  switch (hash_algorithm)
+  {
+  case HASHKIT_HASH_DEFAULT:
+    return libhashkit_one_at_a_time(key, key_length);
+  case HASHKIT_HASH_MD5:
+    return libhashkit_md5(key, key_length);
+  case HASHKIT_HASH_CRC:
+    return libhashkit_crc32(key, key_length);
+  case HASHKIT_HASH_FNV1_64:
+    return libhashkit_fnv1_64(key, key_length);
+  case HASHKIT_HASH_FNV1A_64:
+    return libhashkit_fnv1a_64(key, key_length);
+  case HASHKIT_HASH_FNV1_32:
+    return libhashkit_fnv1_32(key, key_length);
+  case HASHKIT_HASH_FNV1A_32:
+    return libhashkit_fnv1a_32(key, key_length);
+  case HASHKIT_HASH_HSIEH:
+#ifdef HAVE_HSIEH_HASH
+    return libhashkit_hsieh(key, key_length);
+#else
+    return 1;
+#endif
+  case HASHKIT_HASH_MURMUR:
+#ifdef HAVE_MURMUR_HASH
+    return libhashkit_murmur(key, key_length);
+#else
+    return 1;
+#endif
+  case HASHKIT_HASH_JENKINS:
+    return libhashkit_jenkins(key, key_length);
+  case HASHKIT_HASH_CUSTOM:
+  case HASHKIT_HASH_MAX:
+  default:
+#ifdef HAVE_DEBUG
+    fprintf(stderr, "hashkit_hash_t was extended but libhashkit_generate_value was not updated\n");
+    fflush(stderr);
+    assert(0);
+#endif
+    break;
+  }
+
+  return 1;
+}
diff --git a/libhashkit/fnv.c b/libhashkit/fnv.c
deleted file mode 100644 (file)
index fffb94a..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* HashKit
- * Copyright (C) 2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-
-/* FNV hash'es lifted from Dustin Sallings work */
-static uint64_t FNV_64_INIT= UINT64_C(0xcbf29ce484222325);
-static uint64_t FNV_64_PRIME= UINT64_C(0x100000001b3);
-static uint32_t FNV_32_INIT= 2166136261UL;
-static uint32_t FNV_32_PRIME= 16777619;
-
-uint32_t hashkit_fnv1_64(const char *key, size_t key_length, void *context)
-{
-  /* Thanks to pierre@demartines.com for the pointer */
-  uint64_t hash= FNV_64_INIT;
-  (void)context;
-
-  for (size_t x= 0; x < key_length; x++)
-  {
-    hash *= FNV_64_PRIME;
-    hash ^= (uint64_t)key[x];
-  }
-
-  return (uint32_t)hash;
-}
-
-uint32_t hashkit_fnv1a_64(const char *key, size_t key_length, void *context)
-{
-  uint32_t hash= (uint32_t) FNV_64_INIT;
-  (void)context;
-
-  for (size_t x= 0; x < key_length; x++)
-  {
-    uint32_t val= (uint32_t)key[x];
-    hash ^= val;
-    hash *= (uint32_t) FNV_64_PRIME;
-  }
-
-  return hash;
-}
-
-uint32_t hashkit_fnv1_32(const char *key, size_t key_length, void *context)
-{
-  uint32_t hash= FNV_32_INIT;
-  (void)context;
-
-  for (size_t x= 0; x < key_length; x++)
-  {
-    uint32_t val= (uint32_t)key[x];
-    hash *= FNV_32_PRIME;
-    hash ^= val;
-  }
-
-  return hash;
-}
-
-uint32_t hashkit_fnv1a_32(const char *key, size_t key_length, void *context)
-{
-  uint32_t hash= FNV_32_INIT;
-  (void)context;
-
-  for (size_t x= 0; x < key_length; x++)
-  {
-    uint32_t val= (uint32_t)key[x];
-    hash ^= val;
-    hash *= FNV_32_PRIME;
-  }
-
-  return hash;
-}
diff --git a/libhashkit/fnv.cc b/libhashkit/fnv.cc
new file mode 100644 (file)
index 0000000..fffb94a
--- /dev/null
@@ -0,0 +1,75 @@
+/* HashKit
+ * Copyright (C) 2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+
+/* FNV hash'es lifted from Dustin Sallings work */
+static uint64_t FNV_64_INIT= UINT64_C(0xcbf29ce484222325);
+static uint64_t FNV_64_PRIME= UINT64_C(0x100000001b3);
+static uint32_t FNV_32_INIT= 2166136261UL;
+static uint32_t FNV_32_PRIME= 16777619;
+
+uint32_t hashkit_fnv1_64(const char *key, size_t key_length, void *context)
+{
+  /* Thanks to pierre@demartines.com for the pointer */
+  uint64_t hash= FNV_64_INIT;
+  (void)context;
+
+  for (size_t x= 0; x < key_length; x++)
+  {
+    hash *= FNV_64_PRIME;
+    hash ^= (uint64_t)key[x];
+  }
+
+  return (uint32_t)hash;
+}
+
+uint32_t hashkit_fnv1a_64(const char *key, size_t key_length, void *context)
+{
+  uint32_t hash= (uint32_t) FNV_64_INIT;
+  (void)context;
+
+  for (size_t x= 0; x < key_length; x++)
+  {
+    uint32_t val= (uint32_t)key[x];
+    hash ^= val;
+    hash *= (uint32_t) FNV_64_PRIME;
+  }
+
+  return hash;
+}
+
+uint32_t hashkit_fnv1_32(const char *key, size_t key_length, void *context)
+{
+  uint32_t hash= FNV_32_INIT;
+  (void)context;
+
+  for (size_t x= 0; x < key_length; x++)
+  {
+    uint32_t val= (uint32_t)key[x];
+    hash *= FNV_32_PRIME;
+    hash ^= val;
+  }
+
+  return hash;
+}
+
+uint32_t hashkit_fnv1a_32(const char *key, size_t key_length, void *context)
+{
+  uint32_t hash= FNV_32_INIT;
+  (void)context;
+
+  for (size_t x= 0; x < key_length; x++)
+  {
+    uint32_t val= (uint32_t)key[x];
+    hash ^= val;
+    hash *= FNV_32_PRIME;
+  }
+
+  return hash;
+}
diff --git a/libhashkit/function.c b/libhashkit/function.c
deleted file mode 100644 (file)
index 3560abd..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/* HashKit
- * 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.
- */
-
-#include <libhashkit/common.h>
-
-static hashkit_return_t _set_function(struct hashkit_function_st *self, hashkit_hash_algorithm_t hash_algorithm)
-{
-  switch (hash_algorithm)
-  {
-  case HASHKIT_HASH_DEFAULT:
-    self->function= hashkit_one_at_a_time;
-    break;
-  case HASHKIT_HASH_MD5:
-    self->function= hashkit_md5;
-    break;
-  case HASHKIT_HASH_CRC:
-    self->function= hashkit_crc32;
-    break;
-  case HASHKIT_HASH_FNV1_64:
-    self->function= hashkit_fnv1_64;
-    break;
-  case HASHKIT_HASH_FNV1A_64:
-    self->function= hashkit_fnv1a_64;
-    break;
-  case HASHKIT_HASH_FNV1_32:
-    self->function= hashkit_fnv1_32;
-    break;
-  case HASHKIT_HASH_FNV1A_32:
-    self->function= hashkit_fnv1a_32;
-    break;
-  case HASHKIT_HASH_HSIEH:
-#ifdef HAVE_HSIEH_HASH
-    self->function= hashkit_hsieh;
-    break;    
-#else
-    return HASHKIT_FAILURE;
-#endif
-  case HASHKIT_HASH_MURMUR:
-#ifdef HAVE_MURMUR_HASH
-    self->function= hashkit_murmur;
-    break;    
-#else
-    return HASHKIT_FAILURE;
-#endif
-  case HASHKIT_HASH_JENKINS:
-    self->function= hashkit_jenkins;
-    break;    
-  case HASHKIT_HASH_CUSTOM:
-    return HASHKIT_INVALID_ARGUMENT;
-  case HASHKIT_HASH_MAX:
-  default:
-    return HASHKIT_INVALID_HASH;
-  }
-
-  self->context= NULL;
-
-  return HASHKIT_SUCCESS;
-}
-
-hashkit_return_t hashkit_set_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm)
-{
-  return _set_function(&self->base_hash, hash_algorithm);
-}
-
-hashkit_return_t hashkit_set_distribution_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm)
-{
-  return _set_function(&self->distribution_hash, hash_algorithm);
-}
-
-static hashkit_return_t _set_custom_function(struct hashkit_function_st *self, hashkit_hash_fn function, void *context)
-{
-  if (function)
-  {
-    self->function= function;
-    self->context= context;
-
-    return HASHKIT_SUCCESS;
-  }
-
-  return HASHKIT_FAILURE;
-}
-
-hashkit_return_t hashkit_set_custom_function(hashkit_st *self, hashkit_hash_fn function, void *context)
-{
-  return _set_custom_function(&self->base_hash, function, context);
-}
-
-hashkit_return_t hashkit_set_custom_distribution_function(hashkit_st *self, hashkit_hash_fn function, void *context)
-{
-  return _set_custom_function(&self->distribution_hash, function, context);
-}
-
-static hashkit_hash_algorithm_t get_function_type(const hashkit_hash_fn function)
-{
-  if (function == hashkit_one_at_a_time)
-  {
-    return HASHKIT_HASH_DEFAULT;
-  }
-  else if (function == hashkit_md5)
-  {
-    return HASHKIT_HASH_MD5;
-  }
-  else if (function == hashkit_crc32)
-  {
-    return HASHKIT_HASH_CRC;
-  }
-  else if (function == hashkit_fnv1_64)
-  {
-    return HASHKIT_HASH_FNV1_64;
-  }
-  else if (function == hashkit_fnv1a_64)
-  {
-    return HASHKIT_HASH_FNV1A_64;
-  }
-  else if (function == hashkit_fnv1_32)
-  {
-    return HASHKIT_HASH_FNV1_32;
-  }
-  else if (function == hashkit_fnv1a_32)
-  {
-    return HASHKIT_HASH_FNV1A_32;
-  }
-#ifdef HAVE_HSIEH_HASH
-  else if (function == hashkit_hsieh)
-  {
-    return HASHKIT_HASH_HSIEH;
-  }
-#endif
-#ifdef HAVE_MURMUR_HASH
-  else if (function == hashkit_murmur)
-  {
-    return HASHKIT_HASH_MURMUR;
-  }
-#endif
-  else if (function == hashkit_jenkins)
-  {
-    return HASHKIT_HASH_JENKINS;
-  }
-
-  return HASHKIT_HASH_CUSTOM;
-}
-
-hashkit_hash_algorithm_t hashkit_get_function(const hashkit_st *self)
-{
-  return get_function_type(self->base_hash.function);
-}
-
-hashkit_hash_algorithm_t hashkit_get_distribution_function(const hashkit_st *self)
-{
-  return get_function_type(self->distribution_hash.function);
-}
diff --git a/libhashkit/function.cc b/libhashkit/function.cc
new file mode 100644 (file)
index 0000000..7ac9100
--- /dev/null
@@ -0,0 +1,156 @@
+/* HashKit
+ * 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.
+ */
+
+#include <libhashkit/common.h>
+
+static hashkit_return_t _set_function(struct hashkit_st::hashkit_function_st *self, hashkit_hash_algorithm_t hash_algorithm)
+{
+  switch (hash_algorithm)
+  {
+  case HASHKIT_HASH_DEFAULT:
+    self->function= hashkit_one_at_a_time;
+    break;
+  case HASHKIT_HASH_MD5:
+    self->function= hashkit_md5;
+    break;
+  case HASHKIT_HASH_CRC:
+    self->function= hashkit_crc32;
+    break;
+  case HASHKIT_HASH_FNV1_64:
+    self->function= hashkit_fnv1_64;
+    break;
+  case HASHKIT_HASH_FNV1A_64:
+    self->function= hashkit_fnv1a_64;
+    break;
+  case HASHKIT_HASH_FNV1_32:
+    self->function= hashkit_fnv1_32;
+    break;
+  case HASHKIT_HASH_FNV1A_32:
+    self->function= hashkit_fnv1a_32;
+    break;
+  case HASHKIT_HASH_HSIEH:
+#ifdef HAVE_HSIEH_HASH
+    self->function= hashkit_hsieh;
+    break;    
+#else
+    return HASHKIT_FAILURE;
+#endif
+  case HASHKIT_HASH_MURMUR:
+#ifdef HAVE_MURMUR_HASH
+    self->function= hashkit_murmur;
+    break;    
+#else
+    return HASHKIT_FAILURE;
+#endif
+  case HASHKIT_HASH_JENKINS:
+    self->function= hashkit_jenkins;
+    break;    
+  case HASHKIT_HASH_CUSTOM:
+    return HASHKIT_INVALID_ARGUMENT;
+  case HASHKIT_HASH_MAX:
+  default:
+    return HASHKIT_INVALID_HASH;
+  }
+
+  self->context= NULL;
+
+  return HASHKIT_SUCCESS;
+}
+
+hashkit_return_t hashkit_set_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm)
+{
+  return _set_function(&self->base_hash, hash_algorithm);
+}
+
+hashkit_return_t hashkit_set_distribution_function(hashkit_st *self, hashkit_hash_algorithm_t hash_algorithm)
+{
+  return _set_function(&self->distribution_hash, hash_algorithm);
+}
+
+static hashkit_return_t _set_custom_function(struct hashkit_st::hashkit_function_st *self, hashkit_hash_fn function, void *context)
+{
+  if (function)
+  {
+    self->function= function;
+    self->context= context;
+
+    return HASHKIT_SUCCESS;
+  }
+
+  return HASHKIT_FAILURE;
+}
+
+hashkit_return_t hashkit_set_custom_function(hashkit_st *self, hashkit_hash_fn function, void *context)
+{
+  return _set_custom_function(&self->base_hash, function, context);
+}
+
+hashkit_return_t hashkit_set_custom_distribution_function(hashkit_st *self, hashkit_hash_fn function, void *context)
+{
+  return _set_custom_function(&self->distribution_hash, function, context);
+}
+
+static hashkit_hash_algorithm_t get_function_type(const hashkit_hash_fn function)
+{
+  if (function == hashkit_one_at_a_time)
+  {
+    return HASHKIT_HASH_DEFAULT;
+  }
+  else if (function == hashkit_md5)
+  {
+    return HASHKIT_HASH_MD5;
+  }
+  else if (function == hashkit_crc32)
+  {
+    return HASHKIT_HASH_CRC;
+  }
+  else if (function == hashkit_fnv1_64)
+  {
+    return HASHKIT_HASH_FNV1_64;
+  }
+  else if (function == hashkit_fnv1a_64)
+  {
+    return HASHKIT_HASH_FNV1A_64;
+  }
+  else if (function == hashkit_fnv1_32)
+  {
+    return HASHKIT_HASH_FNV1_32;
+  }
+  else if (function == hashkit_fnv1a_32)
+  {
+    return HASHKIT_HASH_FNV1A_32;
+  }
+#ifdef HAVE_HSIEH_HASH
+  else if (function == hashkit_hsieh)
+  {
+    return HASHKIT_HASH_HSIEH;
+  }
+#endif
+#ifdef HAVE_MURMUR_HASH
+  else if (function == hashkit_murmur)
+  {
+    return HASHKIT_HASH_MURMUR;
+  }
+#endif
+  else if (function == hashkit_jenkins)
+  {
+    return HASHKIT_HASH_JENKINS;
+  }
+
+  return HASHKIT_HASH_CUSTOM;
+}
+
+hashkit_hash_algorithm_t hashkit_get_function(const hashkit_st *self)
+{
+  return get_function_type(self->base_hash.function);
+}
+
+hashkit_hash_algorithm_t hashkit_get_distribution_function(const hashkit_st *self)
+{
+  return get_function_type(self->distribution_hash.function);
+}
diff --git a/libhashkit/hashkit.c b/libhashkit/hashkit.c
deleted file mode 100644 (file)
index 7214c14..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/* HashKit
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-
-static const hashkit_st global_default_hash= {
-  .base_hash= {
-    .function= hashkit_one_at_a_time,
-    .context= NULL
-  },
-  .flags= {
-    .is_base_same_distributed= false,
-  }
-};
-
-static inline bool _hashkit_init(hashkit_st *self)
-{
-  self->base_hash= global_default_hash.base_hash;
-  self->distribution_hash= global_default_hash.base_hash;
-  self->flags= global_default_hash.flags;
-
-  return true;
-}
-
-static inline hashkit_st *_hashkit_create(hashkit_st *self)
-{
-  if (self == NULL)
-  {
-    self= (hashkit_st *)malloc(sizeof(hashkit_st));
-    if (self == NULL)
-    {
-      return NULL;
-    }
-
-    self->options.is_allocated= true;
-  }
-  else
-  {
-    self->options.is_allocated= false;
-  }
-
-  return self;
-}
-
-hashkit_st *hashkit_create(hashkit_st *self)
-{
-  self= _hashkit_create(self);
-  if (! self)
-    return self;
-
-  if (! _hashkit_init(self))
-  {
-    hashkit_free(self);
-  }
-
-  return self;
-}
-
-
-void hashkit_free(hashkit_st *self)
-{
-  if (hashkit_is_allocated(self))
-  {
-    free(self);
-  }
-}
-
-hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source)
-{
-  if (source == NULL)
-  {
-    return hashkit_create(destination);
-  }
-
-  /* new_clone will be a pointer to destination */ 
-  destination= _hashkit_create(destination);
-
-  // Should only happen on allocation failure.
-  if (destination == NULL)
-  {
-    return NULL;
-  }
-
-  destination->base_hash= source->base_hash;
-  destination->distribution_hash= source->distribution_hash;
-  destination->flags= source->flags;
-
-  return destination;
-}
-
-bool hashkit_compare(const hashkit_st *first, const hashkit_st *second)
-{
-  if (first->base_hash.function == second->base_hash.function &&
-      first->base_hash.context == second->base_hash.context &&
-      first->distribution_hash.function == second->distribution_hash.function &&
-      first->distribution_hash.context == second->distribution_hash.context &&
-      first->flags.is_base_same_distributed == second->flags.is_base_same_distributed)
-  {
-    return true;
-  }
-
-  return false;
-}
diff --git a/libhashkit/hashkit.cc b/libhashkit/hashkit.cc
new file mode 100644 (file)
index 0000000..201a6df
--- /dev/null
@@ -0,0 +1,99 @@
+/* HashKit
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+
+static inline bool _hashkit_init(hashkit_st *self)
+{
+  self->base_hash.function= hashkit_one_at_a_time;
+  self->base_hash.context= NULL;
+  self->distribution_hash.function= self->base_hash.function;
+  self->flags.is_base_same_distributed= false;
+
+  return true;
+}
+
+static inline hashkit_st *_hashkit_create(hashkit_st *self)
+{
+  if (self == NULL)
+  {
+    self= (hashkit_st *)malloc(sizeof(hashkit_st));
+    if (self == NULL)
+    {
+      return NULL;
+    }
+
+    self->options.is_allocated= true;
+  }
+  else
+  {
+    self->options.is_allocated= false;
+  }
+
+  return self;
+}
+
+hashkit_st *hashkit_create(hashkit_st *self)
+{
+  self= _hashkit_create(self);
+  if (! self)
+    return self;
+
+  if (! _hashkit_init(self))
+  {
+    hashkit_free(self);
+  }
+
+  return self;
+}
+
+
+void hashkit_free(hashkit_st *self)
+{
+  if (hashkit_is_allocated(self))
+  {
+    free(self);
+  }
+}
+
+hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source)
+{
+  if (source == NULL)
+  {
+    return hashkit_create(destination);
+  }
+
+  /* new_clone will be a pointer to destination */ 
+  destination= _hashkit_create(destination);
+
+  // Should only happen on allocation failure.
+  if (destination == NULL)
+  {
+    return NULL;
+  }
+
+  destination->base_hash= source->base_hash;
+  destination->distribution_hash= source->distribution_hash;
+  destination->flags= source->flags;
+
+  return destination;
+}
+
+bool hashkit_compare(const hashkit_st *first, const hashkit_st *second)
+{
+  if (first->base_hash.function == second->base_hash.function &&
+      first->base_hash.context == second->base_hash.context &&
+      first->distribution_hash.function == second->distribution_hash.function &&
+      first->distribution_hash.context == second->distribution_hash.context &&
+      first->flags.is_base_same_distributed == second->flags.is_base_same_distributed)
+  {
+    return true;
+  }
+
+  return false;
+}
index 2d8ad3a2d38aafdaa66737a29921227b96deedc7..9b8761f1c32a53777c882d82a6de16a3f59e304b 100644 (file)
@@ -1,13 +1,42 @@
-/* HashKit
- * Copyright (C) 2009-2010 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  HashKit library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2009-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.
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
  */
 
-#ifndef HASHKIT_H
-#define HASHKIT_H
+
+#pragma once
 
 
 #if !defined(__cplusplus)
@@ -15,6 +44,7 @@
 #endif
 #include <inttypes.h>
 #include <sys/types.h>
+
 #include <libhashkit/visibility.h>
 #include <libhashkit/configure.h>
 #include <libhashkit/types.h>
 #include <libhashkit/str_algorithm.h>
 #include <libhashkit/strerror.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-HASHKIT_API
-hashkit_st *hashkit_create(hashkit_st *hash);
-
-HASHKIT_API
-hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr);
-
-HASHKIT_API
-bool hashkit_compare(const hashkit_st *first, const hashkit_st *second);
-
-HASHKIT_API
-void hashkit_free(hashkit_st *hash);
-
-#define hashkit_is_allocated(__object) ((__object)->options.is_allocated)
-#define hashkit_is_initialized(__object) ((__object)->options.is_initialized)
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
 struct hashkit_st
 {
   struct hashkit_function_st {
@@ -65,65 +72,24 @@ struct hashkit_st
 };
 
 #ifdef __cplusplus
+extern "C" {
+#endif
 
-#include <string>
-
-class Hashkit {
-
-public:
-
-  Hashkit()
-  {
-    hashkit_create(&self);
-  }
-
-  Hashkit(const Hashkit& source)
-  {
-    hashkit_clone(&self, &source.self);
-  }
-
-  Hashkit& operator=(const Hashkit& source)
-  {
-    hashkit_free(&self);
-    hashkit_clone(&self, &source.self);
-
-    return *this;
-  }
-
-  friend bool operator==(const Hashkit &left, const Hashkit &right)
-  {
-    return hashkit_compare(&left.self, &right.self);
-  }
-
-  uint32_t digest(std::string& str)
-  {
-    return hashkit_digest(&self, str.c_str(), str.length());
-  }
+HASHKIT_API
+hashkit_st *hashkit_create(hashkit_st *hash);
 
-  uint32_t digest(const char *key, size_t key_length)
-  {
-    return hashkit_digest(&self, key, key_length);
-  }
+HASHKIT_API
+hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr);
 
-  hashkit_return_t set_function(hashkit_hash_algorithm_t hash_algorithm)
-  {
-    return hashkit_set_function(&self, hash_algorithm);
-  }
+HASHKIT_API
+bool hashkit_compare(const hashkit_st *first, const hashkit_st *second);
 
-  hashkit_return_t set_distribution_function(hashkit_hash_algorithm_t hash_algorithm)
-  {
-    return hashkit_set_function(&self, hash_algorithm);
-  }
+HASHKIT_API
+void hashkit_free(hashkit_st *hash);
 
-  ~Hashkit()
-  {
-    hashkit_free(&self);
-  }
-private:
+#define hashkit_is_allocated(__object) ((__object)->options.is_allocated)
+#define hashkit_is_initialized(__object) ((__object)->options.is_initialized)
 
-  hashkit_st self;
-};
+#ifdef __cplusplus
+} // extern "C"
 #endif
-
-
-#endif /* HASHKIT_H */
diff --git a/libhashkit/hashkit.hpp b/libhashkit/hashkit.hpp
new file mode 100644 (file)
index 0000000..7ead63d
--- /dev/null
@@ -0,0 +1,97 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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.
+ *
+ */
+
+#pragma once
+
+#include <libhashkit/hashkit.h>
+#include <string>
+
+class Hashkit {
+
+public:
+
+  Hashkit()
+  {
+    hashkit_create(&self);
+  }
+
+  Hashkit(const Hashkit& source)
+  {
+    hashkit_clone(&self, &source.self);
+  }
+
+  Hashkit& operator=(const Hashkit& source)
+  {
+    hashkit_free(&self);
+    hashkit_clone(&self, &source.self);
+
+    return *this;
+  }
+
+  friend bool operator==(const Hashkit &left, const Hashkit &right)
+  {
+    return hashkit_compare(&left.self, &right.self);
+  }
+
+  uint32_t digest(std::string& str)
+  {
+    return hashkit_digest(&self, str.c_str(), str.length());
+  }
+
+  uint32_t digest(const char *key, size_t key_length)
+  {
+    return hashkit_digest(&self, key, key_length);
+  }
+
+  hashkit_return_t set_function(hashkit_hash_algorithm_t hash_algorithm)
+  {
+    return hashkit_set_function(&self, hash_algorithm);
+  }
+
+  hashkit_return_t set_distribution_function(hashkit_hash_algorithm_t hash_algorithm)
+  {
+    return hashkit_set_function(&self, hash_algorithm);
+  }
+
+  ~Hashkit()
+  {
+    hashkit_free(&self);
+  }
+private:
+
+  hashkit_st self;
+};
diff --git a/libhashkit/hsieh.c b/libhashkit/hsieh.c
deleted file mode 100644 (file)
index 35a2e20..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* By Paul Hsieh (C) 2004, 2005.  Covered under the Paul Hsieh
- * derivative license.
- * See: http://www.azillionmonkeys.com/qed/weblicense.html for license
- * details.
- * http://www.azillionmonkeys.com/qed/hash.html
-*/
-
-#include <libhashkit/common.h>
-
-#undef get16bits
-#if (defined(__GNUC__) && defined(__i386__))
-#define get16bits(d) (*((const uint16_t *) (d)))
-#endif
-
-#if !defined (get16bits)
-#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
-                      +(uint32_t)(((const uint8_t *)(d))[0]) )
-#endif
-
-uint32_t hashkit_hsieh(const char *key, size_t key_length, void *context __attribute__((unused)))
-{
-  uint32_t hash = 0, tmp;
-  int rem;
-
-  if (key_length <= 0 || key == NULL)
-    return 0;
-
-  rem = key_length & 3;
-  key_length >>= 2;
-
-  /* Main loop */
-  for (;key_length > 0; key_length--)
-  {
-    hash  += get16bits (key);
-    tmp    = (get16bits (key+2) << 11) ^ hash;
-    hash   = (hash << 16) ^ tmp;
-    key  += 2*sizeof (uint16_t);
-    hash  += hash >> 11;
-  }
-
-  /* Handle end cases */
-  switch (rem)
-  {
-  case 3: hash += get16bits (key);
-          hash ^= hash << 16;
-          hash ^= (uint32_t)key[sizeof (uint16_t)] << 18;
-          hash += hash >> 11;
-          break;
-  case 2: hash += get16bits (key);
-          hash ^= hash << 11;
-          hash += hash >> 17;
-          break;
-  case 1: hash += (unsigned char)(*key);
-          hash ^= hash << 10;
-          hash += hash >> 1;
-  default:
-          break;
-  }
-
-  /* Force "avalanching" of final 127 bits */
-  hash ^= hash << 3;
-  hash += hash >> 5;
-  hash ^= hash << 4;
-  hash += hash >> 17;
-  hash ^= hash << 25;
-  hash += hash >> 6;
-
-  return hash;
-}
-
diff --git a/libhashkit/hsieh.cc b/libhashkit/hsieh.cc
new file mode 100644 (file)
index 0000000..35a2e20
--- /dev/null
@@ -0,0 +1,70 @@
+/* By Paul Hsieh (C) 2004, 2005.  Covered under the Paul Hsieh
+ * derivative license.
+ * See: http://www.azillionmonkeys.com/qed/weblicense.html for license
+ * details.
+ * http://www.azillionmonkeys.com/qed/hash.html
+*/
+
+#include <libhashkit/common.h>
+
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__))
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+                      +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+uint32_t hashkit_hsieh(const char *key, size_t key_length, void *context __attribute__((unused)))
+{
+  uint32_t hash = 0, tmp;
+  int rem;
+
+  if (key_length <= 0 || key == NULL)
+    return 0;
+
+  rem = key_length & 3;
+  key_length >>= 2;
+
+  /* Main loop */
+  for (;key_length > 0; key_length--)
+  {
+    hash  += get16bits (key);
+    tmp    = (get16bits (key+2) << 11) ^ hash;
+    hash   = (hash << 16) ^ tmp;
+    key  += 2*sizeof (uint16_t);
+    hash  += hash >> 11;
+  }
+
+  /* Handle end cases */
+  switch (rem)
+  {
+  case 3: hash += get16bits (key);
+          hash ^= hash << 16;
+          hash ^= (uint32_t)key[sizeof (uint16_t)] << 18;
+          hash += hash >> 11;
+          break;
+  case 2: hash += get16bits (key);
+          hash ^= hash << 11;
+          hash += hash >> 17;
+          break;
+  case 1: hash += (unsigned char)(*key);
+          hash ^= hash << 10;
+          hash += hash >> 1;
+  default:
+          break;
+  }
+
+  /* Force "avalanching" of final 127 bits */
+  hash ^= hash << 3;
+  hash += hash >> 5;
+  hash ^= hash << 4;
+  hash += hash >> 17;
+  hash ^= hash << 25;
+  hash += hash >> 6;
+
+  return hash;
+}
+
index 12575dfb0cdeabc6fdb016e40cc3326c4c8cdf46..43300585b6124cde647a4434f00aca8f1a70d6a8 100644 (file)
@@ -22,6 +22,7 @@ nobase_include_HEADERS+= \
                         libhashkit/digest.h \
                         libhashkit/function.h \
                         libhashkit/hashkit.h \
+                        libhashkit/hashkit.hpp \
                         libhashkit/strerror.h \
                         libhashkit/str_algorithm.h \
                         libhashkit/types.h \
@@ -31,31 +32,31 @@ noinst_HEADERS+= \
                 libhashkit/common.h
 
 libhashkit_libhashkit_la_SOURCES= \
-                                 libhashkit/algorithm.c \
-                                 libhashkit/behavior.c \
-                                 libhashkit/crc32.c \
-                                 libhashkit/digest.c \
-                                 libhashkit/fnv.c \
-                                 libhashkit/function.c \
-                                 libhashkit/hashkit.c \
-                                 libhashkit/jenkins.c \
-                                 libhashkit/ketama.c \
-                                 libhashkit/md5.c \
-                                 libhashkit/one_at_a_time.c \
-                                 libhashkit/str_algorithm.c \
-                                 libhashkit/strerror.c
+                                 libhashkit/algorithm.cc \
+                                 libhashkit/behavior.cc \
+                                 libhashkit/crc32.cc \
+                                 libhashkit/digest.cc \
+                                 libhashkit/fnv.cc \
+                                 libhashkit/function.cc \
+                                 libhashkit/hashkit.cc \
+                                 libhashkit/jenkins.cc \
+                                 libhashkit/ketama.cc \
+                                 libhashkit/md5.cc \
+                                 libhashkit/one_at_a_time.cc \
+                                 libhashkit/str_algorithm.cc \
+                                 libhashkit/strerror.cc
 
 if INCLUDE_HSIEH_SRC
-libhashkit_libhashkit_la_SOURCES+= libhashkit/hsieh.c
+libhashkit_libhashkit_la_SOURCES+= libhashkit/hsieh.cc
 endif
 
 if INCLUDE_MURMUR_SRC
-libhashkit_libhashkit_la_SOURCES+= libhashkit/murmur.c
+libhashkit_libhashkit_la_SOURCES+= libhashkit/murmur.cc
 endif
 
-libhashkit_libhashkit_la_CFLAGS= \
-                                ${AM_CFLAGS} \
-                                -DBUILDING_HASHKIT
+libhashkit_libhashkit_la_CXXFLAGS= \
+                                  ${AM_CXXFLAGS} \
+                                  -DBUILDING_HASHKIT
 
 libhashkit_libhashkit_la_LDFLAGS= \
                                  $(LIBM) \
diff --git a/libhashkit/jenkins.c b/libhashkit/jenkins.c
deleted file mode 100644 (file)
index c2001cb..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
-*
-* By Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this
-* code any way you wish, private, educational, or commercial.  It's free.
-* Use for hash table lookup, or anything where one collision in 2^^32 is
-* acceptable.  Do NOT use for cryptographic purposes.
-* http://burtleburtle.net/bob/hash/index.html
-*
-* Modified by Brian Pontz for libmemcached
-* TODO:
-* Add big endian support
-*/
-
-#include <libhashkit/common.h>
-
-#define hashsize(n) ((uint32_t)1<<(n))
-#define hashmask(n) (hashsize(n)-1)
-#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
-
-#define mix(a,b,c) \
-{ \
-  a -= c;  a ^= rot(c, 4);  c += b; \
-  b -= a;  b ^= rot(a, 6);  a += c; \
-  c -= b;  c ^= rot(b, 8);  b += a; \
-  a -= c;  a ^= rot(c,16);  c += b; \
-  b -= a;  b ^= rot(a,19);  a += c; \
-  c -= b;  c ^= rot(b, 4);  b += a; \
-}
-
-#define final(a,b,c) \
-{ \
-  c ^= b; c -= rot(b,14); \
-  a ^= c; a -= rot(c,11); \
-  b ^= a; b -= rot(a,25); \
-  c ^= b; c -= rot(b,16); \
-  a ^= c; a -= rot(c,4);  \
-  b ^= a; b -= rot(a,14); \
-  c ^= b; c -= rot(b,24); \
-}
-
-#define JENKINS_INITVAL 13
-
-/*
-jenkins_hash() -- hash a variable-length key into a 32-bit value
-  k       : the key (the unaligned variable-length array of bytes)
-  length  : the length of the key, counting by bytes
-  initval : can be any 4-byte value
-Returns a 32-bit value.  Every bit of the key affects every bit of
-the return value.  Two keys differing by one or two bits will have
-totally different hash values.
-
-The best hash table sizes are powers of 2.  There is no need to do
-mod a prime (mod is sooo slow!).  If you need less than 32 bits,
-use a bitmask.  For example, if you need only 10 bits, do
-  h = (h & hashmask(10));
-In which case, the hash table should have hashsize(10) elements.
-*/
-
-uint32_t hashkit_jenkins(const char *key, size_t length, void *context)
-{
-  uint32_t a,b,c;                                          /* internal state */
-  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */
-  (void)context;
-
-  /* Set up the internal state */
-  a = b = c = 0xdeadbeef + ((uint32_t)length) + JENKINS_INITVAL;
-
-  u.ptr = key;
-#ifndef WORDS_BIGENDIAN
-  if ((u.i & 0x3) == 0)
-  {
-    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
-
-    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
-    while (length > 12)
-    {
-      a += k[0];
-      b += k[1];
-      c += k[2];
-      mix(a,b,c);
-      length -= 12;
-      k += 3;
-    }
-
-    /*----------------------------- handle the last (probably partial) block */
-    /*
-     * "k[2]&0xffffff" actually reads beyond the end of the string, but
-     * then masks off the part it's not allowed to read.  Because the
-     * string is aligned, the masked-off tail is in the same word as the
-     * rest of the string.  Every machine with memory protection I've seen
-     * does it on word boundaries, so is OK with this.  But VALGRIND will
-     * still catch it and complain.  The masking trick does make the hash
-     * noticably faster for short strings (like English words).
-     */
-    switch(length)
-    {
-    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
-    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
-    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
-    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
-    case 8 : b+=k[1]; a+=k[0]; break;
-    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
-    case 6 : b+=k[1]&0xffff; a+=k[0]; break;
-    case 5 : b+=k[1]&0xff; a+=k[0]; break;
-    case 4 : a+=k[0]; break;
-    case 3 : a+=k[0]&0xffffff; break;
-    case 2 : a+=k[0]&0xffff; break;
-    case 1 : a+=k[0]&0xff; break;
-    case 0 : return c;              /* zero length strings require no mixing */
-    default: return c;
-    }
-
-  }
-  else if ((u.i & 0x1) == 0)
-  {
-    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
-    const uint8_t  *k8;
-
-    /*--------------- all but last block: aligned reads and different mixing */
-    while (length > 12)
-    {
-      a += k[0] + (((uint32_t)k[1])<<16);
-      b += k[2] + (((uint32_t)k[3])<<16);
-      c += k[4] + (((uint32_t)k[5])<<16);
-      mix(a,b,c);
-      length -= 12;
-      k += 6;
-    }
-
-    /*----------------------------- handle the last (probably partial) block */
-    k8 = (const uint8_t *)k;
-    switch(length)
-    {
-    case 12: c+=k[4]+(((uint32_t)k[5])<<16);
-             b+=k[2]+(((uint32_t)k[3])<<16);
-             a+=k[0]+(((uint32_t)k[1])<<16);
-             break;
-    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */
-    case 10: c+=k[4];
-             b+=k[2]+(((uint32_t)k[3])<<16);
-             a+=k[0]+(((uint32_t)k[1])<<16);
-             break;
-    case 9 : c+=k8[8];                      /* fall through */
-    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
-             a+=k[0]+(((uint32_t)k[1])<<16);
-             break;
-    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */
-    case 6 : b+=k[2];
-             a+=k[0]+(((uint32_t)k[1])<<16);
-             break;
-    case 5 : b+=k8[4];                      /* fall through */
-    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
-             break;
-    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */
-    case 2 : a+=k[0];
-             break;
-    case 1 : a+=k8[0];
-             break;
-    case 0 : return c;                     /* zero length requires no mixing */
-    default: return c;
-    }
-
-  }
-  else
-  {                        /* need to read the key one byte at a time */
-#endif /* little endian */
-    const uint8_t *k = (const uint8_t *)key;
-
-    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
-    while (length > 12)
-    {
-      a += k[0];
-      a += ((uint32_t)k[1])<<8;
-      a += ((uint32_t)k[2])<<16;
-      a += ((uint32_t)k[3])<<24;
-      b += k[4];
-      b += ((uint32_t)k[5])<<8;
-      b += ((uint32_t)k[6])<<16;
-      b += ((uint32_t)k[7])<<24;
-      c += k[8];
-      c += ((uint32_t)k[9])<<8;
-      c += ((uint32_t)k[10])<<16;
-      c += ((uint32_t)k[11])<<24;
-      mix(a,b,c);
-      length -= 12;
-      k += 12;
-    }
-
-    /*-------------------------------- last block: affect all 32 bits of (c) */
-    switch(length)                   /* all the case statements fall through */
-    {
-    case 12: c+=((uint32_t)k[11])<<24;
-    case 11: c+=((uint32_t)k[10])<<16;
-    case 10: c+=((uint32_t)k[9])<<8;
-    case 9 : c+=k[8];
-    case 8 : b+=((uint32_t)k[7])<<24;
-    case 7 : b+=((uint32_t)k[6])<<16;
-    case 6 : b+=((uint32_t)k[5])<<8;
-    case 5 : b+=k[4];
-    case 4 : a+=((uint32_t)k[3])<<24;
-    case 3 : a+=((uint32_t)k[2])<<16;
-    case 2 : a+=((uint32_t)k[1])<<8;
-    case 1 : a+=k[0];
-             break;
-    case 0 : return c;
-    default : return c;
-    }
-#ifndef WORDS_BIGENDIAN
-  }
-#endif
-
-  final(a,b,c);
-  return c;
-}
diff --git a/libhashkit/jenkins.cc b/libhashkit/jenkins.cc
new file mode 100644 (file)
index 0000000..c2001cb
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+*
+* By Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this
+* code any way you wish, private, educational, or commercial.  It's free.
+* Use for hash table lookup, or anything where one collision in 2^^32 is
+* acceptable.  Do NOT use for cryptographic purposes.
+* http://burtleburtle.net/bob/hash/index.html
+*
+* Modified by Brian Pontz for libmemcached
+* TODO:
+* Add big endian support
+*/
+
+#include <libhashkit/common.h>
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+#define mix(a,b,c) \
+{ \
+  a -= c;  a ^= rot(c, 4);  c += b; \
+  b -= a;  b ^= rot(a, 6);  a += c; \
+  c -= b;  c ^= rot(b, 8);  b += a; \
+  a -= c;  a ^= rot(c,16);  c += b; \
+  b -= a;  b ^= rot(a,19);  a += c; \
+  c -= b;  c ^= rot(b, 4);  b += a; \
+}
+
+#define final(a,b,c) \
+{ \
+  c ^= b; c -= rot(b,14); \
+  a ^= c; a -= rot(c,11); \
+  b ^= a; b -= rot(a,25); \
+  c ^= b; c -= rot(b,16); \
+  a ^= c; a -= rot(c,4);  \
+  b ^= a; b -= rot(a,14); \
+  c ^= b; c -= rot(b,24); \
+}
+
+#define JENKINS_INITVAL 13
+
+/*
+jenkins_hash() -- hash a variable-length key into a 32-bit value
+  k       : the key (the unaligned variable-length array of bytes)
+  length  : the length of the key, counting by bytes
+  initval : can be any 4-byte value
+Returns a 32-bit value.  Every bit of the key affects every bit of
+the return value.  Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2.  There is no need to do
+mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+use a bitmask.  For example, if you need only 10 bits, do
+  h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+*/
+
+uint32_t hashkit_jenkins(const char *key, size_t length, void *context)
+{
+  uint32_t a,b,c;                                          /* internal state */
+  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */
+  (void)context;
+
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + ((uint32_t)length) + JENKINS_INITVAL;
+
+  u.ptr = key;
+#ifndef WORDS_BIGENDIAN
+  if ((u.i & 0x3) == 0)
+  {
+    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
+
+    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      b += k[1];
+      c += k[2];
+      mix(a,b,c);
+      length -= 12;
+      k += 3;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    /*
+     * "k[2]&0xffffff" actually reads beyond the end of the string, but
+     * then masks off the part it's not allowed to read.  Because the
+     * string is aligned, the masked-off tail is in the same word as the
+     * rest of the string.  Every machine with memory protection I've seen
+     * does it on word boundaries, so is OK with this.  But VALGRIND will
+     * still catch it and complain.  The masking trick does make the hash
+     * noticably faster for short strings (like English words).
+     */
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+    case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+    case 5 : b+=k[1]&0xff; a+=k[0]; break;
+    case 4 : a+=k[0]; break;
+    case 3 : a+=k[0]&0xffffff; break;
+    case 2 : a+=k[0]&0xffff; break;
+    case 1 : a+=k[0]&0xff; break;
+    case 0 : return c;              /* zero length strings require no mixing */
+    default: return c;
+    }
+
+  }
+  else if ((u.i & 0x1) == 0)
+  {
+    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
+    const uint8_t  *k8;
+
+    /*--------------- all but last block: aligned reads and different mixing */
+    while (length > 12)
+    {
+      a += k[0] + (((uint32_t)k[1])<<16);
+      b += k[2] + (((uint32_t)k[3])<<16);
+      c += k[4] + (((uint32_t)k[5])<<16);
+      mix(a,b,c);
+      length -= 12;
+      k += 6;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */
+    case 10: c+=k[4];
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 9 : c+=k8[8];                      /* fall through */
+    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */
+    case 6 : b+=k[2];
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 5 : b+=k8[4];                      /* fall through */
+    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */
+    case 2 : a+=k[0];
+             break;
+    case 1 : a+=k8[0];
+             break;
+    case 0 : return c;                     /* zero length requires no mixing */
+    default: return c;
+    }
+
+  }
+  else
+  {                        /* need to read the key one byte at a time */
+#endif /* little endian */
+    const uint8_t *k = (const uint8_t *)key;
+
+    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      a += ((uint32_t)k[1])<<8;
+      a += ((uint32_t)k[2])<<16;
+      a += ((uint32_t)k[3])<<24;
+      b += k[4];
+      b += ((uint32_t)k[5])<<8;
+      b += ((uint32_t)k[6])<<16;
+      b += ((uint32_t)k[7])<<24;
+      c += k[8];
+      c += ((uint32_t)k[9])<<8;
+      c += ((uint32_t)k[10])<<16;
+      c += ((uint32_t)k[11])<<24;
+      mix(a,b,c);
+      length -= 12;
+      k += 12;
+    }
+
+    /*-------------------------------- last block: affect all 32 bits of (c) */
+    switch(length)                   /* all the case statements fall through */
+    {
+    case 12: c+=((uint32_t)k[11])<<24;
+    case 11: c+=((uint32_t)k[10])<<16;
+    case 10: c+=((uint32_t)k[9])<<8;
+    case 9 : c+=k[8];
+    case 8 : b+=((uint32_t)k[7])<<24;
+    case 7 : b+=((uint32_t)k[6])<<16;
+    case 6 : b+=((uint32_t)k[5])<<8;
+    case 5 : b+=k[4];
+    case 4 : a+=((uint32_t)k[3])<<24;
+    case 3 : a+=((uint32_t)k[2])<<16;
+    case 2 : a+=((uint32_t)k[1])<<8;
+    case 1 : a+=k[0];
+             break;
+    case 0 : return c;
+    default : return c;
+    }
+#ifndef WORDS_BIGENDIAN
+  }
+#endif
+
+  final(a,b,c);
+  return c;
+}
diff --git a/libhashkit/ketama.c b/libhashkit/ketama.c
deleted file mode 100644 (file)
index 45052c2..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/* HashKit
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-#include <math.h>
-
-#if 0
-static uint32_t ketama_server_hash(const char *key, unsigned int key_length, int alignment)
-{
-  unsigned char results[16];
-
-  md5_signature((unsigned char*)key, key_length, results);
-  return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
-    | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
-    | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
-    | (results[0 + alignment * 4] & 0xFF);
-}
-
-static int continuum_points_cmp(const void *t1, const void *t2)
-{
-  hashkit_continuum_point_st *ct1= (hashkit_continuum_point_st *)t1;
-  hashkit_continuum_point_st *ct2= (hashkit_continuum_point_st *)t2;
-
-  if (ct1->value == ct2->value)
-    return 0;
-  else if (ct1->value > ct2->value)
-    return 1;
-  else
-    return -1;
-}
-
-int update_continuum(hashkit_st *hashkit)
-{
-  uint32_t count;
-  uint32_t continuum_index= 0;
-  uint32_t value;
-  uint32_t points_index;
-  uint32_t points_count= 0;
-  uint32_t points_per_server;
-  uint32_t points_per_hash;
-  uint64_t total_weight= 0;
-  uint32_t live_servers;
-  uint8_t *context;
-
-  if (hashkit->active_fn != NULL || hashkit->weight_fn != NULL)
-  {
-    live_servers= 0;
-
-    for (count= 0, context= hashkit->list; count < hashkit->list_size;
-         count++, context+= hashkit->context_size)
-    {
-      if (hashkit->active_fn != NULL)
-      {
-        if (hashkit->active_fn(context))
-          live_servers++;
-        else
-          continue;
-      }
-
-      if (hashkit->weight_fn != NULL)
-        total_weight+= hashkit->weight_fn(context);
-    }
-  }
-
-  if (hashkit->active_fn == NULL)
-    live_servers= (uint32_t)hashkit->list_size;
-
-  if (live_servers == 0)
-    return 0;
-
-  if (hashkit->weight_fn == NULL)
-  {
-    points_per_server= HASHKIT_POINTS_PER_NODE;
-    points_per_hash= 1;
-  }
-  else
-  {
-    points_per_server= HASHKIT_POINTS_PER_NODE_WEIGHTED;
-    points_per_hash= 4;
-  }
-
-  if (live_servers > hashkit->continuum_count)
-  {
-    hashkit_continuum_point_st *new_continuum;
-
-    new_continuum= realloc(hashkit->continuum,
-                           sizeof(hashkit_continuum_point_st) *
-                           (live_servers + HASHKIT_CONTINUUM_ADDITION) *
-                           points_per_server);
-
-    if (new_continuum == NULL)
-      return ENOMEM;
-
-    hashkit->continuum= new_continuum;
-    hashkit->continuum_count= live_servers + HASHKIT_CONTINUUM_ADDITION;
-  }
-
-  for (count= 0, context= hashkit->list; count < hashkit->list_size;
-       count++, context+= hashkit->context_size)
-  {
-    if (hashkit->active_fn != NULL && hashkit->active_fn(context) == false)
-      continue;
-
-    if (hashkit->weight_fn != NULL)
-    {
-        float pct = (float)hashkit->weight_fn(context) / (float)total_weight;
-        points_per_server= (uint32_t) ((floorf((float) (pct * HASHKIT_POINTS_PER_NODE_WEIGHTED / 4 * (float)live_servers + 0.0000000001))) * 4);
-    }
-
-    for (points_index= 0;
-         points_index < points_per_server / points_per_hash;
-         points_index++)
-    {
-      char sort_host[HASHKIT_CONTINUUM_KEY_SIZE]= "";
-      size_t sort_host_length;
-
-      if (hashkit->continuum_key_fn == NULL)
-      {
-        sort_host_length= (size_t) snprintf(sort_host, HASHKIT_CONTINUUM_KEY_SIZE, "%u",
-                                            points_index);
-      }
-      else
-      {
-        sort_host_length= hashkit->continuum_key_fn(sort_host, HASHKIT_CONTINUUM_KEY_SIZE,
-                                                 points_index, context);
-      }
-
-      if (hashkit->weight_fn == NULL)
-      {
-        if (hashkit->continuum_hash_fn == NULL)
-          value= hashkit_default(sort_host, sort_host_length);
-        else
-          value= hashkit->continuum_hash_fn(sort_host, sort_host_length);
-
-        hashkit->continuum[continuum_index].index= count;
-        hashkit->continuum[continuum_index++].value= value;
-      }
-      else
-      {
-        unsigned int i;
-        for (i = 0; i < points_per_hash; i++)
-        {
-           value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
-           hashkit->continuum[continuum_index].index= count;
-           hashkit->continuum[continuum_index++].value= value;
-        }
-      }
-    }
-
-    points_count+= points_per_server;
-  }
-
-  hashkit->continuum_points_count= points_count;
-  qsort(hashkit->continuum, hashkit->continuum_points_count, sizeof(hashkit_continuum_point_st),
-        continuum_points_cmp);
-
-  return 0;
-}
-#endif
diff --git a/libhashkit/ketama.cc b/libhashkit/ketama.cc
new file mode 100644 (file)
index 0000000..45052c2
--- /dev/null
@@ -0,0 +1,164 @@
+/* HashKit
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+#include <math.h>
+
+#if 0
+static uint32_t ketama_server_hash(const char *key, unsigned int key_length, int alignment)
+{
+  unsigned char results[16];
+
+  md5_signature((unsigned char*)key, key_length, results);
+  return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
+    | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
+    | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
+    | (results[0 + alignment * 4] & 0xFF);
+}
+
+static int continuum_points_cmp(const void *t1, const void *t2)
+{
+  hashkit_continuum_point_st *ct1= (hashkit_continuum_point_st *)t1;
+  hashkit_continuum_point_st *ct2= (hashkit_continuum_point_st *)t2;
+
+  if (ct1->value == ct2->value)
+    return 0;
+  else if (ct1->value > ct2->value)
+    return 1;
+  else
+    return -1;
+}
+
+int update_continuum(hashkit_st *hashkit)
+{
+  uint32_t count;
+  uint32_t continuum_index= 0;
+  uint32_t value;
+  uint32_t points_index;
+  uint32_t points_count= 0;
+  uint32_t points_per_server;
+  uint32_t points_per_hash;
+  uint64_t total_weight= 0;
+  uint32_t live_servers;
+  uint8_t *context;
+
+  if (hashkit->active_fn != NULL || hashkit->weight_fn != NULL)
+  {
+    live_servers= 0;
+
+    for (count= 0, context= hashkit->list; count < hashkit->list_size;
+         count++, context+= hashkit->context_size)
+    {
+      if (hashkit->active_fn != NULL)
+      {
+        if (hashkit->active_fn(context))
+          live_servers++;
+        else
+          continue;
+      }
+
+      if (hashkit->weight_fn != NULL)
+        total_weight+= hashkit->weight_fn(context);
+    }
+  }
+
+  if (hashkit->active_fn == NULL)
+    live_servers= (uint32_t)hashkit->list_size;
+
+  if (live_servers == 0)
+    return 0;
+
+  if (hashkit->weight_fn == NULL)
+  {
+    points_per_server= HASHKIT_POINTS_PER_NODE;
+    points_per_hash= 1;
+  }
+  else
+  {
+    points_per_server= HASHKIT_POINTS_PER_NODE_WEIGHTED;
+    points_per_hash= 4;
+  }
+
+  if (live_servers > hashkit->continuum_count)
+  {
+    hashkit_continuum_point_st *new_continuum;
+
+    new_continuum= realloc(hashkit->continuum,
+                           sizeof(hashkit_continuum_point_st) *
+                           (live_servers + HASHKIT_CONTINUUM_ADDITION) *
+                           points_per_server);
+
+    if (new_continuum == NULL)
+      return ENOMEM;
+
+    hashkit->continuum= new_continuum;
+    hashkit->continuum_count= live_servers + HASHKIT_CONTINUUM_ADDITION;
+  }
+
+  for (count= 0, context= hashkit->list; count < hashkit->list_size;
+       count++, context+= hashkit->context_size)
+  {
+    if (hashkit->active_fn != NULL && hashkit->active_fn(context) == false)
+      continue;
+
+    if (hashkit->weight_fn != NULL)
+    {
+        float pct = (float)hashkit->weight_fn(context) / (float)total_weight;
+        points_per_server= (uint32_t) ((floorf((float) (pct * HASHKIT_POINTS_PER_NODE_WEIGHTED / 4 * (float)live_servers + 0.0000000001))) * 4);
+    }
+
+    for (points_index= 0;
+         points_index < points_per_server / points_per_hash;
+         points_index++)
+    {
+      char sort_host[HASHKIT_CONTINUUM_KEY_SIZE]= "";
+      size_t sort_host_length;
+
+      if (hashkit->continuum_key_fn == NULL)
+      {
+        sort_host_length= (size_t) snprintf(sort_host, HASHKIT_CONTINUUM_KEY_SIZE, "%u",
+                                            points_index);
+      }
+      else
+      {
+        sort_host_length= hashkit->continuum_key_fn(sort_host, HASHKIT_CONTINUUM_KEY_SIZE,
+                                                 points_index, context);
+      }
+
+      if (hashkit->weight_fn == NULL)
+      {
+        if (hashkit->continuum_hash_fn == NULL)
+          value= hashkit_default(sort_host, sort_host_length);
+        else
+          value= hashkit->continuum_hash_fn(sort_host, sort_host_length);
+
+        hashkit->continuum[continuum_index].index= count;
+        hashkit->continuum[continuum_index++].value= value;
+      }
+      else
+      {
+        unsigned int i;
+        for (i = 0; i < points_per_hash; i++)
+        {
+           value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
+           hashkit->continuum[continuum_index].index= count;
+           hashkit->continuum[continuum_index++].value= value;
+        }
+      }
+    }
+
+    points_count+= points_per_server;
+  }
+
+  hashkit->continuum_points_count= points_count;
+  qsort(hashkit->continuum, hashkit->continuum_points_count, sizeof(hashkit_continuum_point_st),
+        continuum_points_cmp);
+
+  return 0;
+}
+#endif
diff --git a/libhashkit/md5.c b/libhashkit/md5.c
deleted file mode 100644 (file)
index 1af5e6c..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
-  This Library has been modified from its original form by
-  Brian Aker (brian@tangent.org)
-
-  See below for original Copyright.
-*/
-/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
- */
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
-*/
-
-#include <libhashkit/common.h>
-
-#include <string.h>
-#include <sys/types.h>
-
-/* POINTER defines a generic pointer type */
-typedef unsigned char *POINTER;
-
-
-/* UINT4 defines a four byte word */
-typedef unsigned int UINT4;
-
-
-/* MD5 context. */
-typedef struct {
-  UINT4 state[4];                                   /* state (ABCD) */
-  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
-  unsigned char buffer[64];                         /* input buffer */
-} MD5_CTX;
-
-static void MD5Init (MD5_CTX *context);      /* context */
-static void MD5Update ( MD5_CTX *context,                                        /* context */
-                        const unsigned char *input,                              /* input block */
-                        unsigned int inputLen);                     /* length of input block */
-static void MD5Final ( unsigned char digest[16],                         /* message digest */
-                       MD5_CTX *context);                              /* context */
-
-/* Constants for MD5Transform routine. */
-
-#define S11 7
-#define S12 12
-#define S13 17
-#define S14 22
-#define S21 5
-#define S22 9
-#define S23 14
-#define S24 20
-#define S31 4
-#define S32 11
-#define S33 16
-#define S34 23
-#define S41 6
-#define S42 10
-#define S43 15
-#define S44 21
-
-
-static void MD5Transform (UINT4 state[4],
-                          unsigned char block[64]);
-static void Encode (unsigned char *output,
-                    UINT4 *input,
-                    unsigned int len);
-static void Decode(UINT4 *output, unsigned char *input, unsigned int len);
-
-static unsigned char PADDING[64] = {
-  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* F, G, H and I are basic MD5 functions.
- */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-/* ROTATE_LEFT rotates x left n bits.
- */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
-Rotation is separate from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s, ac) { \
- (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-#define GG(a, b, c, d, x, s, ac) { \
- (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-#define HH(a, b, c, d, x, s, ac) { \
- (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-#define II(a, b, c, d, x, s, ac) { \
- (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-
-
-/*
-  Just a simple method for getting the signature
-  result must be == 16
-*/
-void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result)
-{
-    MD5_CTX my_md5;
-
-    MD5Init(&my_md5);
-    (void)MD5Update(&my_md5, key, length);
-    MD5Final(result, &my_md5);
-}
-
-/* MD5 initialization. Begins an MD5 operation, writing a new context.
- */
-static void MD5Init (MD5_CTX *context)      /* context */
-{
-  context->count[0] = context->count[1] = 0;
-  /* Load magic initialization constants.
-*/
-  context->state[0] = 0x67452301;
-  context->state[1] = 0xefcdab89;
-  context->state[2] = 0x98badcfe;
-  context->state[3] = 0x10325476;
-}
-
-/* MD5 block update operation. Continues an MD5 message-digest
-  operation, processing another message block, and updating the
-  context.
- */
-
-static void MD5Update (
-                       MD5_CTX *context,                                        /* context */
-                       const unsigned char *input,                              /* input block */
-                       unsigned int inputLen)                     /* length of input block */
-{
-  unsigned int i, idx, partLen;
-
-  /* Compute number of bytes mod 64 */
-  idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
-
-
-  /* Update number of bits */
-  if ((context->count[0] += ((UINT4)inputLen << 3))
-      < ((UINT4)inputLen << 3))
-    context->count[1]++;
-  context->count[1] += ((UINT4)inputLen >> 29);
-
-  partLen = 64 - idx;
-
-  /* Transform as many times as possible.
-*/
-  if (inputLen >= partLen) {
- memcpy((POINTER)&context->buffer[idx], (POINTER)input, partLen);
- MD5Transform(context->state, context->buffer);
-
- for (i = partLen; i + 63 < inputLen; i += 64)
-   MD5Transform (context->state, (unsigned char *)&input[i]);
-
- idx = 0;
-  }
-  else
- i = 0;
-
-  /* Buffer remaining input */
-  memcpy((POINTER)&context->buffer[idx], (POINTER)&input[i],
-            inputLen-i);
-}
-
-/* MD5 finalization. Ends an MD5 message-digest operation, writing the
-  the message digest and zeroizing the context.
- */
-
-static void MD5Final (
-                      unsigned char digest[16],                         /* message digest */
-                      MD5_CTX *context)                              /* context */
-{
-  unsigned char bits[8];
-  unsigned int idx, padLen;
-
-  /* Save number of bits */
-  Encode (bits, context->count, 8);
-
-  /* Pad out to 56 mod 64.
-*/
-  idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
-  padLen = (idx < 56) ? (56 - idx) : (120 - idx);
-  MD5Update (context, PADDING, padLen);
-
-  /* Append length (before padding) */
-  MD5Update (context, bits, 8);
-
-  /* Store state in digest */
-  Encode (digest, context->state, 16);
-
-  /* Zeroize sensitive information.
-*/
-  memset((POINTER)context, 0, sizeof (*context));
-}
-
-/* MD5 basic transformation. Transforms state based on block.
- */
-static void MD5Transform (
-                          UINT4 state[4],
-                          unsigned char block[64])
-{
-  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
-
-  Decode (x, block, 64);
-
-  /* Round 1 */
-  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
-  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
-  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
-  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
-  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
-  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
-  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
-  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
-  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
-  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
-  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
-  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
-  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
-  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
-  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
-  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
-
- /* Round 2 */
-  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
-  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
-  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
-  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
-  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
-  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
-  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
-  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
-  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
-  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
-  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
-  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
-  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
-  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
-  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
-  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
-
-  /* Round 3 */
-  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
-  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
-  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
-  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
-  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
-  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
-  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
-  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
-  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
-  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
-  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
-  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
-  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
-  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
-  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
-  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
-
-  /* Round 4 */
-  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
-  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
-  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
-  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
-  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
-  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
-  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
-  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
-  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
-  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
-  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
-  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
-  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
-  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
-  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
-  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
-
-
-  state[0] += a;
-  state[1] += b;
-  state[2] += c;
-  state[3] += d;
-
-  /* Zeroize sensitive information.
-*/
-  memset((POINTER)x, 0, sizeof (x));
-}
-
-/* Encodes input (UINT4) into output (unsigned char). Assumes len is
-  a multiple of 4.
- */
-static void Encode (
-unsigned char *output,
-UINT4 *input,
-unsigned int len)
-{
-  unsigned int i, j;
-
-  for (i = 0, j = 0; j < len; i++, j += 4) {
- output[j] = (unsigned char)(input[i] & 0xff);
- output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
- output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
- output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
-  }
-}
-
-
-/* Decodes input (unsigned char) into output (UINT4). Assumes len is
-  a multiple of 4.
- */
-static void Decode (
-UINT4 *output,
-unsigned char *input,
-unsigned int len)
-{
-  unsigned int i, j;
-
-  for (i = 0, j = 0; j < len; i++, j += 4)
- output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
-   (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
-}
-
-uint32_t hashkit_md5(const char *key, size_t key_length, void *context)
-{
-  unsigned char results[16];
-  (void)context;
-
-  md5_signature((unsigned char*)key, (unsigned int)key_length, results);
-
-  return ((uint32_t) (results[3] & 0xFF) << 24)
-    | ((uint32_t) (results[2] & 0xFF) << 16)
-    | ((uint32_t) (results[1] & 0xFF) << 8)
-    | (results[0] & 0xFF);
-}
diff --git a/libhashkit/md5.cc b/libhashkit/md5.cc
new file mode 100644 (file)
index 0000000..86822f5
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+  This Library has been modified from its original form by
+  Brian Aker (brian@tangent.org)
+
+  See below for original Copyright.
+*/
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+#include <libhashkit/common.h>
+
+#include <string.h>
+#include <sys/types.h>
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+typedef const unsigned char *CONST_POINTER;
+
+
+/* UINT4 defines a four byte word */
+typedef unsigned int UINT4;
+
+
+/* MD5 context. */
+typedef struct {
+  UINT4 state[4];                                   /* state (ABCD) */
+  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                         /* input buffer */
+} MD5_CTX;
+
+static void MD5Init (MD5_CTX *context);      /* context */
+static void MD5Update ( MD5_CTX *context,                                        /* context */
+                        const unsigned char *input,                              /* input block */
+                        unsigned int inputLen);                     /* length of input block */
+static void MD5Final ( unsigned char digest[16],                         /* message digest */
+                       MD5_CTX *context);                              /* context */
+
+/* Constants for MD5Transform routine. */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+
+static void MD5Transform (UINT4 state[4],
+                          const unsigned char block[64]);
+static void Encode (unsigned char *output,
+                    UINT4 *input,
+                    unsigned int len);
+static void Decode(UINT4 *output, const unsigned char *input, unsigned int len);
+
+static unsigned char PADDING[64] = {
+  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+
+
+/*
+  Just a simple method for getting the signature
+  result must be == 16
+*/
+void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result)
+{
+    MD5_CTX my_md5;
+
+    MD5Init(&my_md5);
+    (void)MD5Update(&my_md5, key, length);
+    MD5Final(result, &my_md5);
+}
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+static void MD5Init (MD5_CTX *context)      /* context */
+{
+  context->count[0] = context->count[1] = 0;
+  /* Load magic initialization constants.
+*/
+  context->state[0] = 0x67452301;
+  context->state[1] = 0xefcdab89;
+  context->state[2] = 0x98badcfe;
+  context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+  operation, processing another message block, and updating the
+  context.
+ */
+
+static void MD5Update (
+                       MD5_CTX *context,                                        /* context */
+                       const unsigned char *input,                              /* input block */
+                       unsigned int inputLen)                     /* length of input block */
+{
+  unsigned int i, idx, partLen;
+
+  /* Compute number of bytes mod 64 */
+  idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+
+  /* Update number of bits */
+  if ((context->count[0] += ((UINT4)inputLen << 3))
+      < ((UINT4)inputLen << 3))
+    context->count[1]++;
+  context->count[1] += ((UINT4)inputLen >> 29);
+
+  partLen = 64 - idx;
+
+  /* Transform as many times as possible.
+*/
+  if (inputLen >= partLen) {
+    memcpy((POINTER)&context->buffer[idx], (CONST_POINTER)input, partLen);
+    MD5Transform(context->state, context->buffer);
+
+    for (i = partLen; i + 63 < inputLen; i += 64)
+      MD5Transform (context->state, (CONST_POINTER)&input[i]);
+
+    idx = 0;
+  }
+  else
+    i = 0;
+
+  /* Buffer remaining input */
+  memcpy((POINTER)&context->buffer[idx], (CONST_POINTER)&input[i],
+         inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+  the message digest and zeroizing the context.
+ */
+
+static void MD5Final (
+                      unsigned char digest[16],                         /* message digest */
+                      MD5_CTX *context)                              /* context */
+{
+  unsigned char bits[8];
+  unsigned int idx, padLen;
+
+  /* Save number of bits */
+  Encode (bits, context->count, 8);
+
+  /* Pad out to 56 mod 64.
+*/
+  idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
+  padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+  MD5Update (context, PADDING, padLen);
+
+  /* Append length (before padding) */
+  MD5Update (context, bits, 8);
+
+  /* Store state in digest */
+  Encode (digest, context->state, 16);
+
+  /* Zeroize sensitive information.
+*/
+  memset((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (
+                          UINT4 state[4],
+                          const unsigned char block[64])
+{
+  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+  Decode (x, block, 64);
+
+  /* Round 1 */
+  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+  /* Round 3 */
+  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+  /* Round 4 */
+  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+
+  state[0] += a;
+  state[1] += b;
+  state[2] += c;
+  state[3] += d;
+
+  /* Zeroize sensitive information.
+*/
+  memset((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+  a multiple of 4.
+ */
+static void Encode (
+unsigned char *output,
+UINT4 *input,
+unsigned int len)
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+  }
+}
+
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+  a multiple of 4.
+ */
+static void Decode (
+                    UINT4 *output,
+                    const unsigned char *input,
+                    unsigned int len)
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4)
+    output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+      (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+uint32_t hashkit_md5(const char *key, size_t key_length, void *context)
+{
+  unsigned char results[16];
+  (void)context;
+
+  md5_signature((unsigned char*)key, (unsigned int)key_length, results);
+
+  return ((uint32_t) (results[3] & 0xFF) << 24)
+    | ((uint32_t) (results[2] & 0xFF) << 16)
+    | ((uint32_t) (results[1] & 0xFF) << 8)
+    | (results[0] & 0xFF);
+}
diff --git a/libhashkit/murmur.c b/libhashkit/murmur.c
deleted file mode 100644 (file)
index a40b11b..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-  "Murmur" hash provided by Austin, tanjent@gmail.com
-  http://murmurhash.googlepages.com/
-
-  Note - This code makes a few assumptions about how your machine behaves -
-
-  1. We can read a 4-byte value from any address without crashing
-  2. sizeof(int) == 4
-
-  And it has a few limitations -
-  1. It will not work incrementally.
-  2. It will not produce the same results on little-endian and big-endian
-  machines.
-
-  Updated to murmur2 hash - BP
-*/
-
-#include <libhashkit/common.h>
-
-uint32_t hashkit_murmur(const char *key, size_t length, void *context)
-{
-  /*
-    'm' and 'r' are mixing constants generated offline.  They're not
-    really 'magic', they just happen to work well.
-  */
-
-  const unsigned int m= 0x5bd1e995;
-  const uint32_t seed= (0xdeadbeef * (uint32_t)length);
-  const int r= 24;
-
-
-  // Initialize the hash to a 'random' value
-
-  uint32_t h= seed ^ (uint32_t)length;
-
-  // Mix 4 bytes at a time into the hash
-
-  const unsigned char * data= (const unsigned char *)key;
-  (void)context;
-
-  while(length >= 4)
-  {
-    unsigned int k = *(unsigned int *)data;
-
-    k *= m;
-    k ^= k >> r;
-    k *= m;
-
-    h *= m;
-    h ^= k;
-
-    data += 4;
-    length -= 4;
-  }
-
-  // Handle the last few bytes of the input array
-
-  switch(length)
-  {
-  case 3: h ^= ((uint32_t)data[2]) << 16;
-  case 2: h ^= ((uint32_t)data[1]) << 8;
-  case 1: h ^= data[0];
-          h *= m;
-  default: break;
-  };
-
-  /*
-    Do a few final mixes of the hash to ensure the last few bytes are
-    well-incorporated.
-  */
-
-  h ^= h >> 13;
-  h *= m;
-  h ^= h >> 15;
-
-  return h;
-}
diff --git a/libhashkit/murmur.cc b/libhashkit/murmur.cc
new file mode 100644 (file)
index 0000000..a40b11b
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+  "Murmur" hash provided by Austin, tanjent@gmail.com
+  http://murmurhash.googlepages.com/
+
+  Note - This code makes a few assumptions about how your machine behaves -
+
+  1. We can read a 4-byte value from any address without crashing
+  2. sizeof(int) == 4
+
+  And it has a few limitations -
+  1. It will not work incrementally.
+  2. It will not produce the same results on little-endian and big-endian
+  machines.
+
+  Updated to murmur2 hash - BP
+*/
+
+#include <libhashkit/common.h>
+
+uint32_t hashkit_murmur(const char *key, size_t length, void *context)
+{
+  /*
+    'm' and 'r' are mixing constants generated offline.  They're not
+    really 'magic', they just happen to work well.
+  */
+
+  const unsigned int m= 0x5bd1e995;
+  const uint32_t seed= (0xdeadbeef * (uint32_t)length);
+  const int r= 24;
+
+
+  // Initialize the hash to a 'random' value
+
+  uint32_t h= seed ^ (uint32_t)length;
+
+  // Mix 4 bytes at a time into the hash
+
+  const unsigned char * data= (const unsigned char *)key;
+  (void)context;
+
+  while(length >= 4)
+  {
+    unsigned int k = *(unsigned int *)data;
+
+    k *= m;
+    k ^= k >> r;
+    k *= m;
+
+    h *= m;
+    h ^= k;
+
+    data += 4;
+    length -= 4;
+  }
+
+  // Handle the last few bytes of the input array
+
+  switch(length)
+  {
+  case 3: h ^= ((uint32_t)data[2]) << 16;
+  case 2: h ^= ((uint32_t)data[1]) << 8;
+  case 1: h ^= data[0];
+          h *= m;
+  default: break;
+  };
+
+  /*
+    Do a few final mixes of the hash to ensure the last few bytes are
+    well-incorporated.
+  */
+
+  h ^= h >> 13;
+  h *= m;
+  h ^= h >> 15;
+
+  return h;
+}
diff --git a/libhashkit/one_at_a_time.c b/libhashkit/one_at_a_time.c
deleted file mode 100644 (file)
index aeb11b1..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* HashKit
- * Copyright (C) 2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- */
-
-/*
-  This has is Jenkin's "One at A time Hash".
-http://en.wikipedia.org/wiki/Jenkins_hash_function
-*/
-
-#include <libhashkit/common.h>
-
-uint32_t hashkit_one_at_a_time(const char *key, size_t key_length, void *context)
-{
-  const char *ptr= key;
-  uint32_t value= 0;
-  (void)context;
-
-  while (key_length--)
-  {
-    uint32_t val= (uint32_t) *ptr++;
-    value += val;
-    value += (value << 10);
-    value ^= (value >> 6);
-  }
-  value += (value << 3);
-  value ^= (value >> 11);
-  value += (value << 15);
-
-  return value;
-}
diff --git a/libhashkit/one_at_a_time.cc b/libhashkit/one_at_a_time.cc
new file mode 100644 (file)
index 0000000..aeb11b1
--- /dev/null
@@ -0,0 +1,34 @@
+/* HashKit
+ * Copyright (C) 2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ */
+
+/*
+  This has is Jenkin's "One at A time Hash".
+http://en.wikipedia.org/wiki/Jenkins_hash_function
+*/
+
+#include <libhashkit/common.h>
+
+uint32_t hashkit_one_at_a_time(const char *key, size_t key_length, void *context)
+{
+  const char *ptr= key;
+  uint32_t value= 0;
+  (void)context;
+
+  while (key_length--)
+  {
+    uint32_t val= (uint32_t) *ptr++;
+    value += val;
+    value += (value << 10);
+    value ^= (value >> 6);
+  }
+  value += (value << 3);
+  value ^= (value >> 11);
+  value += (value << 15);
+
+  return value;
+}
diff --git a/libhashkit/str_algorithm.c b/libhashkit/str_algorithm.c
deleted file mode 100644 (file)
index 0a0613b..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- * 
- *  HashKit
- *
- *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *
- *  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 <libhashkit/common.h>
-
-const char * libhashkit_string_hash(hashkit_hash_algorithm_t type)
-{
-  switch(type)
-  {
-  case HASHKIT_HASH_DEFAULT: return "DEFAULT";
-  case HASHKIT_HASH_MD5: return "MD5";
-  case HASHKIT_HASH_CRC: return "CRC";
-  case HASHKIT_HASH_FNV1_64: return "FNV1_64";
-  case HASHKIT_HASH_FNV1A_64: return "FNV1A_64";
-  case HASHKIT_HASH_FNV1_32: return "FNV1_32";
-  case HASHKIT_HASH_FNV1A_32: return "FNV1A_32";
-  case HASHKIT_HASH_HSIEH: return "HSIEH";
-  case HASHKIT_HASH_MURMUR: return "MURMUR";
-  case HASHKIT_HASH_JENKINS: return "JENKINS";
-  case HASHKIT_HASH_CUSTOM: return "CUSTOM";
-  default:
-  case HASHKIT_HASH_MAX: return "INVALID";
-  }
-}
diff --git a/libhashkit/str_algorithm.cc b/libhashkit/str_algorithm.cc
new file mode 100644 (file)
index 0000000..0a0613b
--- /dev/null
@@ -0,0 +1,57 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  HashKit
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ *  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 <libhashkit/common.h>
+
+const char * libhashkit_string_hash(hashkit_hash_algorithm_t type)
+{
+  switch(type)
+  {
+  case HASHKIT_HASH_DEFAULT: return "DEFAULT";
+  case HASHKIT_HASH_MD5: return "MD5";
+  case HASHKIT_HASH_CRC: return "CRC";
+  case HASHKIT_HASH_FNV1_64: return "FNV1_64";
+  case HASHKIT_HASH_FNV1A_64: return "FNV1A_64";
+  case HASHKIT_HASH_FNV1_32: return "FNV1_32";
+  case HASHKIT_HASH_FNV1A_32: return "FNV1A_32";
+  case HASHKIT_HASH_HSIEH: return "HSIEH";
+  case HASHKIT_HASH_MURMUR: return "MURMUR";
+  case HASHKIT_HASH_JENKINS: return "JENKINS";
+  case HASHKIT_HASH_CUSTOM: return "CUSTOM";
+  default:
+  case HASHKIT_HASH_MAX: return "INVALID";
+  }
+}
diff --git a/libhashkit/strerror.c b/libhashkit/strerror.c
deleted file mode 100644 (file)
index 8d7246c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* HashKit
- * Copyright (C) 2009 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- */
-
-#include <libhashkit/common.h>
-
-const char *hashkit_strerror(hashkit_st *ptr, hashkit_return_t rc)
-{
-  (void)ptr;
-  switch (rc)
-  {
-  case HASHKIT_SUCCESS: return "SUCCESS";
-  case HASHKIT_FAILURE: return "FAILURE";
-  case HASHKIT_MEMORY_ALLOCATION_FAILURE: return "MEMORY ALLOCATION FAILURE";
-  case HASHKIT_INVALID_ARGUMENT: return "INVALID ARGUMENT";
-  case HASHKIT_INVALID_HASH: return "INVALID hashkit_hash_algorithm_t";
-  case HASHKIT_MAXIMUM_RETURN:
-  default:
-    return "INVALID hashkit_return_t";
-  }
-}
diff --git a/libhashkit/strerror.cc b/libhashkit/strerror.cc
new file mode 100644 (file)
index 0000000..8d7246c
--- /dev/null
@@ -0,0 +1,25 @@
+/* HashKit
+ * Copyright (C) 2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ */
+
+#include <libhashkit/common.h>
+
+const char *hashkit_strerror(hashkit_st *ptr, hashkit_return_t rc)
+{
+  (void)ptr;
+  switch (rc)
+  {
+  case HASHKIT_SUCCESS: return "SUCCESS";
+  case HASHKIT_FAILURE: return "FAILURE";
+  case HASHKIT_MEMORY_ALLOCATION_FAILURE: return "MEMORY ALLOCATION FAILURE";
+  case HASHKIT_INVALID_ARGUMENT: return "INVALID ARGUMENT";
+  case HASHKIT_INVALID_HASH: return "INVALID hashkit_hash_algorithm_t";
+  case HASHKIT_MAXIMUM_RETURN:
+  default:
+    return "INVALID hashkit_return_t";
+  }
+}
index 7691d4b5941b34d233e0c068fb888394288e8ac9..b8f194c5ed935b552c3f69dd9b9ca225cc72418b 100644 (file)
@@ -13,8 +13,7 @@
  * @brief Visibility control macros
  */
 
-#ifndef HASHKIT_VISIBILITY_H
-#define HASHKIT_VISIBILITY_H
+#pragma once
 
 /**
  *
@@ -47,5 +46,3 @@
 #  define HASHKIT_LOCAL
 # endif /* defined(_MSC_VER) */
 #endif /* defined(BUILDING_HASHKIT) */
-
-#endif /* HASHKIT_VISIBILITY_H */
diff --git a/libmemcached/allocators.c b/libmemcached/allocators.c
deleted file mode 100644 (file)
index fe7b296..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#include "common.h"
-
-void _libmemcached_free(const memcached_st *ptr, void *mem, void *context)
-{
-  (void) ptr;
-  (void) context;
-  free(mem);
-}
-
-void *_libmemcached_malloc(const memcached_st *ptr, size_t size, void *context)
-{
-  (void) ptr;
-  (void) context;
-  return malloc(size);
-}
-
-void *_libmemcached_realloc(const memcached_st *ptr, void *mem, size_t size, void *context)
-{
-  (void) ptr;
-  (void) context;
-  return realloc(mem, size);
-}
-
-void *_libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size, void *context)
-{
-  if (ptr->allocators.malloc != _libmemcached_malloc)
-  {
-     void *ret = _libmemcached_malloc(ptr, nelem * size, context);
-     if (ret != NULL) 
-       memset(ret, 0, nelem * size);
-
-     return ret;
-  }
-
-  return calloc(nelem, size);
-}
-
-static const struct _allocators_st global_default_allocator= {
-  .calloc= _libmemcached_calloc,
-  .context= NULL,
-  .free= _libmemcached_free,
-  .malloc= _libmemcached_malloc,
-  .realloc= _libmemcached_realloc
-};
-
-struct _allocators_st memcached_allocators_return_default(void)
-{
-  return global_default_allocator;
-}
-
-memcached_return_t memcached_set_memory_allocators(memcached_st *ptr,
-                                                   memcached_malloc_fn mem_malloc,
-                                                   memcached_free_fn mem_free,
-                                                   memcached_realloc_fn mem_realloc,
-                                                   memcached_calloc_fn mem_calloc,
-                                                   void *context)
-{
-  /* All should be set, or none should be set */
-  if (mem_malloc == NULL && mem_free == NULL && mem_realloc == NULL && mem_calloc == NULL) 
-  {
-    ptr->allocators= memcached_allocators_return_default();
-  }
-  else if (mem_malloc == NULL || mem_free == NULL || mem_realloc == NULL || mem_calloc == NULL)
-  {
-    return MEMCACHED_FAILURE;
-  }
-  else
-  {
-    ptr->allocators.malloc= mem_malloc;
-    ptr->allocators.free= mem_free;
-    ptr->allocators.realloc= mem_realloc;
-    ptr->allocators.calloc= mem_calloc;
-    ptr->allocators.context= context;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-void *memcached_get_memory_allocators_context(const memcached_st *ptr)
-{
-  return ptr->allocators.context;
-}
-
-void memcached_get_memory_allocators(const memcached_st *ptr,
-                                     memcached_malloc_fn *mem_malloc,
-                                     memcached_free_fn *mem_free,
-                                     memcached_realloc_fn *mem_realloc,
-                                     memcached_calloc_fn *mem_calloc)
-{
-   *mem_malloc= ptr->allocators.malloc;
-   *mem_free= ptr->allocators.free;
-   *mem_realloc= ptr->allocators.realloc;
-   *mem_calloc= ptr->allocators.calloc;
-}
diff --git a/libmemcached/allocators.cc b/libmemcached/allocators.cc
new file mode 100644 (file)
index 0000000..e716bee
--- /dev/null
@@ -0,0 +1,87 @@
+#include "common.h"
+
+void _libmemcached_free(const memcached_st *ptr, void *mem, void *context)
+{
+  (void) ptr;
+  (void) context;
+  free(mem);
+}
+
+void *_libmemcached_malloc(const memcached_st *ptr, size_t size, void *context)
+{
+  (void) ptr;
+  (void) context;
+  return malloc(size);
+}
+
+void *_libmemcached_realloc(const memcached_st *ptr, void *mem, size_t size, void *context)
+{
+  (void) ptr;
+  (void) context;
+  return realloc(mem, size);
+}
+
+void *_libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size, void *context)
+{
+  if (ptr->allocators.malloc != _libmemcached_malloc)
+  {
+     void *ret = _libmemcached_malloc(ptr, nelem * size, context);
+     if (ret != NULL) 
+       memset(ret, 0, nelem * size);
+
+     return ret;
+  }
+
+  return calloc(nelem, size);
+}
+
+struct memcached_allocator_t memcached_allocators_return_default(void)
+{
+  static struct memcached_allocator_t global_default_allocator= { _libmemcached_calloc, _libmemcached_free, _libmemcached_malloc, _libmemcached_realloc, 0 };
+  return global_default_allocator;
+}
+
+memcached_return_t memcached_set_memory_allocators(memcached_st *ptr,
+                                                   memcached_malloc_fn mem_malloc,
+                                                   memcached_free_fn mem_free,
+                                                   memcached_realloc_fn mem_realloc,
+                                                   memcached_calloc_fn mem_calloc,
+                                                   void *context)
+{
+  /* All should be set, or none should be set */
+  if (mem_malloc == NULL && mem_free == NULL && mem_realloc == NULL && mem_calloc == NULL) 
+  {
+    ptr->allocators= memcached_allocators_return_default();
+  }
+  else if (mem_malloc == NULL || mem_free == NULL || mem_realloc == NULL || mem_calloc == NULL)
+  {
+    return MEMCACHED_FAILURE;
+  }
+  else
+  {
+    ptr->allocators.malloc= mem_malloc;
+    ptr->allocators.free= mem_free;
+    ptr->allocators.realloc= mem_realloc;
+    ptr->allocators.calloc= mem_calloc;
+    ptr->allocators.context= context;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+void *memcached_get_memory_allocators_context(const memcached_st *ptr)
+{
+  return ptr->allocators.context;
+}
+
+void memcached_get_memory_allocators(const memcached_st *ptr,
+                                     memcached_malloc_fn *mem_malloc,
+                                     memcached_free_fn *mem_free,
+                                     memcached_realloc_fn *mem_realloc,
+                                     memcached_calloc_fn *mem_calloc)
+{
+   *mem_malloc= ptr->allocators.malloc;
+   *mem_free= ptr->allocators.free;
+   *mem_realloc= ptr->allocators.realloc;
+   *mem_calloc= ptr->allocators.calloc;
+}
index b525e9016cbdf16799dadf4ee6986640e553a603..6e4455f0667464bad548564d5b07f3c249043fac 100644 (file)
@@ -1,16 +1,49 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
  *
- * Summary: work with user defined memory allocators
+ *  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.
  *
  */
 
-#ifndef __LIBMEMCACHED_ALLOCATORS_H__
-#define __LIBMEMCACHED_ALLOCATORS_H__
+#pragma once
+
+struct memcached_allocator_t {
+  memcached_calloc_fn calloc;
+  memcached_free_fn free;
+  memcached_malloc_fn malloc;
+  memcached_realloc_fn realloc;
+  void *context;
+};
 
 #ifdef __cplusplus
 extern "C" {
@@ -47,10 +80,8 @@ LIBMEMCACHED_LOCAL
 void *_libmemcached_calloc(const memcached_st *ptr, size_t nelem, size_t size, void *context);
 
 LIBMEMCACHED_LOCAL
-struct _allocators_st memcached_allocators_return_default(void);
+struct memcached_allocator_t memcached_allocators_return_default(void);
 
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __LIBMEMCACHED_ALLOCATORS_H__ */
diff --git a/libmemcached/analyze.c b/libmemcached/analyze.c
deleted file mode 100644 (file)
index 7dcbf8c..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-#include "common.h"
-
-static void calc_largest_consumption(memcached_analysis_st *result,
-                                     const uint32_t server_num,
-                                     const uint64_t nbytes)
-{
-  if (result->most_used_bytes < nbytes)
-  {
-    result->most_used_bytes= nbytes;
-    result->most_consumed_server= server_num;
-  }
-}
-
-static void calc_oldest_node(memcached_analysis_st *result,
-                                     const uint32_t server_num,
-                                     const uint32_t uptime)
-{
-  if (result->longest_uptime < uptime)
-  {
-    result->longest_uptime= uptime;
-    result->oldest_server= server_num;
-  }
-}
-
-static void calc_least_free_node(memcached_analysis_st *result,
-                                 const uint32_t server_num,
-                                 const uint64_t max_allowed_bytes,
-                                 const uint64_t used_bytes)
-{
-  uint64_t remaining_bytes= max_allowed_bytes - used_bytes;
-
-  if (result->least_remaining_bytes == 0 ||
-      remaining_bytes < result->least_remaining_bytes)
-  {
-    result->least_remaining_bytes= remaining_bytes;
-    result->least_free_server= server_num;
-  }
-}
-
-static void calc_average_item_size(memcached_analysis_st *result,
-                                   const uint64_t total_items,
-                                   const uint64_t total_bytes)
-{
-  if (total_items > 0 && total_bytes > 0)
-    result->average_item_size= (uint32_t) (total_bytes / total_items);
-}
-
-static void calc_hit_ratio(memcached_analysis_st *result,
-                           const uint64_t total_get_hits,
-                           const uint64_t total_get_cmds)
-{
-  if (total_get_hits == 0 || total_get_cmds == 0)
-  {
-    result->pool_hit_ratio= 0;
-    return;
-  }
-
-  double temp= (double) (total_get_hits/total_get_cmds);
-  result->pool_hit_ratio= temp * 100;
-}
-
-memcached_analysis_st *memcached_analyze(memcached_st *memc,
-                                         memcached_stat_st *memc_stat,
-                                         memcached_return_t *error)
-{
-  uint64_t total_items= 0, total_bytes= 0;
-  uint64_t total_get_cmds= 0, total_get_hits= 0;
-  uint32_t server_count, x;
-  memcached_analysis_st *result;
-
-  *error= MEMCACHED_SUCCESS;
-  server_count= memcached_server_count(memc);
-  result= (memcached_analysis_st*)calloc(memcached_server_count(memc),
-                                         sizeof(memcached_analysis_st));
-
-  if (!result)
-  {
-    *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-    return NULL;
-  }
-
-  result->root= memc;
-
-  for (x= 0; x < server_count; x++)
-  {
-    calc_largest_consumption(result, x, memc_stat[x].bytes);
-    calc_oldest_node(result, x, memc_stat[x].uptime);
-    calc_least_free_node(result, x,
-                         memc_stat[x].limit_maxbytes,
-                         memc_stat[x].bytes);
-
-    total_get_hits+= memc_stat[x].get_hits;
-    total_get_cmds+= memc_stat[x].cmd_get;
-    total_items+= memc_stat[x].curr_items;
-    total_bytes+= memc_stat[x].bytes;
-  }
-
-  calc_average_item_size(result, total_items, total_bytes);
-  calc_hit_ratio(result, total_get_hits, total_get_cmds);
-
-  return result;
-}
-
-void memcached_analyze_free(memcached_analysis_st *ptr)
-{
-  free(ptr);
-}
diff --git a/libmemcached/analyze.cc b/libmemcached/analyze.cc
new file mode 100644 (file)
index 0000000..7dcbf8c
--- /dev/null
@@ -0,0 +1,107 @@
+#include "common.h"
+
+static void calc_largest_consumption(memcached_analysis_st *result,
+                                     const uint32_t server_num,
+                                     const uint64_t nbytes)
+{
+  if (result->most_used_bytes < nbytes)
+  {
+    result->most_used_bytes= nbytes;
+    result->most_consumed_server= server_num;
+  }
+}
+
+static void calc_oldest_node(memcached_analysis_st *result,
+                                     const uint32_t server_num,
+                                     const uint32_t uptime)
+{
+  if (result->longest_uptime < uptime)
+  {
+    result->longest_uptime= uptime;
+    result->oldest_server= server_num;
+  }
+}
+
+static void calc_least_free_node(memcached_analysis_st *result,
+                                 const uint32_t server_num,
+                                 const uint64_t max_allowed_bytes,
+                                 const uint64_t used_bytes)
+{
+  uint64_t remaining_bytes= max_allowed_bytes - used_bytes;
+
+  if (result->least_remaining_bytes == 0 ||
+      remaining_bytes < result->least_remaining_bytes)
+  {
+    result->least_remaining_bytes= remaining_bytes;
+    result->least_free_server= server_num;
+  }
+}
+
+static void calc_average_item_size(memcached_analysis_st *result,
+                                   const uint64_t total_items,
+                                   const uint64_t total_bytes)
+{
+  if (total_items > 0 && total_bytes > 0)
+    result->average_item_size= (uint32_t) (total_bytes / total_items);
+}
+
+static void calc_hit_ratio(memcached_analysis_st *result,
+                           const uint64_t total_get_hits,
+                           const uint64_t total_get_cmds)
+{
+  if (total_get_hits == 0 || total_get_cmds == 0)
+  {
+    result->pool_hit_ratio= 0;
+    return;
+  }
+
+  double temp= (double) (total_get_hits/total_get_cmds);
+  result->pool_hit_ratio= temp * 100;
+}
+
+memcached_analysis_st *memcached_analyze(memcached_st *memc,
+                                         memcached_stat_st *memc_stat,
+                                         memcached_return_t *error)
+{
+  uint64_t total_items= 0, total_bytes= 0;
+  uint64_t total_get_cmds= 0, total_get_hits= 0;
+  uint32_t server_count, x;
+  memcached_analysis_st *result;
+
+  *error= MEMCACHED_SUCCESS;
+  server_count= memcached_server_count(memc);
+  result= (memcached_analysis_st*)calloc(memcached_server_count(memc),
+                                         sizeof(memcached_analysis_st));
+
+  if (!result)
+  {
+    *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+    return NULL;
+  }
+
+  result->root= memc;
+
+  for (x= 0; x < server_count; x++)
+  {
+    calc_largest_consumption(result, x, memc_stat[x].bytes);
+    calc_oldest_node(result, x, memc_stat[x].uptime);
+    calc_least_free_node(result, x,
+                         memc_stat[x].limit_maxbytes,
+                         memc_stat[x].bytes);
+
+    total_get_hits+= memc_stat[x].get_hits;
+    total_get_cmds+= memc_stat[x].cmd_get;
+    total_items+= memc_stat[x].curr_items;
+    total_bytes+= memc_stat[x].bytes;
+  }
+
+  calc_average_item_size(result, total_items, total_bytes);
+  calc_hit_ratio(result, total_get_hits, total_get_cmds);
+
+  return result;
+}
+
+void memcached_analyze_free(memcached_analysis_st *ptr)
+{
+  free(ptr);
+}
diff --git a/libmemcached/auto.c b/libmemcached/auto.c
deleted file mode 100644 (file)
index 325ddb6..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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: Methods for adding or decrementing values from an object in memcached
- *
- */
-
-#include "libmemcached/common.h"
-
-static memcached_return_t text_incr_decr(memcached_st *ptr,
-                                         const char *verb,
-                                         const char *group_key, size_t group_key_length,
-                                         const char *key, size_t key_length,
-                                         uint64_t offset,
-                                         uint64_t *value)
-{
-  memcached_return_t rc;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  uint32_t server_key;
-  memcached_server_write_instance_st instance;
-  bool no_reply= ptr->flags.no_reply;
-
-  if (memcached_server_count(ptr) == 0)
-    return memcached_set_error(ptr, MEMCACHED_NO_SERVERS, NULL);
-
-  if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
-    return MEMCACHED_BAD_KEY_PROVIDED;
-
-  server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
-  instance= memcached_server_instance_fetch(ptr, server_key);
-
-  int send_length;
-  send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                        "%s %.*s%.*s %" PRIu64 "%s\r\n", verb,
-                        memcached_print_array(ptr->prefix_key),
-                        (int)key_length, key,
-                        offset, no_reply ? " noreply" : "");
-  if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
-    return MEMCACHED_WRITE_FAILURE;
-
-  rc= memcached_do(instance, buffer, (size_t)send_length, true);
-  if (no_reply || rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-
-  /*
-    So why recheck responce? Because the protocol is brain dead :)
-    The number returned might end up equaling one of the string
-    values. Less chance of a mistake with strncmp() so we will
-    use it. We still called memcached_response() though since it
-    worked its magic for non-blocking IO.
-  */
-  if (! strncmp(buffer, "ERROR\r\n", 7))
-  {
-    *value= 0;
-    rc= MEMCACHED_PROTOCOL_ERROR;
-  }
-  else if (! strncmp(buffer, "CLIENT_ERROR\r\n", 14))
-  {
-    *value= 0;
-    rc= MEMCACHED_PROTOCOL_ERROR;
-  }
-  else if (!strncmp(buffer, "NOT_FOUND\r\n", 11))
-  {
-    *value= 0;
-    rc= MEMCACHED_NOTFOUND;
-  }
-  else
-  {
-    *value= strtoull(buffer, (char **)NULL, 10);
-    rc= MEMCACHED_SUCCESS;
-  }
-
-  return rc;
-}
-
-static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd,
-                                           const char *group_key, size_t group_key_length,
-                                           const char *key, size_t key_length,
-                                           uint64_t offset, uint64_t initial,
-                                           uint32_t expiration,
-                                           uint64_t *value)
-{
-  uint32_t server_key;
-  memcached_server_write_instance_st instance;
-  bool no_reply= ptr->flags.no_reply;
-
-  if (memcached_server_count(ptr) == 0)
-    return memcached_set_error(ptr, MEMCACHED_NO_SERVERS, NULL);
-
-  server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
-  instance= memcached_server_instance_fetch(ptr, server_key);
-
-  if (no_reply)
-  {
-    if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
-      cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;
-    if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
-      cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
-  }
-  protocol_binary_request_incr request= {.bytes= {0}};
-
-  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
-  request.message.header.request.opcode= cmd;
-  request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
-  request.message.header.request.extlen= 20;
-  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-  request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key) +request.message.header.request.extlen));
-  request.message.body.delta= htonll(offset);
-  request.message.body.initial= htonll(initial);
-  request.message.body.expiration= htonl((uint32_t) expiration);
-
-  struct libmemcached_io_vector_st vector[]=
-  {
-    { .length= sizeof(request.bytes), .buffer= request.bytes },
-    { .length= memcached_array_size(ptr->prefix_key), .buffer= ptr->prefix_key },
-    { .length= key_length, .buffer= key }
-  };
-
-  memcached_return_t rc;
-  if ((rc= memcached_vdo(instance, vector, 3, true)) != MEMCACHED_SUCCESS)
-  {
-    memcached_io_reset(instance);
-    return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
-  }
-
-  if (no_reply)
-    return MEMCACHED_SUCCESS;
-  return memcached_response(instance, (char*)value, sizeof(*value), NULL);
-}
-
-memcached_return_t memcached_increment(memcached_st *ptr,
-                                       const char *key, size_t key_length,
-                                       uint32_t offset,
-                                       uint64_t *value)
-{
-  uint64_t local_value;
-  if (! value)
-    value= &local_value;
-
-  return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
-}
-
-memcached_return_t memcached_decrement(memcached_st *ptr,
-                                       const char *key, size_t key_length,
-                                       uint32_t offset,
-                                       uint64_t *value)
-{
-  uint64_t local_value;
-  if (! value)
-    value= &local_value;
-
-  return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
-}
-
-memcached_return_t memcached_increment_by_key(memcached_st *ptr,
-                                              const char *group_key, size_t group_key_length,
-                                              const char *key, size_t key_length,
-                                              uint64_t offset,
-                                              uint64_t *value)
-{
-  memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  uint64_t local_value;
-  if (! value)
-    value= &local_value;
-
-  LIBMEMCACHED_MEMCACHED_INCREMENT_START();
-  if (ptr->flags.binary_protocol)
-  {
-    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
-                         group_key, group_key_length, key, key_length,
-                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
-                         value);
-  }
-  else
-  {
-     rc= text_incr_decr(ptr, "incr", group_key, group_key_length, key, key_length, offset, value);
-  }
-
-  LIBMEMCACHED_MEMCACHED_INCREMENT_END();
-
-  return rc;
-}
-
-memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
-                                              const char *group_key, size_t group_key_length,
-                                              const char *key, size_t key_length,
-                                              uint64_t offset,
-                                              uint64_t *value)
-{
-  memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  uint64_t local_value;
-  if (! value)
-    value= &local_value;
-
-  LIBMEMCACHED_MEMCACHED_DECREMENT_START();
-  if (ptr->flags.binary_protocol)
-  {
-    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
-                         group_key, group_key_length, key, key_length,
-                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
-                         value);
-  }
-  else
-  {
-    rc= text_incr_decr(ptr, "decr", group_key, group_key_length, key, key_length, offset, value);
-  }
-
-  LIBMEMCACHED_MEMCACHED_DECREMENT_END();
-
-  return rc;
-}
-
-memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
-                                                    const char *key,
-                                                    size_t key_length,
-                                                    uint64_t offset,
-                                                    uint64_t initial,
-                                                    time_t expiration,
-                                                    uint64_t *value)
-{
-  uint64_t local_value;
-  if (! value)
-    value= &local_value;
-
-  return memcached_increment_with_initial_by_key(ptr, key, key_length,
-                                                 key, key_length,
-                                                 offset, initial, expiration, value);
-}
-
-memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
-                                                         const char *group_key,
-                                                         size_t group_key_length,
-                                                         const char *key,
-                                                         size_t key_length,
-                                                         uint64_t offset,
-                                                         uint64_t initial,
-                                                         time_t expiration,
-                                                         uint64_t *value)
-{
-  memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  uint64_t local_value;
-  if (! value)
-    value= &local_value;
-
-  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
-  if (ptr->flags.binary_protocol)
-    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
-                         group_key, group_key_length, key, key_length,
-                         offset, initial, (uint32_t)expiration,
-                         value);
-  else
-    rc= MEMCACHED_PROTOCOL_ERROR;
-
-  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
-
-  return rc;
-}
-
-memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
-                                                    const char *key,
-                                                    size_t key_length,
-                                                    uint64_t offset,
-                                                    uint64_t initial,
-                                                    time_t expiration,
-                                                    uint64_t *value)
-{
-  uint64_t local_value;
-  if (! value)
-    value= &local_value;
-
-  return memcached_decrement_with_initial_by_key(ptr, key, key_length,
-                                                 key, key_length,
-                                                 offset, initial, expiration, value);
-}
-
-memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
-                                                           const char *group_key,
-                                                           size_t group_key_length,
-                                                           const char *key,
-                                                           size_t key_length,
-                                                           uint64_t offset,
-                                                           uint64_t initial,
-                                                           time_t expiration,
-                                                           uint64_t *value)
-{
-  memcached_return_t rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  uint64_t local_value;
-  if (! value)
-    value= &local_value;
-
-  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
-  if (ptr->flags.binary_protocol)
-  {
-    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
-                         group_key, group_key_length, key, key_length,
-                         offset, initial, (uint32_t)expiration,
-                         value);
-  }
-  else
-  {
-    rc= MEMCACHED_PROTOCOL_ERROR;
-  }
-
-  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
-
-  return rc;
-}
-
diff --git a/libmemcached/auto.cc b/libmemcached/auto.cc
new file mode 100644 (file)
index 0000000..42c3b5f
--- /dev/null
@@ -0,0 +1,380 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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>
+
+static memcached_return_t text_incr_decr(memcached_st *ptr,
+                                         const char *verb,
+                                         const char *group_key, size_t group_key_length,
+                                         const char *key, size_t key_length,
+                                         uint64_t offset,
+                                         uint64_t *value)
+{
+  memcached_return_t rc;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+  uint32_t server_key;
+  memcached_server_write_instance_st instance;
+  bool no_reply= ptr->flags.no_reply;
+
+  if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+    return MEMCACHED_BAD_KEY_PROVIDED;
+
+  server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
+  instance= memcached_server_instance_fetch(ptr, server_key);
+
+  int send_length;
+  send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                        "%s %.*s%.*s %" PRIu64 "%s\r\n", verb,
+                        memcached_print_array(ptr->prefix_key),
+                        (int)key_length, key,
+                        offset, no_reply ? " noreply" : "");
+  if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
+    return MEMCACHED_WRITE_FAILURE;
+
+  rc= memcached_do(instance, buffer, (size_t)send_length, true);
+  if (no_reply || rc != MEMCACHED_SUCCESS)
+    return rc;
+
+  rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+  /*
+    So why recheck responce? Because the protocol is brain dead :)
+    The number returned might end up equaling one of the string
+    values. Less chance of a mistake with strncmp() so we will
+    use it. We still called memcached_response() though since it
+    worked its magic for non-blocking IO.
+  */
+  if (! strncmp(buffer, "ERROR\r\n", 7))
+  {
+    *value= 0;
+    rc= MEMCACHED_PROTOCOL_ERROR;
+  }
+  else if (! strncmp(buffer, "CLIENT_ERROR\r\n", 14))
+  {
+    *value= 0;
+    rc= MEMCACHED_PROTOCOL_ERROR;
+  }
+  else if (!strncmp(buffer, "NOT_FOUND\r\n", 11))
+  {
+    *value= 0;
+    rc= MEMCACHED_NOTFOUND;
+  }
+  else
+  {
+    *value= strtoull(buffer, (char **)NULL, 10);
+    rc= MEMCACHED_SUCCESS;
+  }
+
+  return rc;
+}
+
+static memcached_return_t binary_incr_decr(memcached_st *ptr, uint8_t cmd,
+                                           const char *group_key, size_t group_key_length,
+                                           const char *key, size_t key_length,
+                                           uint64_t offset, uint64_t initial,
+                                           uint32_t expiration,
+                                           uint64_t *value)
+{
+  uint32_t server_key;
+  memcached_server_write_instance_st instance;
+  bool no_reply= ptr->flags.no_reply;
+
+  if (memcached_server_count(ptr) == 0)
+    return memcached_set_error(ptr, MEMCACHED_NO_SERVERS, NULL);
+
+  server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
+  instance= memcached_server_instance_fetch(ptr, server_key);
+
+  if (no_reply)
+  {
+    if(cmd == PROTOCOL_BINARY_CMD_DECREMENT)
+      cmd= PROTOCOL_BINARY_CMD_DECREMENTQ;
+    if(cmd == PROTOCOL_BINARY_CMD_INCREMENT)
+      cmd= PROTOCOL_BINARY_CMD_INCREMENTQ;
+  }
+  protocol_binary_request_incr request= {}; // = {.bytes= {0}};
+
+  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+  request.message.header.request.opcode= cmd;
+  request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
+  request.message.header.request.extlen= 20;
+  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+  request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key) +request.message.header.request.extlen));
+  request.message.body.delta= htonll(offset);
+  request.message.body.initial= htonll(initial);
+  request.message.body.expiration= htonl((uint32_t) expiration);
+
+  struct libmemcached_io_vector_st vector[]=
+  {
+    { sizeof(request.bytes), request.bytes },
+    { memcached_array_size(ptr->prefix_key), ptr->prefix_key },
+    { key_length, key }
+  };
+
+  memcached_return_t rc;
+  if ((rc= memcached_vdo(instance, vector, 3, true)) != MEMCACHED_SUCCESS)
+  {
+    memcached_io_reset(instance);
+    return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
+  }
+
+  if (no_reply)
+    return MEMCACHED_SUCCESS;
+
+  return memcached_response(instance, (char*)value, sizeof(*value), NULL);
+}
+
+memcached_return_t memcached_increment(memcached_st *ptr,
+                                       const char *key, size_t key_length,
+                                       uint32_t offset,
+                                       uint64_t *value)
+{
+  uint64_t local_value;
+  if (! value)
+    value= &local_value;
+
+  return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
+}
+
+memcached_return_t memcached_decrement(memcached_st *ptr,
+                                       const char *key, size_t key_length,
+                                       uint32_t offset,
+                                       uint64_t *value)
+{
+  uint64_t local_value;
+  if (! value)
+    value= &local_value;
+
+  return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
+}
+
+memcached_return_t memcached_increment_by_key(memcached_st *ptr,
+                                              const char *group_key, size_t group_key_length,
+                                              const char *key, size_t key_length,
+                                              uint64_t offset,
+                                              uint64_t *value)
+{
+  memcached_return_t rc;
+  uint64_t local_value;
+  if (not value)
+    value= &local_value;
+
+  if (memcached_failed(rc= initialize_query(ptr)))
+  {
+    return rc;
+  }
+
+  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
+  {
+    return rc;
+  }
+
+  LIBMEMCACHED_MEMCACHED_INCREMENT_START();
+  if (ptr->flags.binary_protocol)
+  {
+    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
+                         group_key, group_key_length, key, key_length,
+                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
+                         value);
+  }
+  else
+  {
+     rc= text_incr_decr(ptr, "incr", group_key, group_key_length, key, key_length, offset, value);
+  }
+
+  LIBMEMCACHED_MEMCACHED_INCREMENT_END();
+
+  return rc;
+}
+
+memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
+                                              const char *group_key, size_t group_key_length,
+                                              const char *key, size_t key_length,
+                                              uint64_t offset,
+                                              uint64_t *value)
+{
+  uint64_t local_value;
+  if (not value)
+    value= &local_value;
+
+  memcached_return_t rc;
+  if (memcached_failed(rc= initialize_query(ptr)))
+  {
+    return rc;
+  }
+
+  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
+  {
+    return rc;
+  }
+
+
+  LIBMEMCACHED_MEMCACHED_DECREMENT_START();
+  if (ptr->flags.binary_protocol)
+  {
+    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
+                         group_key, group_key_length, key, key_length,
+                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
+                         value);
+  }
+  else
+  {
+    rc= text_incr_decr(ptr, "decr", group_key, group_key_length, key, key_length, offset, value);
+  }
+
+  LIBMEMCACHED_MEMCACHED_DECREMENT_END();
+
+  return rc;
+}
+
+memcached_return_t memcached_increment_with_initial(memcached_st *ptr,
+                                                    const char *key,
+                                                    size_t key_length,
+                                                    uint64_t offset,
+                                                    uint64_t initial,
+                                                    time_t expiration,
+                                                    uint64_t *value)
+{
+  uint64_t local_value;
+  if (! value)
+    value= &local_value;
+
+  return memcached_increment_with_initial_by_key(ptr, key, key_length,
+                                                 key, key_length,
+                                                 offset, initial, expiration, value);
+}
+
+memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
+                                                         const char *group_key,
+                                                         size_t group_key_length,
+                                                         const char *key,
+                                                         size_t key_length,
+                                                         uint64_t offset,
+                                                         uint64_t initial,
+                                                         time_t expiration,
+                                                         uint64_t *value)
+{
+  uint64_t local_value;
+  if (not value)
+    value= &local_value;
+
+  memcached_return_t rc;
+  if (memcached_failed(rc= initialize_query(ptr)))
+  {
+    return rc;
+  }
+
+  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
+  {
+    return rc;
+  }
+
+  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
+  if (ptr->flags.binary_protocol)
+    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
+                         group_key, group_key_length, key, key_length,
+                         offset, initial, (uint32_t)expiration,
+                         value);
+  else
+    rc= MEMCACHED_PROTOCOL_ERROR;
+
+  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
+
+  return rc;
+}
+
+memcached_return_t memcached_decrement_with_initial(memcached_st *ptr,
+                                                    const char *key,
+                                                    size_t key_length,
+                                                    uint64_t offset,
+                                                    uint64_t initial,
+                                                    time_t expiration,
+                                                    uint64_t *value)
+{
+  uint64_t local_value;
+  if (! value)
+    value= &local_value;
+
+  return memcached_decrement_with_initial_by_key(ptr, key, key_length,
+                                                 key, key_length,
+                                                 offset, initial, expiration, value);
+}
+
+memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
+                                                           const char *group_key,
+                                                           size_t group_key_length,
+                                                           const char *key,
+                                                           size_t key_length,
+                                                           uint64_t offset,
+                                                           uint64_t initial,
+                                                           time_t expiration,
+                                                           uint64_t *value)
+{
+  uint64_t local_value;
+  if (not value)
+    value= &local_value;
+
+  memcached_return_t rc;
+  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
+  {
+    return rc;
+  }
+
+  if (memcached_failed(rc= initialize_query(ptr)))
+  {
+    return rc;
+  }
+
+
+  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
+  if (ptr->flags.binary_protocol)
+  {
+    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
+                         group_key, group_key_length, key, key_length,
+                         offset, initial, (uint32_t)expiration,
+                         value);
+  }
+  else
+  {
+    rc= MEMCACHED_PROTOCOL_ERROR;
+  }
+
+  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_END();
+
+  return rc;
+}
+
index 14ee90b54caa01740e8e10d533516b46956f1b41..f37d50fc253c265386b9579e7f2f287ff9833651 100644 (file)
@@ -1,16 +1,41 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 Brian Aker All rights reserved.
  *
- * Summary: Change the behavior of the memcached connection.
+ *  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.
  *
  */
 
-#ifndef __LIBMEMCACHED_AUTO_H__
-#define __LIBMEMCACHED_AUTO_H__
+#pragma once
 
 #ifdef __cplusplus
 extern "C" {
@@ -84,5 +109,3 @@ LIBMEMCACHED_API
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __LIBMEMCACHED_AUTO_H__ */
diff --git a/libmemcached/behavior.c b/libmemcached/behavior.c
deleted file mode 100644 (file)
index 91e33a0..0000000
+++ /dev/null
@@ -1,509 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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: Change the behavior of the memcached connection.
- *
- */
-
-#include <libmemcached/common.h>
-#include <libmemcached/virtual_bucket.h>
-
-#include <time.h>
-#include <sys/types.h>
-
-static bool set_flag(uint64_t data)
-{
-  // Wordy :)
-  return data ? true : false;
-}
-
-/*
-  This function is used to modify the behavior of running client.
-
-  We quit all connections so we can reset the sockets.
-*/
-
-memcached_return_t memcached_behavior_set(memcached_st *ptr,
-                                          const memcached_behavior_t flag,
-                                          uint64_t data)
-{
-  switch (flag)
-  {
-  case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
-    ptr->number_of_replicas= (uint32_t)data;
-    break;
-  case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
-    ptr->io_msg_watermark= (uint32_t) data;
-    break;
-  case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
-    ptr->io_bytes_watermark= (uint32_t)data;
-    break;
-  case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
-    ptr->io_key_prefetch = (uint32_t)data;
-    break;
-  case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
-    ptr->snd_timeout= (int32_t)data;
-    break;
-  case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
-    ptr->rcv_timeout= (int32_t)data;
-    break;
-
-  case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
-    ptr->flags.auto_eject_hosts= set_flag(data);
-  case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
-    ptr->server_failure_limit= (uint32_t)data;
-    break;
-
-  case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
-    send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol
-    if (data)
-    {
-      ptr->flags.verify_key= false;
-    }
-    ptr->flags.binary_protocol= set_flag(data);
-    break;
-  case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
-    ptr->flags.support_cas= set_flag(data);
-    break;
-  case MEMCACHED_BEHAVIOR_NO_BLOCK:
-    ptr->flags.no_block= set_flag(data);
-    send_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
-    ptr->flags.buffer_requests= set_flag(data);
-    send_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_USE_UDP:
-    if (memcached_server_count(ptr))
-    {
-      return MEMCACHED_FAILURE;
-    }
-    ptr->flags.use_udp= set_flag(data);
-    if (data)
-    {
-      ptr->flags.no_reply= set_flag(data);
-    }
-    break;
-  case MEMCACHED_BEHAVIOR_TCP_NODELAY:
-    ptr->flags.tcp_nodelay= set_flag(data);
-    send_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
-    ptr->flags.tcp_keepalive= set_flag(data);
-    send_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_DISTRIBUTION:
-    return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data);
-  case MEMCACHED_BEHAVIOR_KETAMA:
-    {
-      if (data) // Turn on
-        return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
-
-      return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA);
-    }
-  case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
-    {
-      (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5);
-      (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5);
-      ptr->ketama.weighted= set_flag(data);
-      /**
-        @note We try to keep the same distribution going. This should be deprecated and rewritten.
-      */
-      return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
-    }
-  case MEMCACHED_BEHAVIOR_HASH:
-    return memcached_behavior_set_key_hash(ptr, (memcached_hash_t)(data));
-  case MEMCACHED_BEHAVIOR_KETAMA_HASH:
-    return memcached_behavior_set_distribution_hash(ptr, (memcached_hash_t)(data));
-
-  case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
-    return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, 
-                                      memcached_string_with_size("MEMCACHED_BEHAVIOR_CACHE_LOOKUPS has been deprecated."));
-
-  case MEMCACHED_BEHAVIOR_VERIFY_KEY:
-    if (ptr->flags.binary_protocol)
-      return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, 
-                                        memcached_string_with_size("MEMCACHED_BEHAVIOR_VERIFY_KEY if the binary protocol has been enabled."));
-    ptr->flags.verify_key= set_flag(data);
-    break;
-  case MEMCACHED_BEHAVIOR_SORT_HOSTS:
-    {
-      ptr->flags.use_sort_hosts= set_flag(data);
-      run_distribution(ptr);
-
-      break;
-    }
-  case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
-    ptr->poll_timeout= (int32_t)data;
-    break;
-  case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
-    ptr->connect_timeout= (int32_t)data;
-    break;
-  case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
-    ptr->retry_timeout= (int32_t)data;
-    break;
-  case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
-    ptr->send_size= (int32_t)data;
-    send_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
-    ptr->recv_size= (int32_t)data;
-    send_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
-    ptr->tcp_keepidle= (uint32_t)data;
-    send_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_USER_DATA:
-    return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, 
-                                      memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
-  case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
-    ptr->flags.hash_with_prefix_key= set_flag(data);
-    break;
-  case MEMCACHED_BEHAVIOR_NOREPLY:
-    ptr->flags.no_reply= set_flag(data);
-    break;
-  case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
-    ptr->flags.auto_eject_hosts= set_flag(data);
-    break;
-  case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
-      srandom((uint32_t) time(NULL));
-      ptr->flags.randomize_replica_read= set_flag(data);
-      break;
-  case MEMCACHED_BEHAVIOR_CORK:
-      {
-        return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, 
-                                          memcached_string_with_size("MEMCACHED_BEHAVIOR_CORK is now incorporated into the driver by default."));
-      }
-      break;
-  case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
-      return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, 
-                                        memcached_string_with_size("MEMCACHED_BEHAVIOR_LOAD_FROM_FILE can not be set with memcached_behavior_set()"));
-  case MEMCACHED_BEHAVIOR_MAX:
-  default:
-    /* Shouldn't get here */
-    WATCHPOINT_ASSERT(0);
-    return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, 
-                                      memcached_string_with_size("Invalid behavior passed to memcached_behavior_set()"));
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-bool _is_auto_eject_host(const memcached_st *ptr)
-{
-  return ptr->flags.auto_eject_hosts;
-}
-
-uint64_t memcached_behavior_get(memcached_st *ptr,
-                                const memcached_behavior_t flag)
-{
-  switch (flag)
-  {
-  case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
-    return ptr->number_of_replicas;
-  case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
-    return ptr->io_msg_watermark;
-  case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
-    return ptr->io_bytes_watermark;
-  case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
-    return ptr->io_key_prefetch;
-  case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
-    return ptr->flags.binary_protocol;
-  case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
-    return ptr->flags.support_cas;
-
-  case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
-    return true;
-
-  case MEMCACHED_BEHAVIOR_NO_BLOCK:
-    return ptr->flags.no_block;
-  case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
-    return ptr->flags.buffer_requests;
-  case MEMCACHED_BEHAVIOR_USE_UDP:
-    return ptr->flags.use_udp;
-  case MEMCACHED_BEHAVIOR_TCP_NODELAY:
-    return ptr->flags.tcp_nodelay;
-  case MEMCACHED_BEHAVIOR_VERIFY_KEY:
-    return ptr->flags.verify_key;
-  case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
-    return ptr->ketama.weighted;
-  case MEMCACHED_BEHAVIOR_DISTRIBUTION:
-    return ptr->distribution;
-  case MEMCACHED_BEHAVIOR_KETAMA:
-    return (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) ? (uint64_t) 1 : 0;
-  case MEMCACHED_BEHAVIOR_HASH:
-    return hashkit_get_function(&ptr->hashkit);
-  case MEMCACHED_BEHAVIOR_KETAMA_HASH:
-    return hashkit_get_function(&ptr->distribution_hashkit);
-  case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
-  case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
-    return ptr->server_failure_limit;
-  case MEMCACHED_BEHAVIOR_SORT_HOSTS:
-    return ptr->flags.use_sort_hosts;
-  case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
-    return (uint64_t)ptr->poll_timeout;
-  case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
-    return (uint64_t)ptr->connect_timeout;
-  case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
-    return (uint64_t)ptr->retry_timeout;
-  case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
-    return (uint64_t)ptr->snd_timeout;
-  case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
-    return (uint64_t)ptr->rcv_timeout;
-  case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
-    return (uint64_t)ptr->tcp_keepidle;
-  case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
-    {
-      int sock_size= 0;
-      socklen_t sock_length= sizeof(int);
-      memcached_server_write_instance_st instance;
-
-      if (ptr->send_size != -1) // If value is -1 then we are using the default
-        return (uint64_t) ptr->send_size;
-
-      instance= memcached_server_instance_fetch(ptr, 0);
-
-      if (instance) // If we have an instance we test, otherwise we just set and pray
-      {
-        /* REFACTOR */
-        /* We just try the first host, and if it is down we return zero */
-        if ((memcached_connect(instance)) != MEMCACHED_SUCCESS)
-        {
-          return 0;
-        }
-
-        if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS)
-        {
-          return 0;
-        }
-
-        if (getsockopt(instance->fd, SOL_SOCKET, SO_SNDBUF, &sock_size, &sock_length) < 0)
-        {
-          memcached_set_errno(ptr, errno, NULL);
-          return 0; /* Zero means error */
-        }
-      }
-
-      return (uint64_t) sock_size;
-    }
-  case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
-    {
-      int sock_size= 0;
-      socklen_t sock_length= sizeof(int);
-      memcached_server_write_instance_st instance;
-
-      if (ptr->recv_size != -1) // If value is -1 then we are using the default
-        return (uint64_t) ptr->recv_size;
-
-      instance= memcached_server_instance_fetch(ptr, 0);
-
-      /**
-        @note REFACTOR
-      */
-      if (instance)
-      {
-        /* We just try the first host, and if it is down we return zero */
-        if ((memcached_connect(instance)) != MEMCACHED_SUCCESS)
-        {
-          return 0;
-        }
-
-        if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS)
-        {
-          return 0;
-        }
-
-        if (getsockopt(instance->fd, SOL_SOCKET, SO_RCVBUF, &sock_size, &sock_length) < 0)
-        {
-          memcached_set_errno(ptr, errno, NULL);
-          return 0; /* Zero means error */
-        }
-
-      }
-
-      return (uint64_t) sock_size;
-    }
-  case MEMCACHED_BEHAVIOR_USER_DATA:
-    memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, 
-                               memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
-    return 0;
-  case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
-    return ptr->flags.hash_with_prefix_key;
-  case MEMCACHED_BEHAVIOR_NOREPLY:
-    return ptr->flags.no_reply;
-  case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
-    return ptr->flags.auto_eject_hosts;
-  case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
-    return ptr->flags.randomize_replica_read;
-  case MEMCACHED_BEHAVIOR_CORK:
-#ifdef HAVE_MSG_MORE
-    return true;
-#else
-    return false;
-#endif
-  case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
-    return ptr->flags.tcp_keepalive;
-  case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
-    return ptr->configure.filename ? true : false;
-  case MEMCACHED_BEHAVIOR_MAX:
-  default:
-    WATCHPOINT_ASSERT(0); /* Programming mistake if it gets this far */
-    return 0;
-  }
-
-  /* NOTREACHED */
-}
-
-
-memcached_return_t memcached_behavior_set_distribution(memcached_st *ptr, memcached_server_distribution_t type)
-{
-  if (type < MEMCACHED_DISTRIBUTION_CONSISTENT_MAX)
-  {
-    if (MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED)
-    {
-      ptr->ketama.weighted= true;
-    }
-    else
-    {
-      ptr->ketama.weighted= false;
-    }
-    ptr->distribution= type;
-    run_distribution(ptr);
-    return MEMCACHED_SUCCESS;
-  }
-
-  return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
-                                    memcached_string_with_size("Invalid memcached_server_distribution_t"));
-}
-
-
-memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st *ptr)
-{
-  return ptr->distribution;
-}
-
-memcached_return_t memcached_behavior_set_key_hash(memcached_st *ptr, memcached_hash_t type)
-{
-  if (hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS)
-    return MEMCACHED_SUCCESS;
-
-  return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
-                                    memcached_string_with_size("Invalid memcached_hash_t()"));
-}
-
-memcached_hash_t memcached_behavior_get_key_hash(memcached_st *ptr)
-{
-  return (memcached_hash_t)hashkit_get_function(&ptr->hashkit);
-}
-
-memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *ptr, memcached_hash_t type)
-{
-  if (hashkit_set_function(&ptr->distribution_hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS)
-    return MEMCACHED_SUCCESS;
-
-  return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
-                                    memcached_string_with_size("Invalid memcached_hash_t()"));
-}
-
-memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *ptr)
-{
-  return (memcached_hash_t)hashkit_get_function(&ptr->distribution_hashkit);
-}
-
-const char *libmemcached_string_behavior(const memcached_behavior_t flag)
-{
-  switch (flag)
-  {
-  case MEMCACHED_BEHAVIOR_NO_BLOCK: return "MEMCACHED_BEHAVIOR_NO_BLOCK";
-  case MEMCACHED_BEHAVIOR_TCP_NODELAY: return "MEMCACHED_BEHAVIOR_TCP_NODELAY";
-  case MEMCACHED_BEHAVIOR_HASH: return "MEMCACHED_BEHAVIOR_HASH";
-  case MEMCACHED_BEHAVIOR_KETAMA: return "MEMCACHED_BEHAVIOR_KETAMA";
-  case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE";
-  case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE";
-  case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: return "MEMCACHED_BEHAVIOR_CACHE_LOOKUPS";
-  case MEMCACHED_BEHAVIOR_SUPPORT_CAS: return "MEMCACHED_BEHAVIOR_SUPPORT_CAS";
-  case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: return "MEMCACHED_BEHAVIOR_POLL_TIMEOUT";
-  case MEMCACHED_BEHAVIOR_DISTRIBUTION: return "MEMCACHED_BEHAVIOR_DISTRIBUTION";
-  case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: return "MEMCACHED_BEHAVIOR_BUFFER_REQUESTS";
-  case MEMCACHED_BEHAVIOR_USER_DATA: return "MEMCACHED_BEHAVIOR_USER_DATA";
-  case MEMCACHED_BEHAVIOR_SORT_HOSTS: return "MEMCACHED_BEHAVIOR_SORT_HOSTS";
-  case MEMCACHED_BEHAVIOR_VERIFY_KEY: return "MEMCACHED_BEHAVIOR_VERIFY_KEY";
-  case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: return "MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT";
-  case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: return "MEMCACHED_BEHAVIOR_RETRY_TIMEOUT";
-  case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: return "MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED";
-  case MEMCACHED_BEHAVIOR_KETAMA_HASH: return "MEMCACHED_BEHAVIOR_KETAMA_HASH";
-  case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: return "MEMCACHED_BEHAVIOR_BINARY_PROTOCOL";
-  case MEMCACHED_BEHAVIOR_SND_TIMEOUT: return "MEMCACHED_BEHAVIOR_SND_TIMEOUT";
-  case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: return "MEMCACHED_BEHAVIOR_RCV_TIMEOUT";
-  case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT";
-  case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK";
-  case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK";
-  case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: return "MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH";
-  case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: return "MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY";
-  case MEMCACHED_BEHAVIOR_NOREPLY: return "MEMCACHED_BEHAVIOR_NOREPLY";
-  case MEMCACHED_BEHAVIOR_USE_UDP: return "MEMCACHED_BEHAVIOR_USE_UDP";
-  case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: return "MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS";
-  case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: return "MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS";
-  case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: return "MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS";
-  case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: return "MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ";
-  case MEMCACHED_BEHAVIOR_CORK: return "MEMCACHED_BEHAVIOR_CORK";
-  case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: return "MEMCACHED_BEHAVIOR_TCP_KEEPALIVE";
-  case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: return "MEMCACHED_BEHAVIOR_TCP_KEEPIDLE";
-  case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: return "MEMCACHED_BEHAVIOR_LOAD_FROM_FILE";
-  default:
-  case MEMCACHED_BEHAVIOR_MAX: return "INVALID memcached_behavior_t";
-  }
-}
-
-const char *libmemcached_string_distribution(const memcached_server_distribution_t flag)
-{
-  switch (flag)
-  {
-  case MEMCACHED_DISTRIBUTION_MODULA: return "MEMCACHED_DISTRIBUTION_MODULA";
-  case MEMCACHED_DISTRIBUTION_CONSISTENT: return "MEMCACHED_DISTRIBUTION_CONSISTENT";
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA";
-  case MEMCACHED_DISTRIBUTION_RANDOM: return "MEMCACHED_DISTRIBUTION_RANDOM";
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY";
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: return "MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED";
-  case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: return "MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET";
-  default:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: return "INVALID memcached_server_distribution_t";
-  }
-}
-
-memcached_return_t memcached_bucket_set(memcached_st *self,
-                                        const uint32_t *host_map,
-                                        const uint32_t *forward_map,
-                                        const uint32_t buckets,
-                                        const uint32_t replicas)
-{
-  memcached_return_t rc;
-
-  if (! self)
-    return MEMCACHED_INVALID_ARGUMENTS;
-
-  if (! host_map)
-    return MEMCACHED_INVALID_ARGUMENTS;
-
-  memcached_server_distribution_t old;
-  old= memcached_behavior_get_distribution(self);
-
-  rc =memcached_behavior_set_distribution(self, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET);
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  rc= memcached_virtual_bucket_create(self, host_map, forward_map, buckets, replicas);
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    memcached_behavior_set_distribution(self, old);
-  }
-
-  return rc;
-}
diff --git a/libmemcached/behavior.cc b/libmemcached/behavior.cc
new file mode 100644 (file)
index 0000000..91e33a0
--- /dev/null
@@ -0,0 +1,509 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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: Change the behavior of the memcached connection.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <libmemcached/virtual_bucket.h>
+
+#include <time.h>
+#include <sys/types.h>
+
+static bool set_flag(uint64_t data)
+{
+  // Wordy :)
+  return data ? true : false;
+}
+
+/*
+  This function is used to modify the behavior of running client.
+
+  We quit all connections so we can reset the sockets.
+*/
+
+memcached_return_t memcached_behavior_set(memcached_st *ptr,
+                                          const memcached_behavior_t flag,
+                                          uint64_t data)
+{
+  switch (flag)
+  {
+  case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
+    ptr->number_of_replicas= (uint32_t)data;
+    break;
+  case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
+    ptr->io_msg_watermark= (uint32_t) data;
+    break;
+  case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
+    ptr->io_bytes_watermark= (uint32_t)data;
+    break;
+  case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
+    ptr->io_key_prefetch = (uint32_t)data;
+    break;
+  case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
+    ptr->snd_timeout= (int32_t)data;
+    break;
+  case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
+    ptr->rcv_timeout= (int32_t)data;
+    break;
+
+  case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
+    ptr->flags.auto_eject_hosts= set_flag(data);
+  case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
+    ptr->server_failure_limit= (uint32_t)data;
+    break;
+
+  case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
+    send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol
+    if (data)
+    {
+      ptr->flags.verify_key= false;
+    }
+    ptr->flags.binary_protocol= set_flag(data);
+    break;
+  case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
+    ptr->flags.support_cas= set_flag(data);
+    break;
+  case MEMCACHED_BEHAVIOR_NO_BLOCK:
+    ptr->flags.no_block= set_flag(data);
+    send_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
+    ptr->flags.buffer_requests= set_flag(data);
+    send_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_USE_UDP:
+    if (memcached_server_count(ptr))
+    {
+      return MEMCACHED_FAILURE;
+    }
+    ptr->flags.use_udp= set_flag(data);
+    if (data)
+    {
+      ptr->flags.no_reply= set_flag(data);
+    }
+    break;
+  case MEMCACHED_BEHAVIOR_TCP_NODELAY:
+    ptr->flags.tcp_nodelay= set_flag(data);
+    send_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
+    ptr->flags.tcp_keepalive= set_flag(data);
+    send_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_DISTRIBUTION:
+    return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data);
+  case MEMCACHED_BEHAVIOR_KETAMA:
+    {
+      if (data) // Turn on
+        return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
+
+      return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA);
+    }
+  case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
+    {
+      (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5);
+      (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5);
+      ptr->ketama.weighted= set_flag(data);
+      /**
+        @note We try to keep the same distribution going. This should be deprecated and rewritten.
+      */
+      return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
+    }
+  case MEMCACHED_BEHAVIOR_HASH:
+    return memcached_behavior_set_key_hash(ptr, (memcached_hash_t)(data));
+  case MEMCACHED_BEHAVIOR_KETAMA_HASH:
+    return memcached_behavior_set_distribution_hash(ptr, (memcached_hash_t)(data));
+
+  case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
+    return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, 
+                                      memcached_string_with_size("MEMCACHED_BEHAVIOR_CACHE_LOOKUPS has been deprecated."));
+
+  case MEMCACHED_BEHAVIOR_VERIFY_KEY:
+    if (ptr->flags.binary_protocol)
+      return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, 
+                                        memcached_string_with_size("MEMCACHED_BEHAVIOR_VERIFY_KEY if the binary protocol has been enabled."));
+    ptr->flags.verify_key= set_flag(data);
+    break;
+  case MEMCACHED_BEHAVIOR_SORT_HOSTS:
+    {
+      ptr->flags.use_sort_hosts= set_flag(data);
+      run_distribution(ptr);
+
+      break;
+    }
+  case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
+    ptr->poll_timeout= (int32_t)data;
+    break;
+  case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
+    ptr->connect_timeout= (int32_t)data;
+    break;
+  case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
+    ptr->retry_timeout= (int32_t)data;
+    break;
+  case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
+    ptr->send_size= (int32_t)data;
+    send_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
+    ptr->recv_size= (int32_t)data;
+    send_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
+    ptr->tcp_keepidle= (uint32_t)data;
+    send_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_USER_DATA:
+    return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, 
+                                      memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
+  case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
+    ptr->flags.hash_with_prefix_key= set_flag(data);
+    break;
+  case MEMCACHED_BEHAVIOR_NOREPLY:
+    ptr->flags.no_reply= set_flag(data);
+    break;
+  case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
+    ptr->flags.auto_eject_hosts= set_flag(data);
+    break;
+  case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
+      srandom((uint32_t) time(NULL));
+      ptr->flags.randomize_replica_read= set_flag(data);
+      break;
+  case MEMCACHED_BEHAVIOR_CORK:
+      {
+        return memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, 
+                                          memcached_string_with_size("MEMCACHED_BEHAVIOR_CORK is now incorporated into the driver by default."));
+      }
+      break;
+  case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
+      return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, 
+                                        memcached_string_with_size("MEMCACHED_BEHAVIOR_LOAD_FROM_FILE can not be set with memcached_behavior_set()"));
+  case MEMCACHED_BEHAVIOR_MAX:
+  default:
+    /* Shouldn't get here */
+    WATCHPOINT_ASSERT(0);
+    return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS, 
+                                      memcached_string_with_size("Invalid behavior passed to memcached_behavior_set()"));
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+bool _is_auto_eject_host(const memcached_st *ptr)
+{
+  return ptr->flags.auto_eject_hosts;
+}
+
+uint64_t memcached_behavior_get(memcached_st *ptr,
+                                const memcached_behavior_t flag)
+{
+  switch (flag)
+  {
+  case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
+    return ptr->number_of_replicas;
+  case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
+    return ptr->io_msg_watermark;
+  case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
+    return ptr->io_bytes_watermark;
+  case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
+    return ptr->io_key_prefetch;
+  case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
+    return ptr->flags.binary_protocol;
+  case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
+    return ptr->flags.support_cas;
+
+  case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
+    return true;
+
+  case MEMCACHED_BEHAVIOR_NO_BLOCK:
+    return ptr->flags.no_block;
+  case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
+    return ptr->flags.buffer_requests;
+  case MEMCACHED_BEHAVIOR_USE_UDP:
+    return ptr->flags.use_udp;
+  case MEMCACHED_BEHAVIOR_TCP_NODELAY:
+    return ptr->flags.tcp_nodelay;
+  case MEMCACHED_BEHAVIOR_VERIFY_KEY:
+    return ptr->flags.verify_key;
+  case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
+    return ptr->ketama.weighted;
+  case MEMCACHED_BEHAVIOR_DISTRIBUTION:
+    return ptr->distribution;
+  case MEMCACHED_BEHAVIOR_KETAMA:
+    return (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) ? (uint64_t) 1 : 0;
+  case MEMCACHED_BEHAVIOR_HASH:
+    return hashkit_get_function(&ptr->hashkit);
+  case MEMCACHED_BEHAVIOR_KETAMA_HASH:
+    return hashkit_get_function(&ptr->distribution_hashkit);
+  case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
+  case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
+    return ptr->server_failure_limit;
+  case MEMCACHED_BEHAVIOR_SORT_HOSTS:
+    return ptr->flags.use_sort_hosts;
+  case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
+    return (uint64_t)ptr->poll_timeout;
+  case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
+    return (uint64_t)ptr->connect_timeout;
+  case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
+    return (uint64_t)ptr->retry_timeout;
+  case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
+    return (uint64_t)ptr->snd_timeout;
+  case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
+    return (uint64_t)ptr->rcv_timeout;
+  case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
+    return (uint64_t)ptr->tcp_keepidle;
+  case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
+    {
+      int sock_size= 0;
+      socklen_t sock_length= sizeof(int);
+      memcached_server_write_instance_st instance;
+
+      if (ptr->send_size != -1) // If value is -1 then we are using the default
+        return (uint64_t) ptr->send_size;
+
+      instance= memcached_server_instance_fetch(ptr, 0);
+
+      if (instance) // If we have an instance we test, otherwise we just set and pray
+      {
+        /* REFACTOR */
+        /* We just try the first host, and if it is down we return zero */
+        if ((memcached_connect(instance)) != MEMCACHED_SUCCESS)
+        {
+          return 0;
+        }
+
+        if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS)
+        {
+          return 0;
+        }
+
+        if (getsockopt(instance->fd, SOL_SOCKET, SO_SNDBUF, &sock_size, &sock_length) < 0)
+        {
+          memcached_set_errno(ptr, errno, NULL);
+          return 0; /* Zero means error */
+        }
+      }
+
+      return (uint64_t) sock_size;
+    }
+  case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
+    {
+      int sock_size= 0;
+      socklen_t sock_length= sizeof(int);
+      memcached_server_write_instance_st instance;
+
+      if (ptr->recv_size != -1) // If value is -1 then we are using the default
+        return (uint64_t) ptr->recv_size;
+
+      instance= memcached_server_instance_fetch(ptr, 0);
+
+      /**
+        @note REFACTOR
+      */
+      if (instance)
+      {
+        /* We just try the first host, and if it is down we return zero */
+        if ((memcached_connect(instance)) != MEMCACHED_SUCCESS)
+        {
+          return 0;
+        }
+
+        if (memcached_io_wait_for_write(instance) != MEMCACHED_SUCCESS)
+        {
+          return 0;
+        }
+
+        if (getsockopt(instance->fd, SOL_SOCKET, SO_RCVBUF, &sock_size, &sock_length) < 0)
+        {
+          memcached_set_errno(ptr, errno, NULL);
+          return 0; /* Zero means error */
+        }
+
+      }
+
+      return (uint64_t) sock_size;
+    }
+  case MEMCACHED_BEHAVIOR_USER_DATA:
+    memcached_set_error_string(ptr, MEMCACHED_DEPRECATED, 
+                               memcached_string_with_size("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
+    return 0;
+  case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
+    return ptr->flags.hash_with_prefix_key;
+  case MEMCACHED_BEHAVIOR_NOREPLY:
+    return ptr->flags.no_reply;
+  case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
+    return ptr->flags.auto_eject_hosts;
+  case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
+    return ptr->flags.randomize_replica_read;
+  case MEMCACHED_BEHAVIOR_CORK:
+#ifdef HAVE_MSG_MORE
+    return true;
+#else
+    return false;
+#endif
+  case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
+    return ptr->flags.tcp_keepalive;
+  case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
+    return ptr->configure.filename ? true : false;
+  case MEMCACHED_BEHAVIOR_MAX:
+  default:
+    WATCHPOINT_ASSERT(0); /* Programming mistake if it gets this far */
+    return 0;
+  }
+
+  /* NOTREACHED */
+}
+
+
+memcached_return_t memcached_behavior_set_distribution(memcached_st *ptr, memcached_server_distribution_t type)
+{
+  if (type < MEMCACHED_DISTRIBUTION_CONSISTENT_MAX)
+  {
+    if (MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED)
+    {
+      ptr->ketama.weighted= true;
+    }
+    else
+    {
+      ptr->ketama.weighted= false;
+    }
+    ptr->distribution= type;
+    run_distribution(ptr);
+    return MEMCACHED_SUCCESS;
+  }
+
+  return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+                                    memcached_string_with_size("Invalid memcached_server_distribution_t"));
+}
+
+
+memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st *ptr)
+{
+  return ptr->distribution;
+}
+
+memcached_return_t memcached_behavior_set_key_hash(memcached_st *ptr, memcached_hash_t type)
+{
+  if (hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS)
+    return MEMCACHED_SUCCESS;
+
+  return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+                                    memcached_string_with_size("Invalid memcached_hash_t()"));
+}
+
+memcached_hash_t memcached_behavior_get_key_hash(memcached_st *ptr)
+{
+  return (memcached_hash_t)hashkit_get_function(&ptr->hashkit);
+}
+
+memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *ptr, memcached_hash_t type)
+{
+  if (hashkit_set_function(&ptr->distribution_hashkit, (hashkit_hash_algorithm_t)type) == HASHKIT_SUCCESS)
+    return MEMCACHED_SUCCESS;
+
+  return memcached_set_error_string(ptr, MEMCACHED_INVALID_ARGUMENTS,
+                                    memcached_string_with_size("Invalid memcached_hash_t()"));
+}
+
+memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *ptr)
+{
+  return (memcached_hash_t)hashkit_get_function(&ptr->distribution_hashkit);
+}
+
+const char *libmemcached_string_behavior(const memcached_behavior_t flag)
+{
+  switch (flag)
+  {
+  case MEMCACHED_BEHAVIOR_NO_BLOCK: return "MEMCACHED_BEHAVIOR_NO_BLOCK";
+  case MEMCACHED_BEHAVIOR_TCP_NODELAY: return "MEMCACHED_BEHAVIOR_TCP_NODELAY";
+  case MEMCACHED_BEHAVIOR_HASH: return "MEMCACHED_BEHAVIOR_HASH";
+  case MEMCACHED_BEHAVIOR_KETAMA: return "MEMCACHED_BEHAVIOR_KETAMA";
+  case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE";
+  case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE";
+  case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: return "MEMCACHED_BEHAVIOR_CACHE_LOOKUPS";
+  case MEMCACHED_BEHAVIOR_SUPPORT_CAS: return "MEMCACHED_BEHAVIOR_SUPPORT_CAS";
+  case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: return "MEMCACHED_BEHAVIOR_POLL_TIMEOUT";
+  case MEMCACHED_BEHAVIOR_DISTRIBUTION: return "MEMCACHED_BEHAVIOR_DISTRIBUTION";
+  case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: return "MEMCACHED_BEHAVIOR_BUFFER_REQUESTS";
+  case MEMCACHED_BEHAVIOR_USER_DATA: return "MEMCACHED_BEHAVIOR_USER_DATA";
+  case MEMCACHED_BEHAVIOR_SORT_HOSTS: return "MEMCACHED_BEHAVIOR_SORT_HOSTS";
+  case MEMCACHED_BEHAVIOR_VERIFY_KEY: return "MEMCACHED_BEHAVIOR_VERIFY_KEY";
+  case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: return "MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT";
+  case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: return "MEMCACHED_BEHAVIOR_RETRY_TIMEOUT";
+  case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: return "MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED";
+  case MEMCACHED_BEHAVIOR_KETAMA_HASH: return "MEMCACHED_BEHAVIOR_KETAMA_HASH";
+  case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: return "MEMCACHED_BEHAVIOR_BINARY_PROTOCOL";
+  case MEMCACHED_BEHAVIOR_SND_TIMEOUT: return "MEMCACHED_BEHAVIOR_SND_TIMEOUT";
+  case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: return "MEMCACHED_BEHAVIOR_RCV_TIMEOUT";
+  case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT";
+  case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK";
+  case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK";
+  case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: return "MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH";
+  case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: return "MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY";
+  case MEMCACHED_BEHAVIOR_NOREPLY: return "MEMCACHED_BEHAVIOR_NOREPLY";
+  case MEMCACHED_BEHAVIOR_USE_UDP: return "MEMCACHED_BEHAVIOR_USE_UDP";
+  case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: return "MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS";
+  case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: return "MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS";
+  case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: return "MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS";
+  case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: return "MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ";
+  case MEMCACHED_BEHAVIOR_CORK: return "MEMCACHED_BEHAVIOR_CORK";
+  case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: return "MEMCACHED_BEHAVIOR_TCP_KEEPALIVE";
+  case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: return "MEMCACHED_BEHAVIOR_TCP_KEEPIDLE";
+  case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: return "MEMCACHED_BEHAVIOR_LOAD_FROM_FILE";
+  default:
+  case MEMCACHED_BEHAVIOR_MAX: return "INVALID memcached_behavior_t";
+  }
+}
+
+const char *libmemcached_string_distribution(const memcached_server_distribution_t flag)
+{
+  switch (flag)
+  {
+  case MEMCACHED_DISTRIBUTION_MODULA: return "MEMCACHED_DISTRIBUTION_MODULA";
+  case MEMCACHED_DISTRIBUTION_CONSISTENT: return "MEMCACHED_DISTRIBUTION_CONSISTENT";
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA";
+  case MEMCACHED_DISTRIBUTION_RANDOM: return "MEMCACHED_DISTRIBUTION_RANDOM";
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY";
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: return "MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED";
+  case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: return "MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET";
+  default:
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: return "INVALID memcached_server_distribution_t";
+  }
+}
+
+memcached_return_t memcached_bucket_set(memcached_st *self,
+                                        const uint32_t *host_map,
+                                        const uint32_t *forward_map,
+                                        const uint32_t buckets,
+                                        const uint32_t replicas)
+{
+  memcached_return_t rc;
+
+  if (! self)
+    return MEMCACHED_INVALID_ARGUMENTS;
+
+  if (! host_map)
+    return MEMCACHED_INVALID_ARGUMENTS;
+
+  memcached_server_distribution_t old;
+  old= memcached_behavior_get_distribution(self);
+
+  rc =memcached_behavior_set_distribution(self, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET);
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    return rc;
+  }
+
+  rc= memcached_virtual_bucket_create(self, host_map, forward_map, buckets, replicas);
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    memcached_behavior_set_distribution(self, old);
+  }
+
+  return rc;
+}
diff --git a/libmemcached/byteorder.c b/libmemcached/byteorder.c
deleted file mode 100644 (file)
index 97d14f2..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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:
- *
- */
-
-#include "byteorder.h"
-
-/* Byte swap a 64-bit number. */
-#ifndef swap64
-static inline uint64_t swap64(uint64_t in)
-{
-#ifndef WORDS_BIGENDIAN
-  /* Little endian, flip the bytes around until someone makes a faster/better
-   * way to do this. */
-  uint64_t rv= 0;
-  for (uint8_t x= 0; x < 8; x++)
-  {
-    rv= (rv << 8) | (in & 0xff);
-    in >>= 8;
-  }
-  return rv;
-#else
-  /* big-endian machines don't need byte swapping */
-  return in;
-#endif // WORDS_BIGENDIAN
-}
-#endif
-
-uint64_t memcached_ntohll(uint64_t value)
-{
-  return swap64(value);
-}
-
-uint64_t memcached_htonll(uint64_t value)
-{
-  return swap64(value);
-}
diff --git a/libmemcached/byteorder.cc b/libmemcached/byteorder.cc
new file mode 100644 (file)
index 0000000..ab35a9e
--- /dev/null
@@ -0,0 +1,69 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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>
+
+/* Byte swap a 64-bit number. */
+#ifndef swap64
+static inline uint64_t swap64(uint64_t in)
+{
+#ifndef WORDS_BIGENDIAN
+  /* Little endian, flip the bytes around until someone makes a faster/better
+   * way to do this. */
+  uint64_t rv= 0;
+  for (uint8_t x= 0; x < 8; x++)
+  {
+    rv= (rv << 8) | (in & 0xff);
+    in >>= 8;
+  }
+  return rv;
+#else
+  /* big-endian machines don't need byte swapping */
+  return in;
+#endif // WORDS_BIGENDIAN
+}
+#endif
+
+uint64_t memcached_ntohll(uint64_t value)
+{
+  return swap64(value);
+}
+
+uint64_t memcached_htonll(uint64_t value)
+{
+  return swap64(value);
+}
index 90a71ee400003932746d479137a225b7f26e5140..f78790a83dce1822b196d4bd9f4c596d7955b5ed 100644 (file)
@@ -1,39 +1,62 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 Brian Aker All rights reserved.
  *
- * Summary:
+ *  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.
  *
  */
 
-#ifndef __LIBMEMCACHED_BYTEORDER_H__
-#define __LIBMEMCACHED_BYTEORDER_H__
-
-#include "config.h"
+#pragma once
 
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
 
-
-/* Define this here, which will turn on the visibilty controls while we're
- * building libmemcached.
- */
-#define BUILDING_LIBMEMCACHED 1
-
-#include "libmemcached/memcached.h"
-
 #ifndef HAVE_HTONLL
 #define ntohll(a) memcached_ntohll(a)
 #define htonll(a) memcached_htonll(a)
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 LIBMEMCACHED_LOCAL
 uint64_t memcached_ntohll(uint64_t);
 LIBMEMCACHED_LOCAL
 uint64_t memcached_htonll(uint64_t);
+#ifdef __cplusplus
+}
+#endif
+
 #endif
 
 #ifdef linux
@@ -47,5 +70,3 @@ uint64_t memcached_htonll(uint64_t);
 #undef htons
 #undef htonl
 #endif
-
-#endif /*__LIBMEMCACHED_BYTEORDER_H__ */
diff --git a/libmemcached/callback.c b/libmemcached/callback.c
deleted file mode 100644 (file)
index dcb3dde..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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: Change any of the possible callbacks.
- *
- */
-
-#include "libmemcached/common.h"
-#include <sys/types.h>
-
-/*
-  These functions provide data and function callback support
-*/
-
-memcached_return_t memcached_callback_set(memcached_st *ptr,
-                                          const memcached_callback_t flag,
-                                          void *data)
-{
-  switch (flag)
-  {
-  case MEMCACHED_CALLBACK_PREFIX_KEY:
-    {
-      return memcached_set_prefix_key(ptr, (char*)data, data ? strlen((char*)data) : 0);
-    }
-  case MEMCACHED_CALLBACK_USER_DATA:
-    {
-      ptr->user_data= data;
-      break;
-    }
-  case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
-    {
-      memcached_cleanup_fn func= *(memcached_cleanup_fn *)&data;
-      ptr->on_cleanup= func;
-      break;
-    }
-  case MEMCACHED_CALLBACK_CLONE_FUNCTION:
-    {
-      memcached_clone_fn func= *(memcached_clone_fn *)&data;
-      ptr->on_clone= func;
-      break;
-    }
-#ifdef MEMCACHED_ENABLE_DEPRECATED
-  case MEMCACHED_CALLBACK_MALLOC_FUNCTION:
-    {
-      memcached_malloc_function func= *(memcached_malloc_fn *)&data;
-      ptr->call_malloc= func;
-      break;
-    }
-  case MEMCACHED_CALLBACK_REALLOC_FUNCTION:
-    {
-      memcached_realloc_function func= *(memcached_realloc_fn *)&data;
-      ptr->call_realloc= func;
-      break;
-    }
-  case MEMCACHED_CALLBACK_FREE_FUNCTION:
-    {
-      memcached_free_function func= *(memcached_free_fn *)&data;
-      ptr->call_free= func;
-      break;
-    }
-#endif
-  case MEMCACHED_CALLBACK_GET_FAILURE:
-    {
-      memcached_trigger_key_fn func= *(memcached_trigger_key_fn *)&data;
-      ptr->get_key_failure= func;
-      break;
-    }
-  case MEMCACHED_CALLBACK_DELETE_TRIGGER:
-    {
-      memcached_trigger_delete_key_fn func= *(memcached_trigger_delete_key_fn *)&data;
-      ptr->delete_trigger= func;
-      break;
-    }
-  case MEMCACHED_CALLBACK_MAX:
-  default:
-    return MEMCACHED_FAILURE;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-void *memcached_callback_get(memcached_st *ptr,
-                             const memcached_callback_t flag,
-                             memcached_return_t *error)
-{
-  memcached_return_t local_error;
-
-  if (!error)
-    error = &local_error;
-
-  switch (flag)
-  {
-  case MEMCACHED_CALLBACK_PREFIX_KEY:
-    {
-      if (ptr->prefix_key)
-      {
-        *error= MEMCACHED_SUCCESS;
-        return (void *)memcached_array_string(ptr->prefix_key);
-      }
-      else
-      {
-        *error= MEMCACHED_FAILURE;
-        return NULL;
-      }
-    }
-  case MEMCACHED_CALLBACK_USER_DATA:
-    {
-      *error= ptr->user_data ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
-      return (void *)ptr->user_data;
-    }
-  case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
-    {
-      *error= ptr->on_cleanup ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
-      return *(void **)&ptr->on_cleanup;
-    }
-  case MEMCACHED_CALLBACK_CLONE_FUNCTION:
-    {
-      *error= ptr->on_clone ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
-      return *(void **)&ptr->on_clone;
-    }
-#ifdef MEMCACHED_ENABLE_DEPRECATED
-  case MEMCACHED_CALLBACK_MALLOC_FUNCTION:
-    {
-      *error= ptr->call_malloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
-      return *(void **)&ptr->call_malloc;
-    }
-  case MEMCACHED_CALLBACK_REALLOC_FUNCTION:
-    {
-      *error= ptr->call_realloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
-      return *(void **)&ptr->call_realloc;
-    }
-  case MEMCACHED_CALLBACK_FREE_FUNCTION:
-    {
-      *error= ptr->call_free ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
-      return *(void **)&ptr->call_free;
-    }
-#endif
-  case MEMCACHED_CALLBACK_GET_FAILURE:
-    {
-      *error= ptr->get_key_failure ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
-      return *(void **)&ptr->get_key_failure;
-    }
-  case MEMCACHED_CALLBACK_DELETE_TRIGGER:
-    {
-      *error= ptr->delete_trigger ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
-      return *(void **)&ptr->delete_trigger;
-    }
-  case MEMCACHED_CALLBACK_MAX:
-  default:
-    WATCHPOINT_ASSERT(0);
-    *error= MEMCACHED_FAILURE;
-    return NULL;
-  }
-}
diff --git a/libmemcached/callback.cc b/libmemcached/callback.cc
new file mode 100644 (file)
index 0000000..9818af4
--- /dev/null
@@ -0,0 +1,160 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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: Change any of the possible callbacks.
+ *
+ */
+
+#include <libmemcached/common.h>
+#include <sys/types.h>
+
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+
+/*
+  These functions provide data and function callback support
+*/
+
+memcached_return_t memcached_callback_set(memcached_st *ptr,
+                                          const memcached_callback_t flag,
+                                          void *data)
+{
+  switch (flag)
+  {
+  case MEMCACHED_CALLBACK_PREFIX_KEY:
+    {
+      return memcached_set_prefix_key(ptr, (char*)data, data ? strlen((char*)data) : 0);
+    }
+  case MEMCACHED_CALLBACK_USER_DATA:
+    {
+      ptr->user_data= data;
+      break;
+    }
+  case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
+    {
+      memcached_cleanup_fn func= *(memcached_cleanup_fn *)&data;
+      ptr->on_cleanup= func;
+      break;
+    }
+  case MEMCACHED_CALLBACK_CLONE_FUNCTION:
+    {
+      memcached_clone_fn func= *(memcached_clone_fn *)&data;
+      ptr->on_clone= func;
+      break;
+    }
+#ifdef MEMCACHED_ENABLE_DEPRECATED
+  case MEMCACHED_CALLBACK_MALLOC_FUNCTION:
+    {
+      memcached_malloc_function func= *(memcached_malloc_fn *)&data;
+      ptr->call_malloc= func;
+      break;
+    }
+  case MEMCACHED_CALLBACK_REALLOC_FUNCTION:
+    {
+      memcached_realloc_function func= *(memcached_realloc_fn *)&data;
+      ptr->call_realloc= func;
+      break;
+    }
+  case MEMCACHED_CALLBACK_FREE_FUNCTION:
+    {
+      memcached_free_function func= *(memcached_free_fn *)&data;
+      ptr->call_free= func;
+      break;
+    }
+#endif
+  case MEMCACHED_CALLBACK_GET_FAILURE:
+    {
+      memcached_trigger_key_fn func= *(memcached_trigger_key_fn *)&data;
+      ptr->get_key_failure= func;
+      break;
+    }
+  case MEMCACHED_CALLBACK_DELETE_TRIGGER:
+    {
+      memcached_trigger_delete_key_fn func= *(memcached_trigger_delete_key_fn *)&data;
+      ptr->delete_trigger= func;
+      break;
+    }
+  case MEMCACHED_CALLBACK_MAX:
+  default:
+    return MEMCACHED_FAILURE;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+void *memcached_callback_get(memcached_st *ptr,
+                             const memcached_callback_t flag,
+                             memcached_return_t *error)
+{
+  memcached_return_t local_error;
+
+  if (!error)
+    error = &local_error;
+
+  switch (flag)
+  {
+  case MEMCACHED_CALLBACK_PREFIX_KEY:
+    {
+      if (ptr->prefix_key)
+      {
+        *error= MEMCACHED_SUCCESS;
+        return (void *)memcached_array_string(ptr->prefix_key);
+      }
+      else
+      {
+        *error= MEMCACHED_FAILURE;
+        return NULL;
+      }
+    }
+  case MEMCACHED_CALLBACK_USER_DATA:
+    {
+      *error= ptr->user_data ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+      return (void *)ptr->user_data;
+    }
+  case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
+    {
+      *error= ptr->on_cleanup ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+      return *(void **)&ptr->on_cleanup;
+    }
+  case MEMCACHED_CALLBACK_CLONE_FUNCTION:
+    {
+      *error= ptr->on_clone ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+      return *(void **)&ptr->on_clone;
+    }
+#ifdef MEMCACHED_ENABLE_DEPRECATED
+  case MEMCACHED_CALLBACK_MALLOC_FUNCTION:
+    {
+      *error= ptr->call_malloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+      return *(void **)&ptr->call_malloc;
+    }
+  case MEMCACHED_CALLBACK_REALLOC_FUNCTION:
+    {
+      *error= ptr->call_realloc ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+      return *(void **)&ptr->call_realloc;
+    }
+  case MEMCACHED_CALLBACK_FREE_FUNCTION:
+    {
+      *error= ptr->call_free ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+      return *(void **)&ptr->call_free;
+    }
+#endif
+  case MEMCACHED_CALLBACK_GET_FAILURE:
+    {
+      *error= ptr->get_key_failure ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+      return *(void **)&ptr->get_key_failure;
+    }
+  case MEMCACHED_CALLBACK_DELETE_TRIGGER:
+    {
+      *error= ptr->delete_trigger ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
+      return *(void **)&ptr->delete_trigger;
+    }
+  case MEMCACHED_CALLBACK_MAX:
+  default:
+    WATCHPOINT_ASSERT(0);
+    *error= MEMCACHED_FAILURE;
+    return NULL;
+  }
+}
index 4c3a95f4ff270004250c49df212e4a21561a5ba2..b4da80802c2dac996d0dcbe1fa131ff17f613812 100644 (file)
@@ -9,6 +9,7 @@
  *
  */
 
+#pragma once
 #ifndef __LIBMEMCACHED_CALLBACK_H__
 #define __LIBMEMCACHED_CALLBACK_H__
 
index d0a4ab4ce69d6cfc7717e70ceb34090c27b4a523..ec58fd8e2cc9c4b89cdb34c28c991cce11b66f03 100644 (file)
 # endif
 #endif
 
-/* Define this here, which will turn on the visibilty controls while we're
- * building libmemcached.
- */
-#define BUILDING_LIBMEMCACHED 1
-
 
 #include <libmemcached/memcached.h>
 #include <libmemcached/watchpoint.h>
 #include <libmemcached/is.h>
-#include <libmemcached/prefix_key.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 typedef struct memcached_server_st * memcached_server_write_instance_st;
 
@@ -87,6 +85,9 @@ LIBMEMCACHED_LOCAL
 memcached_return_t memcached_server_execute(memcached_st *ptr,
                                             memcached_server_execute_fn callback,
                                             void *context);
+#ifdef __cplusplus
+} // extern "C"
+#endif
 
 
 /* These are private not to be installed headers */
diff --git a/libmemcached/connect.c b/libmemcached/connect.c
deleted file mode 100644 (file)
index a7b17f0..0000000
+++ /dev/null
@@ -1,578 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-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: Server IO, Not public!
- *
- */
-
-#include <libmemcached/common.h>
-#include <assert.h>
-#include <sys/time.h>
-#include <time.h>
-
-static memcached_return_t connect_poll(memcached_server_st *ptr)
-{
-  struct pollfd fds[1];
-  fds[0].fd = ptr->fd;
-  fds[0].events = POLLOUT;
-
-  int error;
-  size_t loop_max= 5;
-
-  while (--loop_max) // Should only loop on cases of ERESTART or EINTR
-  {
-    error= poll(fds, 1, ptr->root->connect_timeout);
-
-    switch (error)
-    {
-    case 1:
-      {
-        int err;
-        socklen_t len= sizeof (err);
-        (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
-
-        // We check the value to see what happened wth the socket.
-        if (err == 0)
-        {
-          return MEMCACHED_SUCCESS;
-        }
-        else
-        {
-          ptr->cached_errno= errno;
-
-          return MEMCACHED_ERRNO;
-        }
-      }
-    case 0:
-      return MEMCACHED_TIMEOUT;
-    default: // A real error occurred and we need to completely bail
-      WATCHPOINT_ERRNO(get_socket_errno());
-      switch (get_socket_errno())
-      {
-#ifdef TARGET_OS_LINUX
-      case ERESTART:
-#endif
-      case EINTR:
-        continue;
-      default:
-        if (fds[0].revents & POLLERR)
-        {
-          int err;
-          socklen_t len= sizeof (err);
-          (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
-          ptr->cached_errno= (err == 0) ? get_socket_errno() : err;
-        }
-        else
-        {
-          ptr->cached_errno= get_socket_errno();
-        }
-
-        (void)closesocket(ptr->fd);
-        ptr->fd= INVALID_SOCKET;
-
-        return MEMCACHED_ERRNO;
-      }
-    }
-  }
-
-  // This should only be possible from ERESTART or EINTR;
-  ptr->cached_errno= get_socket_errno();
-
-  return MEMCACHED_ERRNO;
-}
-
-static memcached_return_t set_hostinfo(memcached_server_st *server)
-{
-  struct addrinfo hints;
-  char str_port[NI_MAXSERV];
-
-  assert(! server->address_info); // We cover the case where a programming mistake has been made.
-  if (server->address_info)
-  {
-    freeaddrinfo(server->address_info);
-    server->address_info= NULL;
-    server->address_info_next= NULL;
-  }
-
-  int length= snprintf(str_port, NI_MAXSERV, "%u", (uint32_t)server->port);
-  if (length >= NI_MAXSERV || length < 0)
-    return MEMCACHED_FAILURE;
-
-  memset(&hints, 0, sizeof(hints));
-
-#if 0
-  hints.ai_family= AF_INET;
-#endif
-  if (server->type == MEMCACHED_CONNECTION_UDP)
-  {
-    hints.ai_protocol= IPPROTO_UDP;
-    hints.ai_socktype= SOCK_DGRAM;
-  }
-  else
-  {
-    hints.ai_socktype= SOCK_STREAM;
-    hints.ai_protocol= IPPROTO_TCP;
-  }
-
-  uint32_t counter= 5;
-  while (--counter)
-  {
-    int e= getaddrinfo(server->hostname, str_port, &hints, &server->address_info);
-
-    if (e == 0)
-    {
-      break;
-    }
-    else if (e == EAI_AGAIN)
-    {
-#ifndef WIN32
-      struct timespec dream, rem;
-
-      dream.tv_nsec= 1000;
-      dream.tv_sec= 0;
-
-      nanosleep(&dream, &rem);
-#endif
-      continue;
-    }
-    else
-    {
-      WATCHPOINT_STRING(server->hostname);
-      WATCHPOINT_STRING(gai_strerror(e));
-      return MEMCACHED_HOST_LOOKUP_FAILURE;
-    }
-  }
-
-  server->address_info_next= server->address_info;
-
-  return MEMCACHED_SUCCESS;
-}
-
-static inline memcached_return_t set_socket_nonblocking(memcached_server_st *ptr)
-{
-#ifdef WIN32
-  u_long arg = 1;
-  if (ioctlsocket(ptr->fd, FIONBIO, &arg) == SOCKET_ERROR)
-  {
-    ptr->cached_errno= get_socket_errno();
-    return MEMCACHED_CONNECTION_FAILURE;
-  }
-#else
-  int flags;
-
-  do
-  {
-    flags= fcntl(ptr->fd, F_GETFL, 0);
-  }
-  while (flags == -1 && (errno == EINTR || errno == EAGAIN));
-
-  unlikely (flags == -1)
-  {
-    ptr->cached_errno= errno;
-    return MEMCACHED_CONNECTION_FAILURE;
-  }
-  else if ((flags & O_NONBLOCK) == 0)
-  {
-    int rval;
-
-    do
-    {
-      rval= fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK);
-    }
-    while (rval == -1 && (errno == EINTR || errno == EAGAIN));
-
-    unlikely (rval == -1)
-    {
-      ptr->cached_errno= errno;
-      return MEMCACHED_CONNECTION_FAILURE;
-    }
-  }
-#endif
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t set_socket_options(memcached_server_st *ptr)
-{
-  WATCHPOINT_ASSERT(ptr->fd != -1);
-
-  if (ptr->type == MEMCACHED_CONNECTION_UDP)
-    return MEMCACHED_SUCCESS;
-
-#ifdef HAVE_SNDTIMEO
-  if (ptr->root->snd_timeout)
-  {
-    int error;
-    struct timeval waittime;
-
-    waittime.tv_sec= 0;
-    waittime.tv_usec= ptr->root->snd_timeout;
-
-    error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDTIMEO,
-                      &waittime, (socklen_t)sizeof(struct timeval));
-    WATCHPOINT_ASSERT(error == 0);
-    if (error)
-      return MEMCACHED_FAILURE;
-  }
-#endif
-
-#ifdef HAVE_RCVTIMEO
-  if (ptr->root->rcv_timeout)
-  {
-    int error;
-    struct timeval waittime;
-
-    waittime.tv_sec= 0;
-    waittime.tv_usec= ptr->root->rcv_timeout;
-
-    error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO,
-                      &waittime, (socklen_t)sizeof(struct timeval));
-    WATCHPOINT_ASSERT(error == 0);
-    if (error)
-      return MEMCACHED_FAILURE;
-  }
-#endif
-
-
-#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
-  {
-    int set = 1;
-    int error= setsockopt(ptr->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
-
-    // This is not considered a fatal error
-    if (error == -1)
-    {
-      WATCHPOINT_ERRNO(get_socket_errno());
-      perror("setsockopt(SO_NOSIGPIPE)");
-    }
-  }
-#endif
-
-  if (ptr->root->flags.no_block)
-  {
-    int error;
-    struct linger linger;
-
-    linger.l_onoff= 1;
-    linger.l_linger= 0; /* By default on close() just drop the socket */
-    error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER,
-                      &linger, (socklen_t)sizeof(struct linger));
-    WATCHPOINT_ASSERT(error == 0);
-    if (error)
-      return MEMCACHED_FAILURE;
-  }
-
-  if (ptr->root->flags.tcp_nodelay)
-  {
-    int flag= 1;
-    int error;
-
-    error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY,
-                      &flag, (socklen_t)sizeof(int));
-    WATCHPOINT_ASSERT(error == 0);
-    if (error)
-      return MEMCACHED_FAILURE;
-  }
-
-  if (ptr->root->flags.tcp_keepalive)
-  {
-    int flag= 1;
-    int error;
-
-    error= setsockopt(ptr->fd, SOL_SOCKET, SO_KEEPALIVE,
-                      &flag, (socklen_t)sizeof(int));
-    WATCHPOINT_ASSERT(error == 0);
-    if (error)
-      return MEMCACHED_FAILURE;
-  }
-
-#ifdef TCP_KEEPIDLE
-  if (ptr->root->tcp_keepidle > 0)
-  {
-    int error;
-
-    error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_KEEPIDLE,
-                      &ptr->root->tcp_keepidle, (socklen_t)sizeof(int));
-    WATCHPOINT_ASSERT(error == 0);
-    if (error)
-      return MEMCACHED_FAILURE;
-  }
-#endif
-
-  if (ptr->root->send_size > 0)
-  {
-    int error;
-
-    error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF,
-                      &ptr->root->send_size, (socklen_t)sizeof(int));
-    WATCHPOINT_ASSERT(error == 0);
-    if (error)
-      return MEMCACHED_FAILURE;
-  }
-
-  if (ptr->root->recv_size > 0)
-  {
-    int error;
-
-    error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVBUF,
-                      &ptr->root->recv_size, (socklen_t)sizeof(int));
-    WATCHPOINT_ASSERT(error == 0);
-    if (error)
-      return MEMCACHED_FAILURE;
-  }
-
-
-  /* libmemcached will always use nonblocking IO to avoid write deadlocks */
-  return set_socket_nonblocking(ptr);
-}
-
-static memcached_return_t unix_socket_connect(memcached_server_st *ptr)
-{
-#ifndef WIN32
-  struct sockaddr_un servAddr;
-
-  WATCHPOINT_ASSERT(ptr->fd == -1);
-
-  if ((ptr->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
-  {
-    ptr->cached_errno= errno;
-    return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
-  }
-
-  memset(&servAddr, 0, sizeof (struct sockaddr_un));
-  servAddr.sun_family= AF_UNIX;
-  strncpy(servAddr.sun_path, ptr->hostname, sizeof(servAddr.sun_path)); /* Copy filename */
-
-test_connect:
-  if (connect(ptr->fd,
-              (struct sockaddr *)&servAddr,
-              sizeof(servAddr)) < 0)
-  {
-    switch (errno)
-    {
-    case EINPROGRESS:
-    case EALREADY:
-    case EINTR:
-      goto test_connect;
-    case EISCONN: /* We were spinning waiting on connect */
-      break;
-    default:
-      WATCHPOINT_ERRNO(errno);
-      ptr->cached_errno= errno;
-      return MEMCACHED_ERRNO;
-    }
-  }
-
-  WATCHPOINT_ASSERT(ptr->fd != -1);
-
-  return MEMCACHED_SUCCESS;
-#else
-  (void)ptr;
-  return MEMCACHED_NOT_SUPPORTED;
-#endif
-}
-
-static memcached_return_t network_connect(memcached_server_st *ptr)
-{
-  bool timeout_error_occured= false;
-
-  WATCHPOINT_ASSERT(ptr->fd == INVALID_SOCKET);
-  WATCHPOINT_ASSERT(ptr->cursor_active == 0);
-
-  if (! ptr->address_info)
-  {
-    memcached_return_t rc= set_hostinfo(ptr);
-    if (rc != MEMCACHED_SUCCESS)
-      return rc;
-  }
-
-  /* Create the socket */
-  while (ptr->address_info_next && ptr->fd == INVALID_SOCKET)
-  {
-    /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
-    if (ptr->type == MEMCACHED_CONNECTION_UDP && ptr->address_info_next->ai_family != AF_INET)
-    {
-      ptr->address_info_next= ptr->address_info_next->ai_next;
-      continue;
-    }
-
-    if ((ptr->fd= socket(ptr->address_info_next->ai_family,
-                         ptr->address_info_next->ai_socktype,
-                         ptr->address_info_next->ai_protocol)) < 0)
-    {
-      ptr->cached_errno= get_socket_errno();
-      WATCHPOINT_ERRNO(get_socket_errno());
-      return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
-    }
-
-    (void)set_socket_options(ptr);
-
-    /* connect to server */
-    if ((connect(ptr->fd, ptr->address_info_next->ai_addr, ptr->address_info_next->ai_addrlen) != SOCKET_ERROR))
-    {
-      break; // Success
-    }
-
-    /* An error occurred */
-    ptr->cached_errno= get_socket_errno();
-    switch (ptr->cached_errno) 
-    {
-    case EWOULDBLOCK:
-    case EINPROGRESS: // nonblocking mode - first return
-    case EALREADY: // nonblocking mode - subsequent returns
-      {
-        memcached_return_t rc;
-        rc= connect_poll(ptr);
-
-        if (rc == MEMCACHED_TIMEOUT)
-          timeout_error_occured= true;
-
-        if (rc == MEMCACHED_SUCCESS)
-          break;
-      }
-
-    case EISCONN: // we are connected :-)
-      break;
-
-    case EINTR: // Special case, we retry ai_addr
-      (void)closesocket(ptr->fd);
-      ptr->fd= INVALID_SOCKET;
-      continue;
-
-    default:
-      (void)closesocket(ptr->fd);
-      ptr->fd= INVALID_SOCKET;
-      ptr->address_info_next= ptr->address_info_next->ai_next;
-      break;
-    }
-  }
-
-  if (ptr->fd == INVALID_SOCKET)
-  {
-    WATCHPOINT_STRING("Never got a good file descriptor");
-
-    /* Failed to connect. schedule next retry */
-    if (ptr->root->retry_timeout)
-    {
-      struct timeval next_time;
-
-      if (gettimeofday(&next_time, NULL) == 0)
-        ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout;
-    }
-
-    if (timeout_error_occured)
-      return MEMCACHED_TIMEOUT;
-
-    return MEMCACHED_ERRNO; /* The last error should be from connect() */
-  }
-
-  return MEMCACHED_SUCCESS; /* The last error should be from connect() */
-}
-
-void set_last_disconnected_host(memcached_server_write_instance_st ptr)
-{
-  // const_cast
-  memcached_st *root= (memcached_st *)ptr->root;
-
-#if 0
-  WATCHPOINT_STRING(ptr->hostname);
-  WATCHPOINT_NUMBER(ptr->port);
-  WATCHPOINT_ERRNO(ptr->cached_errno);
-#endif
-  if (root->last_disconnected_server)
-    memcached_server_free(root->last_disconnected_server);
-  root->last_disconnected_server= memcached_server_clone(NULL, ptr);
-}
-
-memcached_return_t memcached_connect(memcached_server_write_instance_st ptr)
-{
-  memcached_return_t rc= MEMCACHED_NO_SERVERS;
-
-  if (ptr->fd != INVALID_SOCKET)
-    return MEMCACHED_SUCCESS;
-
-  LIBMEMCACHED_MEMCACHED_CONNECT_START();
-
-  /* both retry_timeout and server_failure_limit must be set in order to delay retrying a server on error. */
-  WATCHPOINT_ASSERT(ptr->root);
-  if (ptr->root->retry_timeout && ptr->next_retry)
-  {
-    struct timeval curr_time;
-
-    gettimeofday(&curr_time, NULL);
-
-    // We should optimize this to remove the allocation if the server was
-    // the last server to die
-    if (ptr->next_retry > curr_time.tv_sec)
-    {
-      set_last_disconnected_host(ptr);
-
-      return MEMCACHED_SERVER_MARKED_DEAD;
-    }
-  }
-
-  // If we are over the counter failure, we just fail. Reject host only
-  // works if you have a set number of failures.
-  if (ptr->root->server_failure_limit && ptr->server_failure_counter >= ptr->root->server_failure_limit)
-  {
-    set_last_disconnected_host(ptr);
-
-    // @todo fix this by fixing behavior to no longer make use of
-    // memcached_st
-    if (_is_auto_eject_host(ptr->root))
-    {
-      run_distribution((memcached_st *)ptr->root);
-    }
-
-    return MEMCACHED_SERVER_MARKED_DEAD;
-  }
-
-  /* We need to clean up the multi startup piece */
-  switch (ptr->type)
-  {
-  case MEMCACHED_CONNECTION_UNKNOWN:
-    WATCHPOINT_ASSERT(0);
-    rc= MEMCACHED_NOT_SUPPORTED;
-    break;
-  case MEMCACHED_CONNECTION_UDP:
-  case MEMCACHED_CONNECTION_TCP:
-    rc= network_connect(ptr);
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
-    if (ptr->fd != INVALID_SOCKET && ptr->root->sasl.callbacks)
-    {
-      rc= memcached_sasl_authenticate_connection(ptr);
-      if (rc != MEMCACHED_SUCCESS)
-      {
-        (void)closesocket(ptr->fd);
-        ptr->fd= INVALID_SOCKET;
-      }
-    }
-#endif
-    break;
-  case MEMCACHED_CONNECTION_UNIX_SOCKET:
-    rc= unix_socket_connect(ptr);
-    break;
-  case MEMCACHED_CONNECTION_MAX:
-  default:
-    WATCHPOINT_ASSERT(0);
-  }
-
-  if (rc == MEMCACHED_SUCCESS)
-  {
-    ptr->server_failure_counter= 0;
-    ptr->next_retry= 0;
-  }
-  else
-  {
-    ptr->server_failure_counter++;
-
-    set_last_disconnected_host(ptr);
-  }
-
-  LIBMEMCACHED_MEMCACHED_CONNECT_END();
-
-  return rc;
-}
diff --git a/libmemcached/connect.cc b/libmemcached/connect.cc
new file mode 100644 (file)
index 0000000..1914bc0
--- /dev/null
@@ -0,0 +1,605 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-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 <assert.h>
+#include <sys/time.h>
+#include <time.h>
+
+static memcached_return_t connect_poll(memcached_server_st *ptr)
+{
+  struct pollfd fds[1];
+  fds[0].fd = ptr->fd;
+  fds[0].events = POLLOUT;
+
+  int error;
+  size_t loop_max= 5;
+
+  while (--loop_max) // Should only loop on cases of ERESTART or EINTR
+  {
+    error= poll(fds, 1, ptr->root->connect_timeout);
+
+    switch (error)
+    {
+    case 1:
+      {
+        int err;
+        socklen_t len= sizeof (err);
+        (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
+
+        // We check the value to see what happened wth the socket.
+        if (err == 0)
+        {
+          return MEMCACHED_SUCCESS;
+        }
+        else
+        {
+          ptr->cached_errno= errno;
+
+          return MEMCACHED_ERRNO;
+        }
+      }
+    case 0:
+      return MEMCACHED_TIMEOUT;
+    default: // A real error occurred and we need to completely bail
+      WATCHPOINT_ERRNO(get_socket_errno());
+      switch (get_socket_errno())
+      {
+#ifdef TARGET_OS_LINUX
+      case ERESTART:
+#endif
+      case EINTR:
+        continue;
+      default:
+        if (fds[0].revents & POLLERR)
+        {
+          int err;
+          socklen_t len= sizeof (err);
+          (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
+          ptr->cached_errno= (err == 0) ? get_socket_errno() : err;
+        }
+        else
+        {
+          ptr->cached_errno= get_socket_errno();
+        }
+
+        (void)closesocket(ptr->fd);
+        ptr->fd= INVALID_SOCKET;
+
+        return MEMCACHED_ERRNO;
+      }
+    }
+  }
+
+  // This should only be possible from ERESTART or EINTR;
+  ptr->cached_errno= get_socket_errno();
+
+  return MEMCACHED_ERRNO;
+}
+
+static memcached_return_t set_hostinfo(memcached_server_st *server)
+{
+  char str_port[NI_MAXSERV];
+
+  assert(! server->address_info); // We cover the case where a programming mistake has been made.
+  if (server->address_info)
+  {
+    freeaddrinfo(server->address_info);
+    server->address_info= NULL;
+    server->address_info_next= NULL;
+  }
+
+  int length= snprintf(str_port, NI_MAXSERV, "%u", (uint32_t)server->port);
+  if (length >= NI_MAXSERV || length < 0)
+    return MEMCACHED_FAILURE;
+
+  struct addrinfo hints;
+  memset(&hints, 0, sizeof(struct addrinfo));
+
+#if 0
+  hints.ai_family= AF_INET;
+#endif
+  if (server->type == MEMCACHED_CONNECTION_UDP)
+  {
+    hints.ai_protocol= IPPROTO_UDP;
+    hints.ai_socktype= SOCK_DGRAM;
+  }
+  else
+  {
+    hints.ai_socktype= SOCK_STREAM;
+    hints.ai_protocol= IPPROTO_TCP;
+  }
+
+  uint32_t counter= 5;
+  while (--counter)
+  {
+    int e= getaddrinfo(server->hostname, str_port, &hints, &server->address_info);
+
+    if (e == 0)
+    {
+      break;
+    }
+    else if (e == EAI_AGAIN)
+    {
+#ifndef WIN32
+      struct timespec dream, rem;
+
+      dream.tv_nsec= 1000;
+      dream.tv_sec= 0;
+
+      nanosleep(&dream, &rem);
+#endif
+      continue;
+    }
+    else
+    {
+      WATCHPOINT_STRING(server->hostname);
+      WATCHPOINT_STRING(gai_strerror(e));
+      return MEMCACHED_HOST_LOOKUP_FAILURE;
+    }
+  }
+
+  server->address_info_next= server->address_info;
+
+  return MEMCACHED_SUCCESS;
+}
+
+static inline memcached_return_t set_socket_nonblocking(memcached_server_st *ptr)
+{
+#ifdef WIN32
+  u_long arg = 1;
+  if (ioctlsocket(ptr->fd, FIONBIO, &arg) == SOCKET_ERROR)
+  {
+    ptr->cached_errno= get_socket_errno();
+    return MEMCACHED_CONNECTION_FAILURE;
+  }
+#else
+  int flags;
+
+  do
+  {
+    flags= fcntl(ptr->fd, F_GETFL, 0);
+  }
+  while (flags == -1 && (errno == EINTR || errno == EAGAIN));
+
+  unlikely (flags == -1)
+  {
+    ptr->cached_errno= errno;
+    return MEMCACHED_CONNECTION_FAILURE;
+  }
+  else if ((flags & O_NONBLOCK) == 0)
+  {
+    int rval;
+
+    do
+    {
+      rval= fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK);
+    }
+    while (rval == -1 && (errno == EINTR || errno == EAGAIN));
+
+    unlikely (rval == -1)
+    {
+      ptr->cached_errno= errno;
+      return MEMCACHED_CONNECTION_FAILURE;
+    }
+  }
+#endif
+  return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t set_socket_options(memcached_server_st *ptr)
+{
+  WATCHPOINT_ASSERT(ptr->fd != -1);
+
+  if (ptr->type == MEMCACHED_CONNECTION_UDP)
+    return MEMCACHED_SUCCESS;
+
+#ifdef HAVE_SNDTIMEO
+  if (ptr->root->snd_timeout)
+  {
+    int error;
+    struct timeval waittime;
+
+    waittime.tv_sec= 0;
+    waittime.tv_usec= ptr->root->snd_timeout;
+
+    error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDTIMEO,
+                      &waittime, (socklen_t)sizeof(struct timeval));
+    WATCHPOINT_ASSERT(error == 0);
+    if (error)
+      return MEMCACHED_FAILURE;
+  }
+#endif
+
+#ifdef HAVE_RCVTIMEO
+  if (ptr->root->rcv_timeout)
+  {
+    int error;
+    struct timeval waittime;
+
+    waittime.tv_sec= 0;
+    waittime.tv_usec= ptr->root->rcv_timeout;
+
+    error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO,
+                      &waittime, (socklen_t)sizeof(struct timeval));
+    WATCHPOINT_ASSERT(error == 0);
+    if (error)
+      return MEMCACHED_FAILURE;
+  }
+#endif
+
+
+#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+  {
+    int set = 1;
+    int error= setsockopt(ptr->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
+
+    // This is not considered a fatal error
+    if (error == -1)
+    {
+      WATCHPOINT_ERRNO(get_socket_errno());
+      perror("setsockopt(SO_NOSIGPIPE)");
+    }
+  }
+#endif
+
+  if (ptr->root->flags.no_block)
+  {
+    int error;
+    struct linger linger;
+
+    linger.l_onoff= 1;
+    linger.l_linger= 0; /* By default on close() just drop the socket */
+    error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER,
+                      &linger, (socklen_t)sizeof(struct linger));
+    WATCHPOINT_ASSERT(error == 0);
+    if (error)
+      return MEMCACHED_FAILURE;
+  }
+
+  if (ptr->root->flags.tcp_nodelay)
+  {
+    int flag= 1;
+    int error;
+
+    error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY,
+                      &flag, (socklen_t)sizeof(int));
+    WATCHPOINT_ASSERT(error == 0);
+    if (error)
+      return MEMCACHED_FAILURE;
+  }
+
+  if (ptr->root->flags.tcp_keepalive)
+  {
+    int flag= 1;
+    int error;
+
+    error= setsockopt(ptr->fd, SOL_SOCKET, SO_KEEPALIVE,
+                      &flag, (socklen_t)sizeof(int));
+    WATCHPOINT_ASSERT(error == 0);
+    if (error)
+      return MEMCACHED_FAILURE;
+  }
+
+#ifdef TCP_KEEPIDLE
+  if (ptr->root->tcp_keepidle > 0)
+  {
+    int error;
+
+    error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_KEEPIDLE,
+                      &ptr->root->tcp_keepidle, (socklen_t)sizeof(int));
+    WATCHPOINT_ASSERT(error == 0);
+    if (error)
+      return MEMCACHED_FAILURE;
+  }
+#endif
+
+  if (ptr->root->send_size > 0)
+  {
+    int error;
+
+    error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF,
+                      &ptr->root->send_size, (socklen_t)sizeof(int));
+    WATCHPOINT_ASSERT(error == 0);
+    if (error)
+      return MEMCACHED_FAILURE;
+  }
+
+  if (ptr->root->recv_size > 0)
+  {
+    int error;
+
+    error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVBUF,
+                      &ptr->root->recv_size, (socklen_t)sizeof(int));
+    WATCHPOINT_ASSERT(error == 0);
+    if (error)
+      return MEMCACHED_FAILURE;
+  }
+
+
+  /* libmemcached will always use nonblocking IO to avoid write deadlocks */
+  return set_socket_nonblocking(ptr);
+}
+
+static memcached_return_t unix_socket_connect(memcached_server_st *ptr)
+{
+#ifndef WIN32
+  WATCHPOINT_ASSERT(ptr->fd == -1);
+
+  if ((ptr->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+  {
+    ptr->cached_errno= errno;
+    return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
+  }
+
+  struct sockaddr_un servAddr;
+
+  memset(&servAddr, 0, sizeof (struct sockaddr_un));
+  servAddr.sun_family= AF_UNIX;
+  strncpy(servAddr.sun_path, ptr->hostname, sizeof(servAddr.sun_path)); /* Copy filename */
+
+test_connect:
+  if (connect(ptr->fd,
+              (struct sockaddr *)&servAddr,
+              sizeof(servAddr)) < 0)
+  {
+    switch (errno)
+    {
+    case EINPROGRESS:
+    case EALREADY:
+    case EINTR:
+      goto test_connect;
+    case EISCONN: /* We were spinning waiting on connect */
+      break;
+    default:
+      WATCHPOINT_ERRNO(errno);
+      ptr->cached_errno= errno;
+      return MEMCACHED_ERRNO;
+    }
+  }
+
+  WATCHPOINT_ASSERT(ptr->fd != -1);
+
+  return MEMCACHED_SUCCESS;
+#else
+  (void)ptr;
+  return MEMCACHED_NOT_SUPPORTED;
+#endif
+}
+
+static memcached_return_t network_connect(memcached_server_st *ptr)
+{
+  bool timeout_error_occured= false;
+
+  WATCHPOINT_ASSERT(ptr->fd == INVALID_SOCKET);
+  WATCHPOINT_ASSERT(ptr->cursor_active == 0);
+
+  if (! ptr->address_info)
+  {
+    memcached_return_t rc= set_hostinfo(ptr);
+    if (rc != MEMCACHED_SUCCESS)
+      return rc;
+  }
+
+  /* Create the socket */
+  while (ptr->address_info_next && ptr->fd == INVALID_SOCKET)
+  {
+    /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
+    if (ptr->type == MEMCACHED_CONNECTION_UDP && ptr->address_info_next->ai_family != AF_INET)
+    {
+      ptr->address_info_next= ptr->address_info_next->ai_next;
+      continue;
+    }
+
+    if ((ptr->fd= socket(ptr->address_info_next->ai_family,
+                         ptr->address_info_next->ai_socktype,
+                         ptr->address_info_next->ai_protocol)) < 0)
+    {
+      ptr->cached_errno= get_socket_errno();
+      WATCHPOINT_ERRNO(get_socket_errno());
+      return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
+    }
+
+    (void)set_socket_options(ptr);
+
+    /* connect to server */
+    if ((connect(ptr->fd, ptr->address_info_next->ai_addr, ptr->address_info_next->ai_addrlen) != SOCKET_ERROR))
+    {
+      break; // Success
+    }
+
+    /* An error occurred */
+    ptr->cached_errno= get_socket_errno();
+    switch (ptr->cached_errno) 
+    {
+    case EWOULDBLOCK:
+    case EINPROGRESS: // nonblocking mode - first return
+    case EALREADY: // nonblocking mode - subsequent returns
+      {
+        memcached_return_t rc;
+        rc= connect_poll(ptr);
+
+        if (rc == MEMCACHED_TIMEOUT)
+          timeout_error_occured= true;
+
+        if (rc == MEMCACHED_SUCCESS)
+          break;
+      }
+
+    case EISCONN: // we are connected :-)
+      break;
+
+    case EINTR: // Special case, we retry ai_addr
+      (void)closesocket(ptr->fd);
+      ptr->fd= INVALID_SOCKET;
+      continue;
+
+    default:
+      (void)closesocket(ptr->fd);
+      ptr->fd= INVALID_SOCKET;
+      ptr->address_info_next= ptr->address_info_next->ai_next;
+      break;
+    }
+  }
+
+  if (ptr->fd == INVALID_SOCKET)
+  {
+    WATCHPOINT_STRING("Never got a good file descriptor");
+
+    /* Failed to connect. schedule next retry */
+    if (ptr->root->retry_timeout)
+    {
+      struct timeval next_time;
+
+      if (gettimeofday(&next_time, NULL) == 0)
+        ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout;
+    }
+
+    if (timeout_error_occured)
+      return MEMCACHED_TIMEOUT;
+
+    return MEMCACHED_ERRNO; /* The last error should be from connect() */
+  }
+
+  return MEMCACHED_SUCCESS; /* The last error should be from connect() */
+}
+
+void set_last_disconnected_host(memcached_server_write_instance_st ptr)
+{
+  // const_cast
+  memcached_st *root= (memcached_st *)ptr->root;
+
+#if 0
+  WATCHPOINT_STRING(ptr->hostname);
+  WATCHPOINT_NUMBER(ptr->port);
+  WATCHPOINT_ERRNO(ptr->cached_errno);
+#endif
+  if (root->last_disconnected_server)
+    memcached_server_free(root->last_disconnected_server);
+  root->last_disconnected_server= memcached_server_clone(NULL, ptr);
+}
+
+memcached_return_t memcached_connect(memcached_server_write_instance_st ptr)
+{
+  memcached_return_t rc= MEMCACHED_NO_SERVERS;
+
+  if (ptr->fd != INVALID_SOCKET)
+    return MEMCACHED_SUCCESS;
+
+  LIBMEMCACHED_MEMCACHED_CONNECT_START();
+
+  /* both retry_timeout and server_failure_limit must be set in order to delay retrying a server on error. */
+  WATCHPOINT_ASSERT(ptr->root);
+  if (ptr->root->retry_timeout && ptr->next_retry)
+  {
+    struct timeval curr_time;
+
+    gettimeofday(&curr_time, NULL);
+
+    // We should optimize this to remove the allocation if the server was
+    // the last server to die
+    if (ptr->next_retry > curr_time.tv_sec)
+    {
+      set_last_disconnected_host(ptr);
+
+      return MEMCACHED_SERVER_MARKED_DEAD;
+    }
+  }
+
+  // If we are over the counter failure, we just fail. Reject host only
+  // works if you have a set number of failures.
+  if (ptr->root->server_failure_limit && ptr->server_failure_counter >= ptr->root->server_failure_limit)
+  {
+    set_last_disconnected_host(ptr);
+
+    // @todo fix this by fixing behavior to no longer make use of
+    // memcached_st
+    if (_is_auto_eject_host(ptr->root))
+    {
+      run_distribution((memcached_st *)ptr->root);
+    }
+
+    return MEMCACHED_SERVER_MARKED_DEAD;
+  }
+
+  /* We need to clean up the multi startup piece */
+  switch (ptr->type)
+  {
+  case MEMCACHED_CONNECTION_UNKNOWN:
+    WATCHPOINT_ASSERT(0);
+    rc= MEMCACHED_NOT_SUPPORTED;
+    break;
+  case MEMCACHED_CONNECTION_UDP:
+  case MEMCACHED_CONNECTION_TCP:
+    rc= network_connect(ptr);
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+    if (ptr->fd != INVALID_SOCKET && ptr->root->sasl.callbacks)
+    {
+      rc= memcached_sasl_authenticate_connection(ptr);
+      if (rc != MEMCACHED_SUCCESS)
+      {
+        (void)closesocket(ptr->fd);
+        ptr->fd= INVALID_SOCKET;
+      }
+    }
+#endif
+    break;
+  case MEMCACHED_CONNECTION_UNIX_SOCKET:
+    rc= unix_socket_connect(ptr);
+    break;
+  case MEMCACHED_CONNECTION_MAX:
+  default:
+    WATCHPOINT_ASSERT(0);
+  }
+
+  if (rc == MEMCACHED_SUCCESS)
+  {
+    ptr->server_failure_counter= 0;
+    ptr->next_retry= 0;
+  }
+  else
+  {
+    ptr->server_failure_counter++;
+
+    set_last_disconnected_host(ptr);
+  }
+
+  LIBMEMCACHED_MEMCACHED_CONNECT_END();
+
+  return rc;
+}
diff --git a/libmemcached/delete.c b/libmemcached/delete.c
deleted file mode 100644 (file)
index 78f08f2..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- * 
- *  Libmemcached library
- *
- *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *  Copyright (C) 2006-2009 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/protocol_binary.h>
-
-memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t key_length,
-                                    time_t expiration)
-{
-  return memcached_delete_by_key(ptr, key, key_length,
-                                 key, key_length, expiration);
-}
-
-static inline memcached_return_t binary_delete(memcached_st *ptr,
-                                               uint32_t server_key,
-                                               const char *key,
-                                               size_t key_length,
-                                               bool flush);
-
-memcached_return_t memcached_delete_by_key(memcached_st *ptr,
-                                           const char *group_key, size_t group_key_length,
-                                           const char *key, size_t key_length,
-                                           time_t expiration)
-{
-  bool to_write;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  uint32_t server_key;
-  memcached_server_write_instance_st instance;
-
-  LIBMEMCACHED_MEMCACHED_DELETE_START();
-
-  memcached_return_t rc;
-  if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  rc= memcached_validate_key_length(key_length,
-                                    ptr->flags.binary_protocol);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  unlikely (memcached_server_count(ptr) == 0)
-    return MEMCACHED_NO_SERVERS;
-
-  server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
-  instance= memcached_server_instance_fetch(ptr, server_key);
-
-  to_write= (ptr->flags.buffer_requests) ? false : true;
-
-  bool no_reply= (ptr->flags.no_reply);
-
-  if (ptr->flags.binary_protocol)
-  {
-    likely (! expiration)
-    {
-      rc= binary_delete(ptr, server_key, key, key_length, to_write);
-    }
-    else
-    {
-      rc= MEMCACHED_INVALID_ARGUMENTS;
-    }
-  }
-  else
-  {
-    int send_length;
-
-    unlikely (expiration)
-    {
-       if ((instance->major_version == 1 &&
-            instance->minor_version > 2) ||
-           instance->major_version > 1)
-       {
-         rc= MEMCACHED_INVALID_ARGUMENTS;
-         goto error;
-       }
-       else
-       {
-          /* ensure that we are connected, otherwise we might bump the
-           * command counter before connection */
-          if ((rc= memcached_connect(instance)) != MEMCACHED_SUCCESS)
-          {
-            WATCHPOINT_ERROR(rc);
-            return rc;
-          }
-
-          if (instance->minor_version == 0)
-          {
-             if (no_reply || ! to_write)
-             {
-                /* We might get out of sync with the server if we
-                 * send this command to a server newer than 1.2.x..
-                 * disable no_reply and buffered mode.
-                 */
-                to_write= true;
-                if (no_reply)
-                   memcached_server_response_increment(instance);
-                no_reply= false;
-             }
-          }
-          send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                                "delete %.*s%.*s %u%s\r\n",
-                                memcached_print_array(ptr->prefix_key),
-                                (int) key_length, key,
-                                (uint32_t)expiration,
-                                no_reply ? " noreply" :"" );
-       }
-    }
-    else
-    {
-      send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                            "delete %.*s%.*s%s\r\n",
-                            memcached_print_array(ptr->prefix_key),
-                            (int)key_length, key, no_reply ? " noreply" :"");
-    }
-
-    if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
-    {
-      rc= MEMCACHED_WRITE_FAILURE;
-      goto error;
-    }
-
-    if (ptr->flags.use_udp && ! to_write)
-    {
-      if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
-        return MEMCACHED_WRITE_FAILURE;
-      if (send_length + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
-        memcached_io_write(instance, NULL, 0, true);
-    }
-
-    rc= memcached_do(instance, buffer, (size_t)send_length, to_write);
-  }
-
-  if (rc != MEMCACHED_SUCCESS)
-    goto error;
-
-  if (! to_write)
-  {
-    rc= MEMCACHED_BUFFERED;
-  }
-  else if (!no_reply)
-  {
-    rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-    if (rc == MEMCACHED_DELETED)
-      rc= MEMCACHED_SUCCESS;
-  }
-
-  if (rc == MEMCACHED_SUCCESS && ptr->delete_trigger)
-    ptr->delete_trigger(ptr, key, key_length);
-
-error:
-  LIBMEMCACHED_MEMCACHED_DELETE_END();
-  return rc;
-}
-
-static inline memcached_return_t binary_delete(memcached_st *ptr,
-                                               uint32_t server_key,
-                                               const char *key,
-                                               size_t key_length,
-                                               bool flush)
-{
-  memcached_server_write_instance_st instance;
-  protocol_binary_request_delete request= {.bytes= {0}};
-
-  instance= memcached_server_instance_fetch(ptr, server_key);
-
-  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
-  if (ptr->flags.no_reply)
-    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
-  else
-    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
-  request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
-  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-  request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key)));
-
-  if (ptr->flags.use_udp && ! flush)
-  {
-    size_t cmd_size= sizeof(request.bytes) + key_length;
-    if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
-      return MEMCACHED_WRITE_FAILURE;
-    if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
-      memcached_io_write(instance, NULL, 0, true);
-  }
-
-  struct libmemcached_io_vector_st vector[]=
-  {
-    { .length= sizeof(request.bytes), .buffer= request.bytes},
-    { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
-    { .length= key_length, .buffer= key },
-  };
-
-  memcached_return_t rc= MEMCACHED_SUCCESS;
-
-  if ((rc= memcached_vdo(instance, vector,  3, flush)) != MEMCACHED_SUCCESS)
-  {
-    memcached_io_reset(instance);
-    rc= (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
-  }
-
-  unlikely (ptr->number_of_replicas > 0)
-  {
-    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
-
-    for (uint32_t x= 0; x < ptr->number_of_replicas; ++x)
-    {
-      memcached_server_write_instance_st replica;
-
-      ++server_key;
-      if (server_key == memcached_server_count(ptr))
-        server_key= 0;
-
-      replica= memcached_server_instance_fetch(ptr, server_key);
-
-      if (memcached_vdo(replica, vector, 3, flush) != MEMCACHED_SUCCESS)
-      {
-        memcached_io_reset(replica);
-      }
-      else
-      {
-        memcached_server_response_decrement(replica);
-      }
-    }
-  }
-
-  return rc;
-}
diff --git a/libmemcached/delete.cc b/libmemcached/delete.cc
new file mode 100644 (file)
index 0000000..1005cb9
--- /dev/null
@@ -0,0 +1,264 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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/protocol_binary.h>
+
+memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t key_length,
+                                    time_t expiration)
+{
+  return memcached_delete_by_key(ptr, key, key_length,
+                                 key, key_length, expiration);
+}
+
+static inline memcached_return_t binary_delete(memcached_st *ptr,
+                                               uint32_t server_key,
+                                               const char *key,
+                                               size_t key_length,
+                                               bool flush);
+
+memcached_return_t memcached_delete_by_key(memcached_st *ptr,
+                                           const char *group_key, size_t group_key_length,
+                                           const char *key, size_t key_length,
+                                           time_t expiration)
+{
+  bool to_write;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+  uint32_t server_key;
+  memcached_server_write_instance_st instance;
+
+  LIBMEMCACHED_MEMCACHED_DELETE_START();
+
+  memcached_return_t rc;
+  if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS)
+  {
+    return rc;
+  }
+
+  rc= memcached_validate_key_length(key_length,
+                                    ptr->flags.binary_protocol);
+  unlikely (rc != MEMCACHED_SUCCESS)
+    return rc;
+
+  unlikely (memcached_server_count(ptr) == 0)
+    return MEMCACHED_NO_SERVERS;
+
+  server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
+  instance= memcached_server_instance_fetch(ptr, server_key);
+
+  to_write= (ptr->flags.buffer_requests) ? false : true;
+
+  bool no_reply= (ptr->flags.no_reply);
+
+  if (ptr->flags.binary_protocol)
+  {
+    likely (! expiration)
+    {
+      rc= binary_delete(ptr, server_key, key, key_length, to_write);
+    }
+    else
+    {
+      rc= MEMCACHED_INVALID_ARGUMENTS;
+    }
+  }
+  else
+  {
+    int send_length;
+
+    unlikely (expiration)
+    {
+       if ((instance->major_version == 1 &&
+            instance->minor_version > 2) ||
+           instance->major_version > 1)
+       {
+         rc= MEMCACHED_INVALID_ARGUMENTS;
+         goto error;
+       }
+       else
+       {
+          /* ensure that we are connected, otherwise we might bump the
+           * command counter before connection */
+          if ((rc= memcached_connect(instance)) != MEMCACHED_SUCCESS)
+          {
+            WATCHPOINT_ERROR(rc);
+            return rc;
+          }
+
+          if (instance->minor_version == 0)
+          {
+             if (no_reply || ! to_write)
+             {
+                /* We might get out of sync with the server if we
+                 * send this command to a server newer than 1.2.x..
+                 * disable no_reply and buffered mode.
+                 */
+                to_write= true;
+                if (no_reply)
+                   memcached_server_response_increment(instance);
+                no_reply= false;
+             }
+          }
+          send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                                "delete %.*s%.*s %u%s\r\n",
+                                memcached_print_array(ptr->prefix_key),
+                                (int) key_length, key,
+                                (uint32_t)expiration,
+                                no_reply ? " noreply" :"" );
+       }
+    }
+    else
+    {
+      send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                            "delete %.*s%.*s%s\r\n",
+                            memcached_print_array(ptr->prefix_key),
+                            (int)key_length, key, no_reply ? " noreply" :"");
+    }
+
+    if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
+    {
+      rc= MEMCACHED_WRITE_FAILURE;
+      goto error;
+    }
+
+    if (ptr->flags.use_udp && ! to_write)
+    {
+      if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+        return MEMCACHED_WRITE_FAILURE;
+      if (send_length + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+        memcached_io_write(instance, NULL, 0, true);
+    }
+
+    rc= memcached_do(instance, buffer, (size_t)send_length, to_write);
+  }
+
+  if (rc != MEMCACHED_SUCCESS)
+    goto error;
+
+  if (! to_write)
+  {
+    rc= MEMCACHED_BUFFERED;
+  }
+  else if (!no_reply)
+  {
+    rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+    if (rc == MEMCACHED_DELETED)
+      rc= MEMCACHED_SUCCESS;
+  }
+
+  if (rc == MEMCACHED_SUCCESS && ptr->delete_trigger)
+    ptr->delete_trigger(ptr, key, key_length);
+
+error:
+  LIBMEMCACHED_MEMCACHED_DELETE_END();
+  return rc;
+}
+
+static inline memcached_return_t binary_delete(memcached_st *ptr,
+                                               uint32_t server_key,
+                                               const char *key,
+                                               size_t key_length,
+                                               bool flush)
+{
+  memcached_server_write_instance_st instance;
+  protocol_binary_request_delete request= {};
+
+  instance= memcached_server_instance_fetch(ptr, server_key);
+
+  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+  if (ptr->flags.no_reply)
+  {
+    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
+  }
+  else
+  {
+    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETE;
+  }
+  request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
+  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+  request.message.header.request.bodylen= htonl((uint32_t)(key_length + memcached_array_size(ptr->prefix_key)));
+
+  if (ptr->flags.use_udp && ! flush)
+  {
+    size_t cmd_size= sizeof(request.bytes) + key_length;
+    if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+      return MEMCACHED_WRITE_FAILURE;
+    if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+      memcached_io_write(instance, NULL, 0, true);
+  }
+
+  struct libmemcached_io_vector_st vector[]=
+  {
+    { sizeof(request.bytes), request.bytes},
+    { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) },
+    { key_length, key },
+  };
+
+  memcached_return_t rc= MEMCACHED_SUCCESS;
+
+  if ((rc= memcached_vdo(instance, vector,  3, flush)) != MEMCACHED_SUCCESS)
+  {
+    memcached_io_reset(instance);
+    rc= (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
+  }
+
+  unlikely (ptr->number_of_replicas > 0)
+  {
+    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_DELETEQ;
+
+    for (uint32_t x= 0; x < ptr->number_of_replicas; ++x)
+    {
+      memcached_server_write_instance_st replica;
+
+      ++server_key;
+      if (server_key == memcached_server_count(ptr))
+        server_key= 0;
+
+      replica= memcached_server_instance_fetch(ptr, server_key);
+
+      if (memcached_vdo(replica, vector, 3, flush) != MEMCACHED_SUCCESS)
+      {
+        memcached_io_reset(replica);
+      }
+      else
+      {
+        memcached_server_response_decrement(replica);
+      }
+    }
+  }
+
+  return rc;
+}
index 8d0d7eda880ea7f65822c206b8db79f4140af0b3..617d5857d2a6d4414d4a8130afb014b5704b3eb5 100644 (file)
@@ -1,16 +1,42 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
  *
- * Summary: Delete a key from the server.
+ *  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.
  *
  */
 
-#ifndef __LIBMEMCACHED_DELETE_H__
-#define __LIBMEMCACHED_DELETE_H__
+
+#pragma once
 
 #ifdef __cplusplus
 extern "C" {
@@ -29,5 +55,3 @@ memcached_return_t memcached_delete_by_key(memcached_st *ptr,
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __LIBMEMCACHED_DELETE_H__ */
diff --git a/libmemcached/do.c b/libmemcached/do.c
deleted file mode 100644 (file)
index 14824a6..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-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:
- *
- */
-
-#include "common.h"
-
-memcached_return_t memcached_do(memcached_server_write_instance_st ptr, const void *command,
-                                size_t command_length, bool with_flush)
-{
-  memcached_return_t rc;
-  ssize_t sent_length;
-
-  WATCHPOINT_ASSERT(command_length);
-  WATCHPOINT_ASSERT(command);
-
-  if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS)
-  {
-    WATCHPOINT_ERROR(rc);
-    return rc;
-  }
-
-  /*
-  ** Since non buffering ops in UDP mode dont check to make sure they will fit
-  ** before they start writing, if there is any data in buffer, clear it out,
-  ** otherwise we might get a partial write.
-  **/
-  if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH)
-  {
-    memcached_io_write(ptr, NULL, 0, true);
-  }
-
-  sent_length= memcached_io_write(ptr, command, command_length, with_flush);
-
-  if (sent_length == -1 || (size_t)sent_length != command_length)
-  {
-    rc= MEMCACHED_WRITE_FAILURE;
-  }
-  else if ((ptr->root->flags.no_reply) == 0)
-  {
-    memcached_server_response_increment(ptr);
-  }
-
-  return rc;
-}
-
-memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr,
-                                 const struct libmemcached_io_vector_st *vector, size_t count,
-                                 bool with_flush)
-{
-  memcached_return_t rc;
-  ssize_t sent_length;
-
-  WATCHPOINT_ASSERT(count);
-  WATCHPOINT_ASSERT(vector);
-
-  if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS)
-  {
-    WATCHPOINT_ERROR(rc);
-    return rc;
-  }
-
-  /*
-  ** Since non buffering ops in UDP mode dont check to make sure they will fit
-  ** before they start writing, if there is any data in buffer, clear it out,
-  ** otherwise we might get a partial write.
-  **/
-  if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH)
-  {
-    memcached_io_write(ptr, NULL, 0, true);
-  }
-
-  sent_length= memcached_io_writev(ptr, vector, count, with_flush);
-
-  size_t command_length= 0;
-  for (uint32_t x= 0; x < count; ++x, vector++)
-  {
-    command_length+= vector->length;
-  }
-
-  if (sent_length == -1 || (size_t)sent_length != command_length)
-  {
-    rc= MEMCACHED_WRITE_FAILURE;
-    WATCHPOINT_ERROR(rc);
-    WATCHPOINT_ERRNO(errno);
-  }
-  else if ((ptr->root->flags.no_reply) == 0)
-  {
-    memcached_server_response_increment(ptr);
-  }
-
-  return rc;
-}
diff --git a/libmemcached/do.cc b/libmemcached/do.cc
new file mode 100644 (file)
index 0000000..14824a6
--- /dev/null
@@ -0,0 +1,99 @@
+/* LibMemcached
+ * Copyright (C) 2006-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:
+ *
+ */
+
+#include "common.h"
+
+memcached_return_t memcached_do(memcached_server_write_instance_st ptr, const void *command,
+                                size_t command_length, bool with_flush)
+{
+  memcached_return_t rc;
+  ssize_t sent_length;
+
+  WATCHPOINT_ASSERT(command_length);
+  WATCHPOINT_ASSERT(command);
+
+  if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS)
+  {
+    WATCHPOINT_ERROR(rc);
+    return rc;
+  }
+
+  /*
+  ** Since non buffering ops in UDP mode dont check to make sure they will fit
+  ** before they start writing, if there is any data in buffer, clear it out,
+  ** otherwise we might get a partial write.
+  **/
+  if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH)
+  {
+    memcached_io_write(ptr, NULL, 0, true);
+  }
+
+  sent_length= memcached_io_write(ptr, command, command_length, with_flush);
+
+  if (sent_length == -1 || (size_t)sent_length != command_length)
+  {
+    rc= MEMCACHED_WRITE_FAILURE;
+  }
+  else if ((ptr->root->flags.no_reply) == 0)
+  {
+    memcached_server_response_increment(ptr);
+  }
+
+  return rc;
+}
+
+memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr,
+                                 const struct libmemcached_io_vector_st *vector, size_t count,
+                                 bool with_flush)
+{
+  memcached_return_t rc;
+  ssize_t sent_length;
+
+  WATCHPOINT_ASSERT(count);
+  WATCHPOINT_ASSERT(vector);
+
+  if ((rc= memcached_connect(ptr)) != MEMCACHED_SUCCESS)
+  {
+    WATCHPOINT_ERROR(rc);
+    return rc;
+  }
+
+  /*
+  ** Since non buffering ops in UDP mode dont check to make sure they will fit
+  ** before they start writing, if there is any data in buffer, clear it out,
+  ** otherwise we might get a partial write.
+  **/
+  if (ptr->type == MEMCACHED_CONNECTION_UDP && with_flush && ptr->write_buffer_offset > UDP_DATAGRAM_HEADER_LENGTH)
+  {
+    memcached_io_write(ptr, NULL, 0, true);
+  }
+
+  sent_length= memcached_io_writev(ptr, vector, count, with_flush);
+
+  size_t command_length= 0;
+  for (uint32_t x= 0; x < count; ++x, vector++)
+  {
+    command_length+= vector->length;
+  }
+
+  if (sent_length == -1 || (size_t)sent_length != command_length)
+  {
+    rc= MEMCACHED_WRITE_FAILURE;
+    WATCHPOINT_ERROR(rc);
+    WATCHPOINT_ERRNO(errno);
+  }
+  else if ((ptr->root->flags.no_reply) == 0)
+  {
+    memcached_server_response_increment(ptr);
+  }
+
+  return rc;
+}
diff --git a/libmemcached/dump.c b/libmemcached/dump.c
deleted file mode 100644 (file)
index 18c1597..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-  We use this to dump all keys.
-
-  At this point we only support a callback method. This could be optimized by first
-  calling items and finding active slabs. For the moment though we just loop through
-  all slabs on servers and "grab" the keys.
-*/
-
-#include "common.h"
-static memcached_return_t ascii_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
-{
-  memcached_return_t rc= MEMCACHED_SUCCESS;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  uint32_t server_key;
-  uint32_t x;
-
-  unlikely (memcached_server_count(ptr) == 0)
-    return MEMCACHED_NO_SERVERS;
-
-  for (server_key= 0; server_key < memcached_server_count(ptr); server_key++)
-  {
-    memcached_server_write_instance_st instance;
-    instance= memcached_server_instance_fetch(ptr, server_key);
-
-    /* 256 I BELIEVE is the upper limit of slabs */
-    for (x= 0; x < 256; x++)
-    {
-      int send_length;
-      send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                            "stats cachedump %u 0 0\r\n", x);
-
-      if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
-      {
-        return MEMCACHED_FAILURE;
-      }
-
-      rc= memcached_do(instance, buffer, (size_t)send_length, true);
-
-      unlikely (rc != MEMCACHED_SUCCESS)
-        goto error;
-
-      while (1)
-      {
-        uint32_t callback_counter;
-        rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-
-        if (rc == MEMCACHED_ITEM)
-        {
-          char *string_ptr, *end_ptr;
-          char *key;
-
-          string_ptr= buffer;
-          string_ptr+= 5; /* Move past ITEM */
-          for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++);
-          key= string_ptr;
-          key[(size_t)(end_ptr-string_ptr)]= 0;
-          for (callback_counter= 0; callback_counter < number_of_callbacks; callback_counter++)
-          {
-            rc= (*callback[callback_counter])(ptr, key, (size_t)(end_ptr-string_ptr), context);
-            if (rc != MEMCACHED_SUCCESS)
-              break;
-          }
-        }
-        else if (rc == MEMCACHED_END)
-          break;
-        else if (rc == MEMCACHED_SERVER_ERROR || rc == MEMCACHED_CLIENT_ERROR)
-        {
-          /* If we try to request stats cachedump for a slab class that is too big
-           * the server will return an incorrect error message:
-           * "MEMCACHED_SERVER_ERROR failed to allocate memory"
-           * This isn't really a fatal error, so let's just skip it. I want to
-           * fix the return value from the memcached server to a CLIENT_ERROR,
-           * so let's add support for that as well right now.
-           */
-          rc= MEMCACHED_END;
-          break;
-        }
-        else
-          goto error;
-      }
-    }
-  }
-
-error:
-  if (rc == MEMCACHED_END)
-    return MEMCACHED_SUCCESS;
-  else
-    return rc;
-}
-
-memcached_return_t memcached_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
-{
-  memcached_return_t rc;
-  if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  /* 
-    No support for Binary protocol yet
-    @todo Fix this so that we just flush, switch to ascii, and then go back to binary.
-  */
-  if (ptr->flags.binary_protocol)
-    return MEMCACHED_FAILURE;
-
-  return ascii_dump(ptr, callback, context, number_of_callbacks);
-}
diff --git a/libmemcached/dump.cc b/libmemcached/dump.cc
new file mode 100644 (file)
index 0000000..18c1597
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+  We use this to dump all keys.
+
+  At this point we only support a callback method. This could be optimized by first
+  calling items and finding active slabs. For the moment though we just loop through
+  all slabs on servers and "grab" the keys.
+*/
+
+#include "common.h"
+static memcached_return_t ascii_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
+{
+  memcached_return_t rc= MEMCACHED_SUCCESS;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+  uint32_t server_key;
+  uint32_t x;
+
+  unlikely (memcached_server_count(ptr) == 0)
+    return MEMCACHED_NO_SERVERS;
+
+  for (server_key= 0; server_key < memcached_server_count(ptr); server_key++)
+  {
+    memcached_server_write_instance_st instance;
+    instance= memcached_server_instance_fetch(ptr, server_key);
+
+    /* 256 I BELIEVE is the upper limit of slabs */
+    for (x= 0; x < 256; x++)
+    {
+      int send_length;
+      send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                            "stats cachedump %u 0 0\r\n", x);
+
+      if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
+      {
+        return MEMCACHED_FAILURE;
+      }
+
+      rc= memcached_do(instance, buffer, (size_t)send_length, true);
+
+      unlikely (rc != MEMCACHED_SUCCESS)
+        goto error;
+
+      while (1)
+      {
+        uint32_t callback_counter;
+        rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+        if (rc == MEMCACHED_ITEM)
+        {
+          char *string_ptr, *end_ptr;
+          char *key;
+
+          string_ptr= buffer;
+          string_ptr+= 5; /* Move past ITEM */
+          for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++);
+          key= string_ptr;
+          key[(size_t)(end_ptr-string_ptr)]= 0;
+          for (callback_counter= 0; callback_counter < number_of_callbacks; callback_counter++)
+          {
+            rc= (*callback[callback_counter])(ptr, key, (size_t)(end_ptr-string_ptr), context);
+            if (rc != MEMCACHED_SUCCESS)
+              break;
+          }
+        }
+        else if (rc == MEMCACHED_END)
+          break;
+        else if (rc == MEMCACHED_SERVER_ERROR || rc == MEMCACHED_CLIENT_ERROR)
+        {
+          /* If we try to request stats cachedump for a slab class that is too big
+           * the server will return an incorrect error message:
+           * "MEMCACHED_SERVER_ERROR failed to allocate memory"
+           * This isn't really a fatal error, so let's just skip it. I want to
+           * fix the return value from the memcached server to a CLIENT_ERROR,
+           * so let's add support for that as well right now.
+           */
+          rc= MEMCACHED_END;
+          break;
+        }
+        else
+          goto error;
+      }
+    }
+  }
+
+error:
+  if (rc == MEMCACHED_END)
+    return MEMCACHED_SUCCESS;
+  else
+    return rc;
+}
+
+memcached_return_t memcached_dump(memcached_st *ptr, memcached_dump_fn *callback, void *context, uint32_t number_of_callbacks)
+{
+  memcached_return_t rc;
+  if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS)
+  {
+    return rc;
+  }
+
+  /* 
+    No support for Binary protocol yet
+    @todo Fix this so that we just flush, switch to ascii, and then go back to binary.
+  */
+  if (ptr->flags.binary_protocol)
+    return MEMCACHED_FAILURE;
+
+  return ascii_dump(ptr, callback, context, number_of_callbacks);
+}
index ef207a955f25d610efdc346e7e5a204c95efe32c..02169a28f0e7525ffe8496f9a9c0225bc5e582c5 100644 (file)
@@ -139,7 +139,7 @@ void memcached_error_print(const memcached_st *self)
 
 static void _error_free(memcached_error_t *error)
 {
-  if (! error)
+  if (not error)
     return;
 
   _error_free(error->next);
@@ -156,10 +156,11 @@ static void _error_free(memcached_error_t *error)
 
 void memcached_error_free(memcached_st *self)
 {
-  if (! self)
+  if (not self)
     return;
 
   _error_free(self->error_messages);
+  self->error_messages= NULL;
 }
 
 const char *memcached_last_error_message(memcached_st *memc)
diff --git a/libmemcached/flush.c b/libmemcached/flush.c
deleted file mode 100644 (file)
index 8da6b5b..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-#include "common.h"
-
-static memcached_return_t memcached_flush_binary(memcached_st *ptr, 
-                                                 time_t expiration);
-static memcached_return_t memcached_flush_textual(memcached_st *ptr, 
-                                                  time_t expiration);
-
-memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration)
-{
-  memcached_return_t rc;
-  if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  LIBMEMCACHED_MEMCACHED_FLUSH_START();
-  if (ptr->flags.binary_protocol)
-    rc= memcached_flush_binary(ptr, expiration);
-  else
-    rc= memcached_flush_textual(ptr, expiration);
-  LIBMEMCACHED_MEMCACHED_FLUSH_END();
-  return rc;
-}
-
-static memcached_return_t memcached_flush_textual(memcached_st *ptr, 
-                                                  time_t expiration)
-{
-  unlikely (memcached_server_count(ptr) == 0)
-    return MEMCACHED_NO_SERVERS;
-
-  for (unsigned int x= 0; x < memcached_server_count(ptr); x++)
-  {
-    memcached_return_t rc;
-    char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
-    bool no_reply= ptr->flags.no_reply;
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(ptr, x);
-
-    int send_length;
-    if (expiration)
-    {
-      send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
-                            "flush_all %llu%s\r\n",
-                            (unsigned long long)expiration, no_reply ? " noreply" : "");
-    }
-    else
-    {
-      send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
-                            "flush_all%s\r\n", no_reply ? " noreply" : "");
-    }
-
-    if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
-    {
-      return MEMCACHED_FAILURE;
-    }
-
-    rc= memcached_do(instance, buffer, (size_t)send_length, true);
-
-    if (rc == MEMCACHED_SUCCESS && !no_reply)
-      (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t memcached_flush_binary(memcached_st *ptr, 
-                                                 time_t expiration)
-{
-  protocol_binary_request_flush request= {.bytes= {0}};
-
-  unlikely (memcached_server_count(ptr) == 0)
-    return MEMCACHED_NO_SERVERS;
-
-  request.message.header.request.magic= (uint8_t)PROTOCOL_BINARY_REQ;
-  request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
-  request.message.header.request.extlen= 4;
-  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-  request.message.header.request.bodylen= htonl(request.message.header.request.extlen);
-  request.message.body.expiration= htonl((uint32_t) expiration);
-
-  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
-  {
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(ptr, x);
-
-    if (ptr->flags.no_reply)
-    {
-      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ;
-    }
-    else
-    {
-      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
-    }
-
-    if (memcached_do(instance, request.bytes, sizeof(request.bytes), true) != MEMCACHED_SUCCESS) 
-    {
-      memcached_io_reset(instance);
-      return MEMCACHED_WRITE_FAILURE;
-    } 
-  }
-
-  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
-  {
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(ptr, x);
-
-    if (memcached_server_response_count(instance) > 0)
-      (void)memcached_response(instance, NULL, 0, NULL);
-  }
-
-  return MEMCACHED_SUCCESS;
-}
diff --git a/libmemcached/flush.cc b/libmemcached/flush.cc
new file mode 100644 (file)
index 0000000..6a1364c
--- /dev/null
@@ -0,0 +1,149 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ *  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>
+
+static memcached_return_t memcached_flush_binary(memcached_st *ptr, 
+                                                 time_t expiration);
+static memcached_return_t memcached_flush_textual(memcached_st *ptr, 
+                                                  time_t expiration);
+
+memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration)
+{
+  memcached_return_t rc;
+  if (memcached_failed(rc= initialize_query(ptr)))
+  {
+    return rc;
+  }
+
+  LIBMEMCACHED_MEMCACHED_FLUSH_START();
+  if (ptr->flags.binary_protocol)
+    rc= memcached_flush_binary(ptr, expiration);
+  else
+    rc= memcached_flush_textual(ptr, expiration);
+  LIBMEMCACHED_MEMCACHED_FLUSH_END();
+  return rc;
+}
+
+static memcached_return_t memcached_flush_textual(memcached_st *ptr, 
+                                                  time_t expiration)
+{
+  unlikely (memcached_server_count(ptr) == 0)
+    return MEMCACHED_NO_SERVERS;
+
+  for (unsigned int x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_return_t rc;
+    char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+    bool no_reply= ptr->flags.no_reply;
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    int send_length;
+    if (expiration)
+    {
+      send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
+                            "flush_all %llu%s\r\n",
+                            (unsigned long long)expiration, no_reply ? " noreply" : "");
+    }
+    else
+    {
+      send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
+                            "flush_all%s\r\n", no_reply ? " noreply" : "");
+    }
+
+    if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
+    {
+      return MEMCACHED_FAILURE;
+    }
+
+    rc= memcached_do(instance, buffer, (size_t)send_length, true);
+
+    if (rc == MEMCACHED_SUCCESS && !no_reply)
+      (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t memcached_flush_binary(memcached_st *ptr, 
+                                                 time_t expiration)
+{
+  protocol_binary_request_flush request= {};
+
+  unlikely (memcached_server_count(ptr) == 0)
+    return MEMCACHED_NO_SERVERS;
+
+  request.message.header.request.magic= (uint8_t)PROTOCOL_BINARY_REQ;
+  request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
+  request.message.header.request.extlen= 4;
+  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+  request.message.header.request.bodylen= htonl(request.message.header.request.extlen);
+  request.message.body.expiration= htonl((uint32_t) expiration);
+
+  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    if (ptr->flags.no_reply)
+    {
+      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ;
+    }
+    else
+    {
+      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
+    }
+
+    if (memcached_do(instance, request.bytes, sizeof(request.bytes), true) != MEMCACHED_SUCCESS) 
+    {
+      memcached_io_reset(instance);
+      return MEMCACHED_WRITE_FAILURE;
+    } 
+  }
+
+  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    if (memcached_server_response_count(instance) > 0)
+      (void)memcached_response(instance, NULL, 0, NULL);
+  }
+
+  return MEMCACHED_SUCCESS;
+}
index 36c0759899a6d18af9cbf74a29c345459532e8ca..820a98e77d6463f56fdf8b9e35d3f1d8b09ea2b2 100644 (file)
@@ -1,16 +1,41 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
  *
- * Summary: Flush connections.
+ *  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.
  *
  */
 
-#ifndef __LIBMEMCACHED_FLUSH_H__
-#define __LIBMEMCACHED_FLUSH_H__
+#pragma once
 
 #ifdef __cplusplus
 extern "C" {
@@ -22,5 +47,3 @@ memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration);
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __LIBMEMCACHED_FLUSH_H__ */
diff --git a/libmemcached/flush_buffers.c b/libmemcached/flush_buffers.c
deleted file mode 100644 (file)
index 649db98..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "common.h"
-
-memcached_return_t memcached_flush_buffers(memcached_st *memc)
-{
-  memcached_return_t ret= MEMCACHED_SUCCESS;
-
-  for (uint32_t x= 0; x < memcached_server_count(memc); ++x)
-  {
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(memc, x);
-
-    if (instance->write_buffer_offset != 0) 
-    {
-      if (instance->fd == -1 &&
-          (ret= memcached_connect(instance)) != MEMCACHED_SUCCESS)
-      {
-        WATCHPOINT_ERROR(ret);
-        return ret;
-      }
-
-      if (memcached_io_write(instance, NULL, 0, true) == -1)
-      {
-        ret= MEMCACHED_SOME_ERRORS;
-      }
-    }
-  }
-
-  return ret;
-}
diff --git a/libmemcached/flush_buffers.cc b/libmemcached/flush_buffers.cc
new file mode 100644 (file)
index 0000000..bb3c4de
--- /dev/null
@@ -0,0 +1,66 @@
+/*  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>
+
+memcached_return_t memcached_flush_buffers(memcached_st *memc)
+{
+  memcached_return_t ret= MEMCACHED_SUCCESS;
+
+  for (uint32_t x= 0; x < memcached_server_count(memc); ++x)
+  {
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(memc, x);
+
+    if (instance->write_buffer_offset != 0) 
+    {
+      if (instance->fd == -1 &&
+          (ret= memcached_connect(instance)) != MEMCACHED_SUCCESS)
+      {
+        WATCHPOINT_ERROR(ret);
+        return ret;
+      }
+
+      if (memcached_io_write(instance, NULL, 0, true) == -1)
+      {
+        ret= MEMCACHED_SOME_ERRORS;
+      }
+    }
+  }
+
+  return ret;
+}
index 88d8a81c2508bc1bb5118e894ba7fe5eaaf1404a..31b5868742f2a62832994755a085374b4f305d81 100644 (file)
@@ -1,16 +1,41 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
  *
- * Summary: Work with fetching results
+ *  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.
  *
  */
 
-#ifndef __LIBMEMCACHED_FLUSH_BUFFERS_H__
-#define __LIBMEMCACHED_FLUSH_BUFFERS_H__
+#pragma once
 
 #ifdef __cplusplus
 extern "C" {
@@ -22,5 +47,3 @@ memcached_return_t memcached_flush_buffers(memcached_st *mem);
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __LIBMEMCACHED_FLUSH_BUFFERS_H__ */
diff --git a/libmemcached/get.c b/libmemcached/get.c
deleted file mode 100644 (file)
index 46b6319..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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: Get functions for libmemcached
- *
- */
-
-#include "common.h"
-
-/*
-  What happens if no servers exist?
-*/
-char *memcached_get(memcached_st *ptr, const char *key,
-                    size_t key_length,
-                    size_t *value_length,
-                    uint32_t *flags,
-                    memcached_return_t *error)
-{
-  return memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length,
-                              flags, error);
-}
-
-static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
-                                                     const char *group_key,
-                                                     size_t group_key_length,
-                                                     const char * const *keys,
-                                                     const size_t *key_length,
-                                                     size_t number_of_keys,
-                                                     bool mget_mode);
-
-char *memcached_get_by_key(memcached_st *ptr,
-                           const char *group_key,
-                           size_t group_key_length,
-                           const char *key, size_t key_length,
-                           size_t *value_length,
-                           uint32_t *flags,
-                           memcached_return_t *error)
-{
-  char *value;
-  size_t dummy_length;
-  uint32_t dummy_flags;
-  memcached_return_t dummy_error;
-
-  unlikely (ptr->flags.use_udp)
-  {
-    *error= MEMCACHED_NOT_SUPPORTED;
-    return NULL;
-  }
-
-  /* Request the key */
-  *error= memcached_mget_by_key_real(ptr, group_key, group_key_length,
-                                     (const char * const *)&key,
-                                     &key_length, 1, false);
-
-  value= memcached_fetch(ptr, NULL, NULL,
-                         value_length, flags, error);
-  /* This is for historical reasons */
-  if (*error == MEMCACHED_END)
-    *error= MEMCACHED_NOTFOUND;
-
-  if (value == NULL)
-  {
-    if (ptr->get_key_failure && *error == MEMCACHED_NOTFOUND)
-    {
-      memcached_return_t rc;
-
-      memcached_result_reset(&ptr->result);
-      rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result);
-
-      /* On all failure drop to returning NULL */
-      if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
-      {
-        if (rc == MEMCACHED_BUFFERED)
-        {
-          uint64_t latch; /* We use latch to track the state of the original socket */
-          latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
-          if (latch == 0)
-            memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
-
-          rc= memcached_set(ptr, key, key_length,
-                            (memcached_result_value(&ptr->result)),
-                            (memcached_result_length(&ptr->result)),
-                            0,
-                            (memcached_result_flags(&ptr->result)));
-
-          if (rc == MEMCACHED_BUFFERED && latch == 0)
-            memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
-        }
-        else
-        {
-          rc= memcached_set(ptr, key, key_length,
-                            (memcached_result_value(&ptr->result)),
-                            (memcached_result_length(&ptr->result)),
-                            0,
-                            (memcached_result_flags(&ptr->result)));
-        }
-
-        if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
-        {
-          *error= rc;
-          *value_length= memcached_result_length(&ptr->result);
-          *flags= memcached_result_flags(&ptr->result);
-          return memcached_string_c_copy(&ptr->result.value);
-        }
-      }
-    }
-
-    return NULL;
-  }
-
-  (void)memcached_fetch(ptr, NULL, NULL,
-                        &dummy_length, &dummy_flags,
-                        &dummy_error);
-  WATCHPOINT_ASSERT(dummy_length == 0);
-
-  return value;
-}
-
-memcached_return_t memcached_mget(memcached_st *ptr,
-                                  const char * const *keys,
-                                  const size_t *key_length,
-                                  size_t number_of_keys)
-{
-  return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys);
-}
-
-static memcached_return_t binary_mget_by_key(memcached_st *ptr,
-                                             uint32_t master_server_key,
-                                             bool is_group_key_set,
-                                             const char * const *keys,
-                                             const size_t *key_length,
-                                             size_t number_of_keys,
-                                             bool mget_mode);
-
-static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
-                                                     const char *group_key,
-                                                     size_t group_key_length,
-                                                     const char * const *keys,
-                                                     const size_t *key_length,
-                                                     size_t number_of_keys,
-                                                     bool mget_mode)
-{
-  bool failures_occured_in_sending= false;
-  const char *get_command= "get ";
-  uint8_t get_command_length= 4;
-  unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */
-  bool is_group_key_set= false;
-
-  memcached_return_t rc;
-  if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  unlikely (ptr->flags.use_udp)
-    return MEMCACHED_NOT_SUPPORTED;
-
-  LIBMEMCACHED_MEMCACHED_MGET_START();
-
-  if (number_of_keys == 0)
-    return MEMCACHED_NOTFOUND;
-
-  if (ptr->flags.verify_key && (memcached_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED))
-    return MEMCACHED_BAD_KEY_PROVIDED;
-
-  if (group_key && group_key_length)
-  {
-    if (ptr->flags.verify_key && (memcached_key_test((const char * const *)&group_key, &group_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
-      return MEMCACHED_BAD_KEY_PROVIDED;
-    master_server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
-    is_group_key_set= true;
-  }
-
-  /*
-    Here is where we pay for the non-block API. We need to remove any data sitting
-    in the queue before we start our get.
-
-    It might be optimum to bounce the connection if count > some number.
-  */
-  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
-  {
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(ptr, x);
-
-    if (memcached_server_response_count(instance))
-    {
-      char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
-      if (ptr->flags.no_block)
-        (void)memcached_io_write(instance, NULL, 0, true);
-
-      while(memcached_server_response_count(instance))
-        (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
-    }
-  }
-
-  if (ptr->flags.binary_protocol)
-  {
-    return binary_mget_by_key(ptr, master_server_key, is_group_key_set, keys,
-                              key_length, number_of_keys, mget_mode);
-  }
-
-  if (ptr->flags.support_cas)
-  {
-    get_command= "gets ";
-    get_command_length= 5;
-  }
-
-  /*
-    If a server fails we warn about errors and start all over with sending keys
-    to the server.
-  */
-  WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
-  size_t hosts_connected= 0;
-  for (uint32_t x= 0; x < number_of_keys; x++)
-  {
-    memcached_server_write_instance_st instance;
-    uint32_t server_key;
-
-    if (is_group_key_set)
-    {
-      server_key= master_server_key;
-    }
-    else
-    {
-      server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
-    }
-
-    instance= memcached_server_instance_fetch(ptr, server_key);
-
-    struct libmemcached_io_vector_st vector[]=
-    {
-      { .length= get_command_length, .buffer= get_command },
-      { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
-      { .length= key_length[x], .buffer= keys[x] },
-      { .length= 1, .buffer= " " }
-    };
-
-
-    if (memcached_server_response_count(instance) == 0)
-    {
-      rc= memcached_connect(instance);
-
-      if (rc != MEMCACHED_SUCCESS)
-      {
-        continue;
-      }
-      hosts_connected++;
-
-      if ((memcached_io_writev(instance, vector, 4, false)) == -1)
-      {
-        failures_occured_in_sending= true;
-        continue;
-      }
-      WATCHPOINT_ASSERT(instance->cursor_active == 0);
-      memcached_server_response_increment(instance);
-      WATCHPOINT_ASSERT(instance->cursor_active == 1);
-    }
-    else
-    {
-      if ((memcached_io_writev(instance, (vector + 1), 3, false)) == -1)
-      {
-        memcached_server_response_reset(instance);
-        failures_occured_in_sending= true;
-        continue;
-      }
-    }
-  }
-
-  if (hosts_connected == 0)
-  {
-    LIBMEMCACHED_MEMCACHED_MGET_END();
-
-    if (rc != MEMCACHED_SUCCESS)
-      return rc;
-
-    return MEMCACHED_NO_SERVERS;
-  }
-
-
-  /*
-    Should we muddle on if some servers are dead?
-  */
-  bool success_happened= false;
-  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
-  {
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(ptr, x);
-
-    if (memcached_server_response_count(instance))
-    {
-      /* We need to do something about non-connnected hosts in the future */
-      if ((memcached_io_write(instance, "\r\n", 2, true)) == -1)
-      {
-        failures_occured_in_sending= true;
-      }
-      else
-      {
-        success_happened= true;
-      }
-    }
-  }
-
-  LIBMEMCACHED_MEMCACHED_MGET_END();
-
-  if (failures_occured_in_sending && success_happened)
-    return MEMCACHED_SOME_ERRORS;
-
-  if (success_happened)
-    return MEMCACHED_SUCCESS;
-
-  return MEMCACHED_FAILURE;
-}
-
-memcached_return_t memcached_mget_by_key(memcached_st *ptr,
-                                         const char *group_key,
-                                         size_t group_key_length,
-                                         const char * const *keys,
-                                         const size_t *key_length,
-                                         size_t number_of_keys)
-{
-  return memcached_mget_by_key_real(ptr, group_key, group_key_length, keys,
-                                    key_length, number_of_keys, true);
-}
-
-memcached_return_t memcached_mget_execute(memcached_st *ptr,
-                                          const char * const *keys,
-                                          const size_t *key_length,
-                                          size_t number_of_keys,
-                                          memcached_execute_fn *callback,
-                                          void *context,
-                                          unsigned int number_of_callbacks)
-{
-  return memcached_mget_execute_by_key(ptr, NULL, 0, keys, key_length,
-                                       number_of_keys, callback,
-                                       context, number_of_callbacks);
-}
-
-memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr,
-                                                 const char *group_key,
-                                                 size_t group_key_length,
-                                                 const char * const *keys,
-                                                 const size_t *key_length,
-                                                 size_t number_of_keys,
-                                                 memcached_execute_fn *callback,
-                                                 void *context,
-                                                 unsigned int number_of_callbacks)
-{
-  if ((ptr->flags.binary_protocol) == 0)
-    return MEMCACHED_NOT_SUPPORTED;
-
-  memcached_return_t rc;
-  memcached_callback_st *original_callbacks= ptr->callbacks;
-  memcached_callback_st cb= {
-    .callback= callback,
-    .context= context,
-    .number_of_callback= number_of_callbacks
-  };
-
-  ptr->callbacks= &cb;
-  rc= memcached_mget_by_key(ptr, group_key, group_key_length, keys,
-                            key_length, number_of_keys);
-  ptr->callbacks= original_callbacks;
-  return rc;
-}
-
-static memcached_return_t simple_binary_mget(memcached_st *ptr,
-                                             uint32_t master_server_key,
-                                             bool is_group_key_set,
-                                             const char * const *keys,
-                                             const size_t *key_length,
-                                             size_t number_of_keys, bool mget_mode)
-{
-  memcached_return_t rc= MEMCACHED_NOTFOUND;
-
-  bool flush= (number_of_keys == 1);
-
-  /*
-    If a server fails we warn about errors and start all over with sending keys
-    to the server.
-  */
-  for (uint32_t x= 0; x < number_of_keys; ++x)
-  {
-    uint32_t server_key;
-    memcached_server_write_instance_st instance;
-
-    if (is_group_key_set)
-    {
-      server_key= master_server_key;
-    }
-    else
-    {
-      server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
-    }
-
-    instance= memcached_server_instance_fetch(ptr, server_key);
-
-    if (memcached_server_response_count(instance) == 0)
-    {
-      rc= memcached_connect(instance);
-      if (rc != MEMCACHED_SUCCESS)
-        continue;
-    }
-
-    protocol_binary_request_getk request= {.bytes= {0}};
-    request.message.header.request.magic= PROTOCOL_BINARY_REQ;
-    if (mget_mode)
-      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETKQ;
-    else
-      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
-
-    memcached_return_t vk;
-    vk= memcached_validate_key_length(key_length[x],
-                                      ptr->flags.binary_protocol);
-    unlikely (vk != MEMCACHED_SUCCESS)
-    {
-      if (x > 0)
-      {
-        memcached_io_reset(instance);
-      }
-
-      return vk;
-    }
-
-    request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key)));
-    request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-    request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + memcached_array_size(ptr->prefix_key)));
-
-    struct libmemcached_io_vector_st vector[]=
-    {
-      { .length= sizeof(request.bytes), .buffer= request.bytes },
-      { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
-      { .length= key_length[x], .buffer= keys[x] }
-    };
-
-    if (memcached_io_writev(instance, vector, 3, flush) == -1)
-    {
-      memcached_server_response_reset(instance);
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-
-    /* We just want one pending response per server */
-    memcached_server_response_reset(instance);
-    memcached_server_response_increment(instance);
-    if ((x > 0 && x == ptr->io_key_prefetch) && memcached_flush_buffers(ptr) != MEMCACHED_SUCCESS)
-    {
-      rc= MEMCACHED_SOME_ERRORS;
-    }
-  }
-
-  if (mget_mode)
-  {
-    /*
-     * Send a noop command to flush the buffers
-   */
-    protocol_binary_request_noop request= {.bytes= {0}};
-    request.message.header.request.magic= PROTOCOL_BINARY_REQ;
-    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_NOOP;
-    request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-
-    for (uint32_t x= 0; x < memcached_server_count(ptr); ++x)
-    {
-      memcached_server_write_instance_st instance=
-        memcached_server_instance_fetch(ptr, x);
-
-      if (memcached_server_response_count(instance))
-      {
-        if (memcached_io_write(instance, NULL, 0, true) == -1)
-        {
-          memcached_server_response_reset(instance);
-          memcached_io_reset(instance);
-          rc= MEMCACHED_SOME_ERRORS;
-        }
-
-        if (memcached_io_write(instance, request.bytes,
-                               sizeof(request.bytes), true) == -1)
-        {
-          memcached_server_response_reset(instance);
-          memcached_io_reset(instance);
-          rc= MEMCACHED_SOME_ERRORS;
-        }
-      }
-    }
-  }
-
-
-  return rc;
-}
-
-static memcached_return_t replication_binary_mget(memcached_st *ptr,
-                                                  uint32_t* hash,
-                                                  bool* dead_servers,
-                                                  const char *const *keys,
-                                                  const size_t *key_length,
-                                                  size_t number_of_keys)
-{
-  memcached_return_t rc= MEMCACHED_NOTFOUND;
-  uint32_t start= 0;
-  uint64_t randomize_read= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ);
-
-  if (randomize_read)
-    start= (uint32_t)random() % (uint32_t)(ptr->number_of_replicas + 1);
-
-  /* Loop for each replica */
-  for (uint32_t replica= 0; replica <= ptr->number_of_replicas; ++replica)
-  {
-    bool success= true;
-
-    for (uint32_t x= 0; x < number_of_keys; ++x)
-    {
-      memcached_server_write_instance_st instance;
-
-      if (hash[x] == memcached_server_count(ptr))
-        continue; /* Already successfully sent */
-
-      uint32_t server= hash[x] + replica;
-
-      /* In case of randomized reads */
-      if (randomize_read && ((server + start) <= (hash[x] + ptr->number_of_replicas)))
-        server += start;
-
-      while (server >= memcached_server_count(ptr))
-        server -= memcached_server_count(ptr);
-
-      if (dead_servers[server])
-        continue;
-
-      instance= memcached_server_instance_fetch(ptr, server);
-
-      if (memcached_server_response_count(instance) == 0)
-      {
-        rc= memcached_connect(instance);
-        if (rc != MEMCACHED_SUCCESS)
-        {
-          memcached_io_reset(instance);
-          dead_servers[server]= true;
-          success= false;
-          continue;
-        }
-      }
-
-      protocol_binary_request_getk request= {
-        .message.header.request= {
-          .magic= PROTOCOL_BINARY_REQ,
-          .opcode= PROTOCOL_BINARY_CMD_GETK,
-          .keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key))),
-          .datatype= PROTOCOL_BINARY_RAW_BYTES,
-          .bodylen= htonl((uint32_t)(key_length[x] + memcached_array_size(ptr->prefix_key)))
-        }
-      };
-
-      /*
-       * We need to disable buffering to actually know that the request was
-       * successfully sent to the server (so that we should expect a result
-       * back). It would be nice to do this in buffered mode, but then it
-       * would be complex to handle all error situations if we got to send
-       * some of the messages, and then we failed on writing out some others
-       * and we used the callback interface from memcached_mget_execute so
-       * that we might have processed some of the responses etc. For now,
-       * just make sure we work _correctly_
-     */
-      struct libmemcached_io_vector_st vector[]=
-      {
-        { .length= sizeof(request.bytes), .buffer= request.bytes },
-        { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
-        { .length= key_length[x], .buffer= keys[x] }
-      };
-
-      if (memcached_io_writev(instance, vector, 3, true) == -1)
-      {
-        memcached_io_reset(instance);
-        dead_servers[server]= true;
-        success= false;
-        continue;
-      }
-
-      memcached_server_response_increment(instance);
-      hash[x]= memcached_server_count(ptr);
-    }
-
-    if (success)
-      break;
-  }
-
-  return rc;
-}
-
-static memcached_return_t binary_mget_by_key(memcached_st *ptr,
-                                             uint32_t master_server_key,
-                                             bool is_group_key_set,
-                                             const char * const *keys,
-                                             const size_t *key_length,
-                                             size_t number_of_keys,
-                                             bool mget_mode)
-{
-  memcached_return_t rc;
-
-  if (ptr->number_of_replicas == 0)
-  {
-    rc= simple_binary_mget(ptr, master_server_key, is_group_key_set,
-                           keys, key_length, number_of_keys, mget_mode);
-  }
-  else
-  {
-    uint32_t* hash;
-    bool* dead_servers;
-
-    hash= libmemcached_malloc(ptr, sizeof(uint32_t) * number_of_keys);
-    dead_servers= libmemcached_calloc(ptr, memcached_server_count(ptr), sizeof(bool));
-
-    if (hash == NULL || dead_servers == NULL)
-    {
-      libmemcached_free(ptr, hash);
-      libmemcached_free(ptr, dead_servers);
-      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-    }
-
-    if (is_group_key_set)
-    {
-      for (size_t x= 0; x < number_of_keys; x++)
-      {
-        hash[x]= master_server_key;
-      }
-    }
-    else
-    {
-      for (size_t x= 0; x < number_of_keys; x++)
-      {
-        hash[x]= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
-      }
-    }
-
-    rc= replication_binary_mget(ptr, hash, dead_servers, keys,
-                                key_length, number_of_keys);
-
-    libmemcached_free(ptr, hash);
-    libmemcached_free(ptr, dead_servers);
-
-    return MEMCACHED_SUCCESS;
-  }
-
-  return rc;
-}
diff --git a/libmemcached/get.cc b/libmemcached/get.cc
new file mode 100644 (file)
index 0000000..29d01bc
--- /dev/null
@@ -0,0 +1,648 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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: Get functions for libmemcached
+ *
+ */
+
+#include "common.h"
+
+/*
+  What happens if no servers exist?
+*/
+char *memcached_get(memcached_st *ptr, const char *key,
+                    size_t key_length,
+                    size_t *value_length,
+                    uint32_t *flags,
+                    memcached_return_t *error)
+{
+  return memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length,
+                              flags, error);
+}
+
+static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
+                                                     const char *group_key,
+                                                     size_t group_key_length,
+                                                     const char * const *keys,
+                                                     const size_t *key_length,
+                                                     size_t number_of_keys,
+                                                     bool mget_mode);
+
+char *memcached_get_by_key(memcached_st *ptr,
+                           const char *group_key,
+                           size_t group_key_length,
+                           const char *key, size_t key_length,
+                           size_t *value_length,
+                           uint32_t *flags,
+                           memcached_return_t *error)
+{
+  char *value;
+  size_t dummy_length;
+  uint32_t dummy_flags;
+  memcached_return_t dummy_error;
+
+  unlikely (ptr->flags.use_udp)
+  {
+    *error= MEMCACHED_NOT_SUPPORTED;
+    return NULL;
+  }
+
+  /* Request the key */
+  *error= memcached_mget_by_key_real(ptr, group_key, group_key_length,
+                                     (const char * const *)&key,
+                                     &key_length, 1, false);
+
+  value= memcached_fetch(ptr, NULL, NULL,
+                         value_length, flags, error);
+  /* This is for historical reasons */
+  if (*error == MEMCACHED_END)
+    *error= MEMCACHED_NOTFOUND;
+
+  if (value == NULL)
+  {
+    if (ptr->get_key_failure && *error == MEMCACHED_NOTFOUND)
+    {
+      memcached_return_t rc;
+
+      memcached_result_reset(&ptr->result);
+      rc= ptr->get_key_failure(ptr, key, key_length, &ptr->result);
+
+      /* On all failure drop to returning NULL */
+      if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
+      {
+        if (rc == MEMCACHED_BUFFERED)
+        {
+          uint64_t latch; /* We use latch to track the state of the original socket */
+          latch= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
+          if (latch == 0)
+            memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
+
+          rc= memcached_set(ptr, key, key_length,
+                            (memcached_result_value(&ptr->result)),
+                            (memcached_result_length(&ptr->result)),
+                            0,
+                            (memcached_result_flags(&ptr->result)));
+
+          if (rc == MEMCACHED_BUFFERED && latch == 0)
+            memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
+        }
+        else
+        {
+          rc= memcached_set(ptr, key, key_length,
+                            (memcached_result_value(&ptr->result)),
+                            (memcached_result_length(&ptr->result)),
+                            0,
+                            (memcached_result_flags(&ptr->result)));
+        }
+
+        if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED)
+        {
+          *error= rc;
+          *value_length= memcached_result_length(&ptr->result);
+          *flags= memcached_result_flags(&ptr->result);
+          return memcached_string_c_copy(&ptr->result.value);
+        }
+      }
+    }
+
+    return NULL;
+  }
+
+  (void)memcached_fetch(ptr, NULL, NULL,
+                        &dummy_length, &dummy_flags,
+                        &dummy_error);
+  WATCHPOINT_ASSERT(dummy_length == 0);
+
+  return value;
+}
+
+memcached_return_t memcached_mget(memcached_st *ptr,
+                                  const char * const *keys,
+                                  const size_t *key_length,
+                                  size_t number_of_keys)
+{
+  return memcached_mget_by_key(ptr, NULL, 0, keys, key_length, number_of_keys);
+}
+
+static memcached_return_t binary_mget_by_key(memcached_st *ptr,
+                                             uint32_t master_server_key,
+                                             bool is_group_key_set,
+                                             const char * const *keys,
+                                             const size_t *key_length,
+                                             size_t number_of_keys,
+                                             bool mget_mode);
+
+static memcached_return_t memcached_mget_by_key_real(memcached_st *ptr,
+                                                     const char *group_key,
+                                                     size_t group_key_length,
+                                                     const char * const *keys,
+                                                     const size_t *key_length,
+                                                     size_t number_of_keys,
+                                                     bool mget_mode)
+{
+  bool failures_occured_in_sending= false;
+  const char *get_command= "get ";
+  uint8_t get_command_length= 4;
+  unsigned int master_server_key= (unsigned int)-1; /* 0 is a valid server id! */
+  bool is_group_key_set= false;
+
+  memcached_return_t rc;
+  if (memcached_failed(rc= initialize_query(ptr)))
+  {
+    return rc;
+  }
+
+  unlikely (ptr->flags.use_udp)
+    return MEMCACHED_NOT_SUPPORTED;
+
+  LIBMEMCACHED_MEMCACHED_MGET_START();
+
+  if (number_of_keys == 0)
+    return MEMCACHED_NOTFOUND;
+
+  if (ptr->flags.verify_key && (memcached_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED))
+  {
+    return MEMCACHED_BAD_KEY_PROVIDED;
+  }
+
+  if (group_key && group_key_length)
+  {
+    if (ptr->flags.verify_key and (memcached_key_test((const char * const *)&group_key, &group_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+      return MEMCACHED_BAD_KEY_PROVIDED;
+
+    master_server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
+    is_group_key_set= true;
+  }
+
+  /*
+    Here is where we pay for the non-block API. We need to remove any data sitting
+    in the queue before we start our get.
+
+    It might be optimum to bounce the connection if count > some number.
+  */
+  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    if (memcached_server_response_count(instance))
+    {
+      char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+      if (ptr->flags.no_block)
+        (void)memcached_io_write(instance, NULL, 0, true);
+
+      while(memcached_server_response_count(instance))
+        (void)memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
+    }
+  }
+
+  if (ptr->flags.binary_protocol)
+  {
+    return binary_mget_by_key(ptr, master_server_key, is_group_key_set, keys,
+                              key_length, number_of_keys, mget_mode);
+  }
+
+  if (ptr->flags.support_cas)
+  {
+    get_command= "gets ";
+    get_command_length= 5;
+  }
+
+  /*
+    If a server fails we warn about errors and start all over with sending keys
+    to the server.
+  */
+  WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
+  size_t hosts_connected= 0;
+  for (uint32_t x= 0; x < number_of_keys; x++)
+  {
+    memcached_server_write_instance_st instance;
+    uint32_t server_key;
+
+    if (is_group_key_set)
+    {
+      server_key= master_server_key;
+    }
+    else
+    {
+      server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
+    }
+
+    instance= memcached_server_instance_fetch(ptr, server_key);
+
+    struct libmemcached_io_vector_st vector[]=
+    {
+      { get_command_length, get_command },
+      { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) },
+      { key_length[x], keys[x] },
+      { 1, " " }
+    };
+
+
+    if (memcached_server_response_count(instance) == 0)
+    {
+      rc= memcached_connect(instance);
+
+      if (rc != MEMCACHED_SUCCESS)
+      {
+        continue;
+      }
+      hosts_connected++;
+
+      if ((memcached_io_writev(instance, vector, 4, false)) == -1)
+      {
+        failures_occured_in_sending= true;
+        continue;
+      }
+      WATCHPOINT_ASSERT(instance->cursor_active == 0);
+      memcached_server_response_increment(instance);
+      WATCHPOINT_ASSERT(instance->cursor_active == 1);
+    }
+    else
+    {
+      if ((memcached_io_writev(instance, (vector + 1), 3, false)) == -1)
+      {
+        memcached_server_response_reset(instance);
+        failures_occured_in_sending= true;
+        continue;
+      }
+    }
+  }
+
+  if (hosts_connected == 0)
+  {
+    LIBMEMCACHED_MEMCACHED_MGET_END();
+
+    if (rc != MEMCACHED_SUCCESS)
+      return rc;
+
+    return MEMCACHED_NO_SERVERS;
+  }
+
+
+  /*
+    Should we muddle on if some servers are dead?
+  */
+  bool success_happened= false;
+  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    if (memcached_server_response_count(instance))
+    {
+      /* We need to do something about non-connnected hosts in the future */
+      if ((memcached_io_write(instance, "\r\n", 2, true)) == -1)
+      {
+        failures_occured_in_sending= true;
+      }
+      else
+      {
+        success_happened= true;
+      }
+    }
+  }
+
+  LIBMEMCACHED_MEMCACHED_MGET_END();
+
+  if (failures_occured_in_sending && success_happened)
+    return MEMCACHED_SOME_ERRORS;
+
+  if (success_happened)
+    return MEMCACHED_SUCCESS;
+
+  return MEMCACHED_FAILURE;
+}
+
+memcached_return_t memcached_mget_by_key(memcached_st *ptr,
+                                         const char *group_key,
+                                         size_t group_key_length,
+                                         const char * const *keys,
+                                         const size_t *key_length,
+                                         size_t number_of_keys)
+{
+  return memcached_mget_by_key_real(ptr, group_key, group_key_length, keys,
+                                    key_length, number_of_keys, true);
+}
+
+memcached_return_t memcached_mget_execute(memcached_st *ptr,
+                                          const char * const *keys,
+                                          const size_t *key_length,
+                                          size_t number_of_keys,
+                                          memcached_execute_fn *callback,
+                                          void *context,
+                                          unsigned int number_of_callbacks)
+{
+  return memcached_mget_execute_by_key(ptr, NULL, 0, keys, key_length,
+                                       number_of_keys, callback,
+                                       context, number_of_callbacks);
+}
+
+memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr,
+                                                 const char *group_key,
+                                                 size_t group_key_length,
+                                                 const char * const *keys,
+                                                 const size_t *key_length,
+                                                 size_t number_of_keys,
+                                                 memcached_execute_fn *callback,
+                                                 void *context,
+                                                 unsigned int number_of_callbacks)
+{
+  if ((ptr->flags.binary_protocol) == 0)
+    return MEMCACHED_NOT_SUPPORTED;
+
+  memcached_return_t rc;
+  memcached_callback_st *original_callbacks= ptr->callbacks;
+  memcached_callback_st cb= {
+    callback,
+    context,
+    number_of_callbacks
+  };
+
+  ptr->callbacks= &cb;
+  rc= memcached_mget_by_key(ptr, group_key, group_key_length, keys,
+                            key_length, number_of_keys);
+  ptr->callbacks= original_callbacks;
+  return rc;
+}
+
+static memcached_return_t simple_binary_mget(memcached_st *ptr,
+                                             uint32_t master_server_key,
+                                             bool is_group_key_set,
+                                             const char * const *keys,
+                                             const size_t *key_length,
+                                             size_t number_of_keys, bool mget_mode)
+{
+  memcached_return_t rc= MEMCACHED_NOTFOUND;
+
+  bool flush= (number_of_keys == 1);
+
+  /*
+    If a server fails we warn about errors and start all over with sending keys
+    to the server.
+  */
+  for (uint32_t x= 0; x < number_of_keys; ++x)
+  {
+    uint32_t server_key;
+    memcached_server_write_instance_st instance;
+
+    if (is_group_key_set)
+    {
+      server_key= master_server_key;
+    }
+    else
+    {
+      server_key= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
+    }
+
+    instance= memcached_server_instance_fetch(ptr, server_key);
+
+    if (memcached_server_response_count(instance) == 0)
+    {
+      rc= memcached_connect(instance);
+      if (rc != MEMCACHED_SUCCESS)
+        continue;
+    }
+
+    protocol_binary_request_getk request= { }; //= {.bytes= {0}};
+    request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+    if (mget_mode)
+      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETKQ;
+    else
+      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
+
+    memcached_return_t vk;
+    vk= memcached_validate_key_length(key_length[x],
+                                      ptr->flags.binary_protocol);
+    unlikely (vk != MEMCACHED_SUCCESS)
+    {
+      if (x > 0)
+      {
+        memcached_io_reset(instance);
+      }
+
+      return vk;
+    }
+
+    request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key)));
+    request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+    request.message.header.request.bodylen= htonl((uint32_t)( key_length[x] + memcached_array_size(ptr->prefix_key)));
+
+    struct libmemcached_io_vector_st vector[]=
+    {
+      { sizeof(request.bytes), request.bytes },
+      { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) },
+      { key_length[x], keys[x] }
+    };
+
+    if (memcached_io_writev(instance, vector, 3, flush) == -1)
+    {
+      memcached_server_response_reset(instance);
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+
+    /* We just want one pending response per server */
+    memcached_server_response_reset(instance);
+    memcached_server_response_increment(instance);
+    if ((x > 0 && x == ptr->io_key_prefetch) && memcached_flush_buffers(ptr) != MEMCACHED_SUCCESS)
+    {
+      rc= MEMCACHED_SOME_ERRORS;
+    }
+  }
+
+  if (mget_mode)
+  {
+    /*
+      Send a noop command to flush the buffers
+    */
+    protocol_binary_request_noop request= {}; //= {.bytes= {0}};
+    request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_NOOP;
+    request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+    for (uint32_t x= 0; x < memcached_server_count(ptr); ++x)
+    {
+      memcached_server_write_instance_st instance=
+        memcached_server_instance_fetch(ptr, x);
+
+      if (memcached_server_response_count(instance))
+      {
+        if (memcached_io_write(instance, NULL, 0, true) == -1)
+        {
+          memcached_server_response_reset(instance);
+          memcached_io_reset(instance);
+          rc= MEMCACHED_SOME_ERRORS;
+        }
+
+        if (memcached_io_write(instance, request.bytes,
+                               sizeof(request.bytes), true) == -1)
+        {
+          memcached_server_response_reset(instance);
+          memcached_io_reset(instance);
+          rc= MEMCACHED_SOME_ERRORS;
+        }
+      }
+    }
+  }
+
+
+  return rc;
+}
+
+static memcached_return_t replication_binary_mget(memcached_st *ptr,
+                                                  uint32_t* hash,
+                                                  bool* dead_servers,
+                                                  const char *const *keys,
+                                                  const size_t *key_length,
+                                                  size_t number_of_keys)
+{
+  memcached_return_t rc= MEMCACHED_NOTFOUND;
+  uint32_t start= 0;
+  uint64_t randomize_read= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ);
+
+  if (randomize_read)
+    start= (uint32_t)random() % (uint32_t)(ptr->number_of_replicas + 1);
+
+  /* Loop for each replica */
+  for (uint32_t replica= 0; replica <= ptr->number_of_replicas; ++replica)
+  {
+    bool success= true;
+
+    for (uint32_t x= 0; x < number_of_keys; ++x)
+    {
+      memcached_server_write_instance_st instance;
+
+      if (hash[x] == memcached_server_count(ptr))
+        continue; /* Already successfully sent */
+
+      uint32_t server= hash[x] + replica;
+
+      /* In case of randomized reads */
+      if (randomize_read && ((server + start) <= (hash[x] + ptr->number_of_replicas)))
+        server += start;
+
+      while (server >= memcached_server_count(ptr))
+        server -= memcached_server_count(ptr);
+
+      if (dead_servers[server])
+        continue;
+
+      instance= memcached_server_instance_fetch(ptr, server);
+
+      if (memcached_server_response_count(instance) == 0)
+      {
+        rc= memcached_connect(instance);
+        if (rc != MEMCACHED_SUCCESS)
+        {
+          memcached_io_reset(instance);
+          dead_servers[server]= true;
+          success= false;
+          continue;
+        }
+      }
+
+      protocol_binary_request_getk request= {};
+      request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_GETK;
+      request.message.header.request.keylen= htons((uint16_t)(key_length[x] + memcached_array_size(ptr->prefix_key)));
+      request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+      request.message.header.request.bodylen= htonl((uint32_t)(key_length[x] + memcached_array_size(ptr->prefix_key)));
+
+      /*
+       * We need to disable buffering to actually know that the request was
+       * successfully sent to the server (so that we should expect a result
+       * back). It would be nice to do this in buffered mode, but then it
+       * would be complex to handle all error situations if we got to send
+       * some of the messages, and then we failed on writing out some others
+       * and we used the callback interface from memcached_mget_execute so
+       * that we might have processed some of the responses etc. For now,
+       * just make sure we work _correctly_
+     */
+      struct libmemcached_io_vector_st vector[]=
+      {
+        { sizeof(request.bytes), request.bytes },
+        { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) },
+        { key_length[x], keys[x] }
+      };
+
+      if (memcached_io_writev(instance, vector, 3, true) == -1)
+      {
+        memcached_io_reset(instance);
+        dead_servers[server]= true;
+        success= false;
+        continue;
+      }
+
+      memcached_server_response_increment(instance);
+      hash[x]= memcached_server_count(ptr);
+    }
+
+    if (success)
+      break;
+  }
+
+  return rc;
+}
+
+static memcached_return_t binary_mget_by_key(memcached_st *ptr,
+                                             uint32_t master_server_key,
+                                             bool is_group_key_set,
+                                             const char * const *keys,
+                                             const size_t *key_length,
+                                             size_t number_of_keys,
+                                             bool mget_mode)
+{
+  memcached_return_t rc;
+
+  if (ptr->number_of_replicas == 0)
+  {
+    rc= simple_binary_mget(ptr, master_server_key, is_group_key_set,
+                           keys, key_length, number_of_keys, mget_mode);
+  }
+  else
+  {
+    uint32_t* hash;
+    bool* dead_servers;
+
+    hash= static_cast<uint32_t*>(libmemcached_malloc(ptr, sizeof(uint32_t) * number_of_keys));
+    dead_servers= static_cast<bool*>(libmemcached_calloc(ptr, memcached_server_count(ptr), sizeof(bool)));
+
+    if (hash == NULL || dead_servers == NULL)
+    {
+      libmemcached_free(ptr, hash);
+      libmemcached_free(ptr, dead_servers);
+      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+    }
+
+    if (is_group_key_set)
+    {
+      for (size_t x= 0; x < number_of_keys; x++)
+      {
+        hash[x]= master_server_key;
+      }
+    }
+    else
+    {
+      for (size_t x= 0; x < number_of_keys; x++)
+      {
+        hash[x]= memcached_generate_hash_with_redistribution(ptr, keys[x], key_length[x]);
+      }
+    }
+
+    rc= replication_binary_mget(ptr, hash, dead_servers, keys,
+                                key_length, number_of_keys);
+
+    libmemcached_free(ptr, hash);
+    libmemcached_free(ptr, dead_servers);
+
+    return MEMCACHED_SUCCESS;
+  }
+
+  return rc;
+}
diff --git a/libmemcached/hash.c b/libmemcached/hash.c
deleted file mode 100644 (file)
index e5f87a7..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- * 
- *  Libmemcached library
- *
- *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *  Copyright (C) 2006-2009 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/virtual_bucket.h>
-
-
-uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm)
-{
-  return libhashkit_digest(key, key_length, (hashkit_hash_algorithm_t)hash_algorithm);
-}
-
-static inline uint32_t generate_hash(const memcached_st *ptr, const char *key, size_t key_length)
-{
-  return hashkit_digest(&ptr->hashkit, key, key_length);
-}
-
-static uint32_t dispatch_host(const memcached_st *ptr, uint32_t hash)
-{
-  switch (ptr->distribution)
-  {
-  case MEMCACHED_DISTRIBUTION_CONSISTENT:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
-    {
-      uint32_t num= ptr->ketama.continuum_points_counter;
-      WATCHPOINT_ASSERT(ptr->continuum);
-
-      hash= hash;
-      memcached_continuum_item_st *begin, *end, *left, *right, *middle;
-      begin= left= ptr->ketama.continuum;
-      end= right= ptr->ketama.continuum + num;
-
-      while (left < right)
-      {
-        middle= left + (right - left) / 2;
-        if (middle->value < hash)
-          left= middle + 1;
-        else
-          right= middle;
-      }
-      if (right == end)
-        right= begin;
-      return right->index;
-    }
-  case MEMCACHED_DISTRIBUTION_MODULA:
-    return hash % memcached_server_count(ptr);
-  case MEMCACHED_DISTRIBUTION_RANDOM:
-    return (uint32_t) random() % memcached_server_count(ptr);
-  case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
-    {
-      return memcached_virtual_bucket_get(ptr, hash);
-    }
-  default:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
-    WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
-    return hash % memcached_server_count(ptr);
-  }
-  /* NOTREACHED */
-}
-
-/*
-  One version is public and will not modify the distribution hash, the other will.
-*/
-static inline uint32_t _generate_hash_wrapper(const memcached_st *ptr, const char *key, size_t key_length)
-{
-  WATCHPOINT_ASSERT(memcached_server_count(ptr));
-
-  if (memcached_server_count(ptr) == 1)
-    return 0;
-
-  if (ptr->flags.hash_with_prefix_key)
-  {
-    size_t temp_length= memcached_array_size(ptr->prefix_key) + key_length;
-    char temp[temp_length];
-
-    if (temp_length > MEMCACHED_MAX_KEY -1)
-      return 0;
-
-    strncpy(temp, memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key));
-    strncpy(temp + memcached_array_size(ptr->prefix_key), key, key_length);
-
-    return generate_hash(ptr, temp, temp_length);
-  }
-  else
-  {
-    return generate_hash(ptr, key, key_length);
-  }
-}
-
-static inline void _regen_for_auto_eject(memcached_st *ptr)
-{
-  if (_is_auto_eject_host(ptr) && ptr->ketama.next_distribution_rebuild)
-  {
-    struct timeval now;
-
-    if (gettimeofday(&now, NULL) == 0 &&
-        now.tv_sec > ptr->ketama.next_distribution_rebuild)
-    {
-      run_distribution(ptr);
-    }
-  }
-}
-
-void memcached_autoeject(memcached_st *ptr)
-{
-  _regen_for_auto_eject(ptr);
-}
-
-uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length)
-{
-  uint32_t hash= _generate_hash_wrapper(ptr, key, key_length);
-
-  _regen_for_auto_eject(ptr);
-
-  return dispatch_host(ptr, hash);
-}
-
-uint32_t memcached_generate_hash(const memcached_st *ptr, const char *key, size_t key_length)
-{
-  return dispatch_host(ptr, _generate_hash_wrapper(ptr, key, key_length));
-}
-
-const hashkit_st *memcached_get_hashkit(const memcached_st *ptr)
-{
-  return &ptr->hashkit;
-}
-
-memcached_return_t memcached_set_hashkit(memcached_st *self, hashkit_st *hashk)
-{
-  hashkit_free(&self->hashkit);
-  hashkit_clone(&self->hashkit, hashk);
-
-  return MEMCACHED_SUCCESS;
-}
-
-const char * libmemcached_string_hash(memcached_hash_t type)
-{
-  return libhashkit_string_hash((hashkit_hash_algorithm_t)type);
-}
diff --git a/libmemcached/hash.cc b/libmemcached/hash.cc
new file mode 100644 (file)
index 0000000..0e6295b
--- /dev/null
@@ -0,0 +1,176 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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/virtual_bucket.h>
+
+
+uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm)
+{
+  return libhashkit_digest(key, key_length, (hashkit_hash_algorithm_t)hash_algorithm);
+}
+
+static inline uint32_t generate_hash(const memcached_st *ptr, const char *key, size_t key_length)
+{
+  return hashkit_digest(&ptr->hashkit, key, key_length);
+}
+
+static uint32_t dispatch_host(const memcached_st *ptr, uint32_t hash)
+{
+  switch (ptr->distribution)
+  {
+  case MEMCACHED_DISTRIBUTION_CONSISTENT:
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+    {
+      uint32_t num= ptr->ketama.continuum_points_counter;
+      WATCHPOINT_ASSERT(ptr->continuum);
+
+      hash= hash;
+      memcached_continuum_item_st *begin, *end, *left, *right, *middle;
+      begin= left= ptr->ketama.continuum;
+      end= right= ptr->ketama.continuum + num;
+
+      while (left < right)
+      {
+        middle= left + (right - left) / 2;
+        if (middle->value < hash)
+          left= middle + 1;
+        else
+          right= middle;
+      }
+      if (right == end)
+        right= begin;
+      return right->index;
+    }
+  case MEMCACHED_DISTRIBUTION_MODULA:
+    return hash % memcached_server_count(ptr);
+  case MEMCACHED_DISTRIBUTION_RANDOM:
+    return (uint32_t) random() % memcached_server_count(ptr);
+  case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
+    {
+      return memcached_virtual_bucket_get(ptr, hash);
+    }
+  default:
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
+    WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
+    return hash % memcached_server_count(ptr);
+  }
+  /* NOTREACHED */
+}
+
+/*
+  One version is public and will not modify the distribution hash, the other will.
+*/
+static inline uint32_t _generate_hash_wrapper(const memcached_st *ptr, const char *key, size_t key_length)
+{
+  WATCHPOINT_ASSERT(memcached_server_count(ptr));
+
+  if (memcached_server_count(ptr) == 1)
+    return 0;
+
+  if (ptr->flags.hash_with_prefix_key)
+  {
+    size_t temp_length= memcached_array_size(ptr->prefix_key) + key_length;
+    char temp[MEMCACHED_MAX_KEY];
+
+    if (temp_length > MEMCACHED_MAX_KEY -1)
+      return 0;
+
+    strncpy(temp, memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key));
+    strncpy(temp + memcached_array_size(ptr->prefix_key), key, key_length);
+
+    return generate_hash(ptr, temp, temp_length);
+  }
+  else
+  {
+    return generate_hash(ptr, key, key_length);
+  }
+}
+
+static inline void _regen_for_auto_eject(memcached_st *ptr)
+{
+  if (_is_auto_eject_host(ptr) && ptr->ketama.next_distribution_rebuild)
+  {
+    struct timeval now;
+
+    if (gettimeofday(&now, NULL) == 0 &&
+        now.tv_sec > ptr->ketama.next_distribution_rebuild)
+    {
+      run_distribution(ptr);
+    }
+  }
+}
+
+void memcached_autoeject(memcached_st *ptr)
+{
+  _regen_for_auto_eject(ptr);
+}
+
+uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length)
+{
+  uint32_t hash= _generate_hash_wrapper(ptr, key, key_length);
+
+  _regen_for_auto_eject(ptr);
+
+  return dispatch_host(ptr, hash);
+}
+
+uint32_t memcached_generate_hash(const memcached_st *ptr, const char *key, size_t key_length)
+{
+  return dispatch_host(ptr, _generate_hash_wrapper(ptr, key, key_length));
+}
+
+const hashkit_st *memcached_get_hashkit(const memcached_st *ptr)
+{
+  return &ptr->hashkit;
+}
+
+memcached_return_t memcached_set_hashkit(memcached_st *self, hashkit_st *hashk)
+{
+  hashkit_free(&self->hashkit);
+  hashkit_clone(&self->hashkit, hashk);
+
+  return MEMCACHED_SUCCESS;
+}
+
+const char * libmemcached_string_hash(memcached_hash_t type)
+{
+  return libhashkit_string_hash((hashkit_hash_algorithm_t)type);
+}
diff --git a/libmemcached/hosts.c b/libmemcached/hosts.c
deleted file mode 100644 (file)
index 7e68766..0000000
+++ /dev/null
@@ -1,451 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-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: 
- *
- */
-
-#include "common.h"
-#include <math.h>
-
-/* Protoypes (static) */
-static memcached_return_t server_add(memcached_st *ptr, const char *hostname,
-                                     in_port_t port,
-                                     uint32_t weight,
-                                     memcached_connection_t type);
-
-static memcached_return_t update_continuum(memcached_st *ptr);
-
-static int compare_servers(const void *p1, const void *p2)
-{
-  int return_value;
-  memcached_server_instance_st a= (memcached_server_instance_st)p1;
-  memcached_server_instance_st b= (memcached_server_instance_st)p2;
-
-  return_value= strcmp(a->hostname, b->hostname);
-
-  if (return_value == 0)
-  {
-    return_value= (int) (a->port - b->port);
-  }
-
-  return return_value;
-}
-
-static void sort_hosts(memcached_st *ptr)
-{
-  if (memcached_server_count(ptr))
-  {
-    memcached_server_write_instance_st instance;
-
-    qsort(memcached_server_list(ptr), memcached_server_count(ptr), sizeof(memcached_server_st), compare_servers);
-    instance= memcached_server_instance_fetch(ptr, 0);
-    instance->number_of_hosts= memcached_server_count(ptr);
-  }
-}
-
-
-memcached_return_t run_distribution(memcached_st *ptr)
-{
-  if (ptr->flags.use_sort_hosts)
-    sort_hosts(ptr);
-
-  switch (ptr->distribution)
-  {
-  case MEMCACHED_DISTRIBUTION_CONSISTENT:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
-    return update_continuum(ptr);
-  case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
-  case MEMCACHED_DISTRIBUTION_MODULA:
-    break;
-  case MEMCACHED_DISTRIBUTION_RANDOM:
-    srandom((uint32_t) time(NULL));
-    break;
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
-  default:
-    WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-static uint32_t ketama_server_hash(const char *key, size_t key_length, uint32_t alignment)
-{
-  unsigned char results[16];
-
-  libhashkit_md5_signature((unsigned char*)key, key_length, results);
-
-  return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
-    | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
-    | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
-    | (results[0 + alignment * 4] & 0xFF);
-}
-
-static int continuum_item_cmp(const void *t1, const void *t2)
-{
-  memcached_continuum_item_st *ct1= (memcached_continuum_item_st *)t1;
-  memcached_continuum_item_st *ct2= (memcached_continuum_item_st *)t2;
-
-  /* Why 153? Hmmm... */
-  WATCHPOINT_ASSERT(ct1->value != 153);
-  if (ct1->value == ct2->value)
-    return 0;
-  else if (ct1->value > ct2->value)
-    return 1;
-  else
-    return -1;
-}
-
-static memcached_return_t update_continuum(memcached_st *ptr)
-{
-  uint32_t continuum_index= 0;
-  memcached_server_st *list;
-  uint32_t pointer_counter= 0;
-  uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
-  uint32_t pointer_per_hash= 1;
-  uint32_t live_servers= 0;
-  struct timeval now;
-
-  if (gettimeofday(&now, NULL) != 0)
-  {
-    memcached_set_errno(ptr, errno, NULL);
-    return MEMCACHED_ERRNO;
-  }
-
-  list= memcached_server_list(ptr);
-
-  /* count live servers (those without a retry delay set) */
-  bool is_auto_ejecting= _is_auto_eject_host(ptr);
-  if (is_auto_ejecting)
-  {
-    live_servers= 0;
-    ptr->ketama.next_distribution_rebuild= 0;
-    for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
-    {
-      if (list[host_index].next_retry <= now.tv_sec)
-        live_servers++;
-      else
-      {
-        if (ptr->ketama.next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->ketama.next_distribution_rebuild)
-          ptr->ketama.next_distribution_rebuild= list[host_index].next_retry;
-      }
-    }
-  }
-  else
-  {
-    live_servers= memcached_server_count(ptr);
-  }
-
-  uint64_t is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
-  uint32_t points_per_server= (uint32_t) (is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER);
-
-  if (live_servers == 0)
-    return MEMCACHED_SUCCESS;
-
-  if (live_servers > ptr->ketama.continuum_count)
-  {
-    memcached_continuum_item_st *new_ptr;
-
-    new_ptr= libmemcached_realloc(ptr, ptr->ketama.continuum,
-                                  sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server);
-
-    if (new_ptr == 0)
-      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-    ptr->ketama.continuum= new_ptr;
-    ptr->ketama.continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION;
-  }
-
-  uint64_t total_weight= 0;
-  if (is_ketama_weighted)
-  {
-    for (uint32_t host_index = 0; host_index < memcached_server_count(ptr); ++host_index)
-    {
-      if (! is_auto_ejecting || list[host_index].next_retry <= now.tv_sec)
-      {
-        total_weight += list[host_index].weight;
-      }
-    }
-  }
-
-  for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
-  {
-    if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec)
-      continue;
-
-    if (is_ketama_weighted)
-    {
-        float pct = (float)list[host_index].weight / (float)total_weight;
-        pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4);
-        pointer_per_hash= 4;
-#ifdef DEBUG
-        printf("ketama_weighted:%s|%d|%llu|%u\n",
-               list[host_index].hostname,
-               list[host_index].port,
-               (unsigned long long)list[host_index].weight,
-               pointer_per_server);
-#endif
-    }
-
-
-    if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY)
-    {
-      for (uint32_t pointer_index= 0;
-           pointer_index < pointer_per_server / pointer_per_hash;
-           pointer_index++)
-      {
-        char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
-        int sort_host_length;
-
-        // Spymemcached ketema key format is: hostname/ip:port-index
-        // If hostname is not available then: /ip:port-index
-        sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
-                                   "/%s:%u-%u",
-                                   list[host_index].hostname,
-                                   (uint32_t)list[host_index].port,
-                                   pointer_index);
-
-        if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0)
-        {
-          return MEMCACHED_FAILURE;
-        }
-#ifdef DEBUG
-        printf("update_continuum: key is %s\n", sort_host);
-#endif
-
-        WATCHPOINT_ASSERT(sort_host_length);
-
-        if (is_ketama_weighted)
-        {
-          for (uint32_t x= 0; x < pointer_per_hash; x++)
-          {
-            uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
-             ptr->ketama.continuum[continuum_index].index= host_index;
-             ptr->ketama.continuum[continuum_index++].value= value;
-          }
-        }
-        else
-        {
-          uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length);
-          ptr->ketama.continuum[continuum_index].index= host_index;
-          ptr->ketama.continuum[continuum_index++].value= value;
-        }
-      }
-    }
-    else
-    {
-      for (uint32_t pointer_index= 1;
-           pointer_index <= pointer_per_server / pointer_per_hash;
-           pointer_index++)
-      {
-        char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
-        int sort_host_length;
-
-        if (list[host_index].port == MEMCACHED_DEFAULT_PORT)
-        {
-          sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
-                                     "%s-%u",
-                                     list[host_index].hostname,
-                                     pointer_index - 1);
-        }
-        else
-        {
-          sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
-                                     "%s:%u-%u",
-                                     list[host_index].hostname,
-                                     (uint32_t)list[host_index].port,
-                                     pointer_index - 1);
-        }
-
-        if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0)
-        {
-          return MEMCACHED_FAILURE;
-        }
-
-        WATCHPOINT_ASSERT(sort_host_length);
-
-        if (is_ketama_weighted)
-        {
-          for (uint32_t x = 0; x < pointer_per_hash; x++)
-          {
-             uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
-             ptr->ketama.continuum[continuum_index].index= host_index;
-             ptr->ketama.continuum[continuum_index++].value= value;
-          }
-        }
-        else
-        {
-          uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length);
-          ptr->ketama.continuum[continuum_index].index= host_index;
-          ptr->ketama.continuum[continuum_index++].value= value;
-        }
-      }
-    }
-
-    pointer_counter+= pointer_per_server;
-  }
-
-  WATCHPOINT_ASSERT(ptr);
-  WATCHPOINT_ASSERT(ptr->continuum);
-  WATCHPOINT_ASSERT(memcached_server_count(ptr) * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE);
-  ptr->ketama.continuum_points_counter= pointer_counter;
-  qsort(ptr->ketama.continuum, ptr->ketama.continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);
-
-#ifdef DEBUG
-  for (uint32_t pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++)
-  {
-    WATCHPOINT_ASSERT(ptr->continuum[pointer_index].value <= ptr->continuum[pointer_index + 1].value);
-  }
-#endif
-
-  return MEMCACHED_SUCCESS;
-}
-
-
-memcached_return_t memcached_server_push(memcached_st *ptr, const memcached_server_list_st list)
-{
-  uint32_t count;
-  memcached_server_st *new_host_list;
-
-  if (! list)
-    return MEMCACHED_SUCCESS;
-
-  count= memcached_server_list_count(list);
-  new_host_list= libmemcached_realloc(ptr, memcached_server_list(ptr),
-                                      sizeof(memcached_server_st) * (count + memcached_server_count(ptr)));
-
-  if (! new_host_list)
-    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-  memcached_server_list_set(ptr, new_host_list);
-
-  for (uint32_t x= 0; x < count; x++)
-  {
-    memcached_server_write_instance_st instance;
-
-    if ((ptr->flags.use_udp && list[x].type != MEMCACHED_CONNECTION_UDP)
-            || ((list[x].type == MEMCACHED_CONNECTION_UDP)
-            && ! (ptr->flags.use_udp)) )
-    {
-      return MEMCACHED_INVALID_HOST_PROTOCOL;
-    }
-
-    WATCHPOINT_ASSERT(list[x].hostname[0] != 0);
-
-    instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));
-    WATCHPOINT_ASSERT(instance);
-
-    /* TODO check return type */
-    instance= memcached_server_create_with(ptr, instance, list[x].hostname,
-                                           list[x].port, list[x].weight, list[x].type);
-    if (! instance)
-    {
-      return memcached_set_error(ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, NULL);
-    }
-    ptr->number_of_hosts++;
-  }
-
-  // Provides backwards compatibility with server list.
-  {
-    memcached_server_write_instance_st instance;
-    instance= memcached_server_instance_fetch(ptr, 0);
-    instance->number_of_hosts= memcached_server_count(ptr);
-  }
-
-  return run_distribution(ptr);
-}
-
-memcached_return_t memcached_server_add_unix_socket(memcached_st *ptr,
-                                                    const char *filename)
-{
-  return memcached_server_add_unix_socket_with_weight(ptr, filename, 0);
-}
-
-memcached_return_t memcached_server_add_unix_socket_with_weight(memcached_st *ptr,
-                                                                const char *filename,
-                                                                uint32_t weight)
-{
-  if (! filename)
-    return MEMCACHED_FAILURE;
-
-  return server_add(ptr, filename, 0, weight, MEMCACHED_CONNECTION_UNIX_SOCKET);
-}
-
-memcached_return_t memcached_server_add_udp(memcached_st *ptr,
-                                            const char *hostname,
-                                            in_port_t port)
-{
-  return memcached_server_add_udp_with_weight(ptr, hostname, port, 0);
-}
-
-memcached_return_t memcached_server_add_udp_with_weight(memcached_st *ptr,
-                                                        const char *hostname,
-                                                        in_port_t port,
-                                                        uint32_t weight)
-{
-  if (! port)
-    port= MEMCACHED_DEFAULT_PORT;
-
-  if (! hostname)
-    hostname= "localhost";
-
-  return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_UDP);
-}
-
-memcached_return_t memcached_server_add(memcached_st *ptr,
-                                        const char *hostname,
-                                        in_port_t port)
-{
-  return memcached_server_add_with_weight(ptr, hostname, port, 0);
-}
-
-memcached_return_t memcached_server_add_with_weight(memcached_st *ptr,
-                                                    const char *hostname,
-                                                    in_port_t port,
-                                                    uint32_t weight)
-{
-  if (! port)
-    port= MEMCACHED_DEFAULT_PORT;
-
-  if (! hostname)
-    hostname= "localhost";
-
-  return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_TCP);
-}
-
-static memcached_return_t server_add(memcached_st *ptr, const char *hostname,
-                                     in_port_t port,
-                                     uint32_t weight,
-                                     memcached_connection_t type)
-{
-  memcached_server_st *new_host_list;
-  memcached_server_write_instance_st instance;
-
-  if ( (ptr->flags.use_udp && type != MEMCACHED_CONNECTION_UDP)
-      || ( (type == MEMCACHED_CONNECTION_UDP) && (! ptr->flags.use_udp) ) )
-    return MEMCACHED_INVALID_HOST_PROTOCOL;
-
-  new_host_list= libmemcached_realloc(ptr, memcached_server_list(ptr),
-                                      sizeof(memcached_server_st) * (ptr->number_of_hosts + 1));
-
-  if (new_host_list == NULL)
-    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-  memcached_server_list_set(ptr, new_host_list);
-
-  /* TODO: Check return type */
-  instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));
-  (void)memcached_server_create_with(ptr, instance, hostname, port, weight, type);
-  ptr->number_of_hosts++;
-
-  instance= memcached_server_instance_fetch(ptr, 0);
-  memcached_servers_set_count(instance, memcached_server_count(ptr));
-
-  return run_distribution(ptr);
-}
diff --git a/libmemcached/hosts.cc b/libmemcached/hosts.cc
new file mode 100644 (file)
index 0000000..14b4558
--- /dev/null
@@ -0,0 +1,450 @@
+/* LibMemcached
+ * Copyright (C) 2006-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: 
+ *
+ */
+
+#include "common.h"
+#include <math.h>
+
+/* Protoypes (static) */
+static memcached_return_t server_add(memcached_st *ptr, const char *hostname,
+                                     in_port_t port,
+                                     uint32_t weight,
+                                     memcached_connection_t type);
+
+static memcached_return_t update_continuum(memcached_st *ptr);
+
+static int compare_servers(const void *p1, const void *p2)
+{
+  int return_value;
+  memcached_server_instance_st a= (memcached_server_instance_st)p1;
+  memcached_server_instance_st b= (memcached_server_instance_st)p2;
+
+  return_value= strcmp(a->hostname, b->hostname);
+
+  if (return_value == 0)
+  {
+    return_value= (int) (a->port - b->port);
+  }
+
+  return return_value;
+}
+
+static void sort_hosts(memcached_st *ptr)
+{
+  if (memcached_server_count(ptr))
+  {
+    memcached_server_write_instance_st instance;
+
+    qsort(memcached_server_list(ptr), memcached_server_count(ptr), sizeof(memcached_server_st), compare_servers);
+    instance= memcached_server_instance_fetch(ptr, 0);
+    instance->number_of_hosts= memcached_server_count(ptr);
+  }
+}
+
+
+memcached_return_t run_distribution(memcached_st *ptr)
+{
+  if (ptr->flags.use_sort_hosts)
+    sort_hosts(ptr);
+
+  switch (ptr->distribution)
+  {
+  case MEMCACHED_DISTRIBUTION_CONSISTENT:
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
+    return update_continuum(ptr);
+  case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
+  case MEMCACHED_DISTRIBUTION_MODULA:
+    break;
+  case MEMCACHED_DISTRIBUTION_RANDOM:
+    srandom((uint32_t) time(NULL));
+    break;
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
+  default:
+    WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+static uint32_t ketama_server_hash(const char *key, size_t key_length, uint32_t alignment)
+{
+  unsigned char results[16];
+
+  libhashkit_md5_signature((unsigned char*)key, key_length, results);
+
+  return ((uint32_t) (results[3 + alignment * 4] & 0xFF) << 24)
+    | ((uint32_t) (results[2 + alignment * 4] & 0xFF) << 16)
+    | ((uint32_t) (results[1 + alignment * 4] & 0xFF) << 8)
+    | (results[0 + alignment * 4] & 0xFF);
+}
+
+static int continuum_item_cmp(const void *t1, const void *t2)
+{
+  memcached_continuum_item_st *ct1= (memcached_continuum_item_st *)t1;
+  memcached_continuum_item_st *ct2= (memcached_continuum_item_st *)t2;
+
+  /* Why 153? Hmmm... */
+  WATCHPOINT_ASSERT(ct1->value != 153);
+  if (ct1->value == ct2->value)
+    return 0;
+  else if (ct1->value > ct2->value)
+    return 1;
+  else
+    return -1;
+}
+
+static memcached_return_t update_continuum(memcached_st *ptr)
+{
+  uint32_t continuum_index= 0;
+  memcached_server_st *list;
+  uint32_t pointer_counter= 0;
+  uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
+  uint32_t pointer_per_hash= 1;
+  uint32_t live_servers= 0;
+  struct timeval now;
+
+  if (gettimeofday(&now, NULL) != 0)
+  {
+    memcached_set_errno(ptr, errno, NULL);
+    return MEMCACHED_ERRNO;
+  }
+
+  list= memcached_server_list(ptr);
+
+  /* count live servers (those without a retry delay set) */
+  bool is_auto_ejecting= _is_auto_eject_host(ptr);
+  if (is_auto_ejecting)
+  {
+    live_servers= 0;
+    ptr->ketama.next_distribution_rebuild= 0;
+    for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
+    {
+      if (list[host_index].next_retry <= now.tv_sec)
+        live_servers++;
+      else
+      {
+        if (ptr->ketama.next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->ketama.next_distribution_rebuild)
+          ptr->ketama.next_distribution_rebuild= list[host_index].next_retry;
+      }
+    }
+  }
+  else
+  {
+    live_servers= memcached_server_count(ptr);
+  }
+
+  uint64_t is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
+  uint32_t points_per_server= (uint32_t) (is_ketama_weighted ? MEMCACHED_POINTS_PER_SERVER_KETAMA : MEMCACHED_POINTS_PER_SERVER);
+
+  if (live_servers == 0)
+    return MEMCACHED_SUCCESS;
+
+  if (live_servers > ptr->ketama.continuum_count)
+  {
+    memcached_continuum_item_st *new_ptr;
+
+    new_ptr= static_cast<memcached_continuum_item_st*>(libmemcached_realloc(ptr, ptr->ketama.continuum,
+                                                                           sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server));
+
+    if (new_ptr == 0)
+      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+    ptr->ketama.continuum= new_ptr;
+    ptr->ketama.continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION;
+  }
+
+  uint64_t total_weight= 0;
+  if (is_ketama_weighted)
+  {
+    for (uint32_t host_index = 0; host_index < memcached_server_count(ptr); ++host_index)
+    {
+      if (! is_auto_ejecting || list[host_index].next_retry <= now.tv_sec)
+      {
+        total_weight += list[host_index].weight;
+      }
+    }
+  }
+
+  for (uint32_t host_index= 0; host_index < memcached_server_count(ptr); ++host_index)
+  {
+    if (is_auto_ejecting && list[host_index].next_retry > now.tv_sec)
+      continue;
+
+    if (is_ketama_weighted)
+    {
+        float pct = (float)list[host_index].weight / (float)total_weight;
+        pointer_per_server= (uint32_t) ((floorf((float) (pct * MEMCACHED_POINTS_PER_SERVER_KETAMA / 4 * (float)live_servers + 0.0000000001))) * 4);
+        pointer_per_hash= 4;
+#ifdef DEBUG
+        printf("ketama_weighted:%s|%d|%llu|%u\n",
+               list[host_index].hostname,
+               list[host_index].port,
+               (unsigned long long)list[host_index].weight,
+               pointer_per_server);
+#endif
+    }
+
+
+    if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY)
+    {
+      for (uint32_t pointer_index= 0;
+           pointer_index < pointer_per_server / pointer_per_hash;
+           pointer_index++)
+      {
+        char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
+        int sort_host_length;
+
+        // Spymemcached ketema key format is: hostname/ip:port-index
+        // If hostname is not available then: /ip:port-index
+        sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+                                   "/%s:%u-%u",
+                                   list[host_index].hostname,
+                                   (uint32_t)list[host_index].port,
+                                   pointer_index);
+
+        if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0)
+        {
+          return MEMCACHED_FAILURE;
+        }
+#ifdef DEBUG
+        printf("update_continuum: key is %s\n", sort_host);
+#endif
+
+        WATCHPOINT_ASSERT(sort_host_length);
+
+        if (is_ketama_weighted)
+        {
+          for (uint32_t x= 0; x < pointer_per_hash; x++)
+          {
+            uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
+             ptr->ketama.continuum[continuum_index].index= host_index;
+             ptr->ketama.continuum[continuum_index++].value= value;
+          }
+        }
+        else
+        {
+          uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length);
+          ptr->ketama.continuum[continuum_index].index= host_index;
+          ptr->ketama.continuum[continuum_index++].value= value;
+        }
+      }
+    }
+    else
+    {
+      for (uint32_t pointer_index= 1;
+           pointer_index <= pointer_per_server / pointer_per_hash;
+           pointer_index++)
+      {
+        char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
+        int sort_host_length;
+
+        if (list[host_index].port == MEMCACHED_DEFAULT_PORT)
+        {
+          sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+                                     "%s-%u",
+                                     list[host_index].hostname,
+                                     pointer_index - 1);
+        }
+        else
+        {
+          sort_host_length= snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+                                     "%s:%u-%u",
+                                     list[host_index].hostname,
+                                     (uint32_t)list[host_index].port,
+                                     pointer_index - 1);
+        }
+
+        if (sort_host_length >= MEMCACHED_MAX_HOST_SORT_LENGTH || sort_host_length < 0)
+        {
+          return MEMCACHED_FAILURE;
+        }
+
+        WATCHPOINT_ASSERT(sort_host_length);
+
+        if (is_ketama_weighted)
+        {
+          for (uint32_t x = 0; x < pointer_per_hash; x++)
+          {
+             uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
+             ptr->ketama.continuum[continuum_index].index= host_index;
+             ptr->ketama.continuum[continuum_index++].value= value;
+          }
+        }
+        else
+        {
+          uint32_t value= hashkit_digest(&ptr->distribution_hashkit, sort_host, (size_t)sort_host_length);
+          ptr->ketama.continuum[continuum_index].index= host_index;
+          ptr->ketama.continuum[continuum_index++].value= value;
+        }
+      }
+    }
+
+    pointer_counter+= pointer_per_server;
+  }
+
+  WATCHPOINT_ASSERT(ptr);
+  WATCHPOINT_ASSERT(ptr->continuum);
+  WATCHPOINT_ASSERT(memcached_server_count(ptr) * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE);
+  ptr->ketama.continuum_points_counter= pointer_counter;
+  qsort(ptr->ketama.continuum, ptr->ketama.continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);
+
+#ifdef DEBUG
+  for (uint32_t pointer_index= 0; memcached_server_count(ptr) && pointer_index < ((live_servers * MEMCACHED_POINTS_PER_SERVER) - 1); pointer_index++)
+  {
+    WATCHPOINT_ASSERT(ptr->continuum[pointer_index].value <= ptr->continuum[pointer_index + 1].value);
+  }
+#endif
+
+  return MEMCACHED_SUCCESS;
+}
+
+
+memcached_return_t memcached_server_push(memcached_st *ptr, const memcached_server_list_st list)
+{
+  if (not list)
+    return MEMCACHED_SUCCESS;
+
+  uint32_t count= memcached_server_list_count(list);
+
+  memcached_server_st *new_host_list;
+  new_host_list= static_cast<memcached_server_st*>(libmemcached_realloc(ptr, memcached_server_list(ptr),
+                                                                       sizeof(memcached_server_st) * (count + memcached_server_count(ptr))));
+
+  if (not new_host_list)
+    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+  memcached_server_list_set(ptr, new_host_list);
+
+  for (uint32_t x= 0; x < count; x++)
+  {
+    memcached_server_write_instance_st instance;
+
+    if ((ptr->flags.use_udp && list[x].type != MEMCACHED_CONNECTION_UDP)
+            || ((list[x].type == MEMCACHED_CONNECTION_UDP)
+            && ! (ptr->flags.use_udp)) )
+    {
+      return MEMCACHED_INVALID_HOST_PROTOCOL;
+    }
+
+    WATCHPOINT_ASSERT(list[x].hostname[0] != 0);
+
+    instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));
+    WATCHPOINT_ASSERT(instance);
+
+    /* TODO check return type */
+    instance= memcached_server_create_with(ptr, instance, list[x].hostname,
+                                           list[x].port, list[x].weight, list[x].type);
+    if (! instance)
+    {
+      return memcached_set_error(ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, NULL);
+    }
+    ptr->number_of_hosts++;
+  }
+
+  // Provides backwards compatibility with server list.
+  {
+    memcached_server_write_instance_st instance;
+    instance= memcached_server_instance_fetch(ptr, 0);
+    instance->number_of_hosts= memcached_server_count(ptr);
+  }
+
+  return run_distribution(ptr);
+}
+
+memcached_return_t memcached_server_add_unix_socket(memcached_st *ptr,
+                                                    const char *filename)
+{
+  return memcached_server_add_unix_socket_with_weight(ptr, filename, 0);
+}
+
+memcached_return_t memcached_server_add_unix_socket_with_weight(memcached_st *ptr,
+                                                                const char *filename,
+                                                                uint32_t weight)
+{
+  if (! filename)
+    return MEMCACHED_FAILURE;
+
+  return server_add(ptr, filename, 0, weight, MEMCACHED_CONNECTION_UNIX_SOCKET);
+}
+
+memcached_return_t memcached_server_add_udp(memcached_st *ptr,
+                                            const char *hostname,
+                                            in_port_t port)
+{
+  return memcached_server_add_udp_with_weight(ptr, hostname, port, 0);
+}
+
+memcached_return_t memcached_server_add_udp_with_weight(memcached_st *ptr,
+                                                        const char *hostname,
+                                                        in_port_t port,
+                                                        uint32_t weight)
+{
+  if (! port)
+    port= MEMCACHED_DEFAULT_PORT;
+
+  if (! hostname)
+    hostname= "localhost";
+
+  return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_UDP);
+}
+
+memcached_return_t memcached_server_add(memcached_st *ptr,
+                                        const char *hostname,
+                                        in_port_t port)
+{
+  return memcached_server_add_with_weight(ptr, hostname, port, 0);
+}
+
+memcached_return_t memcached_server_add_with_weight(memcached_st *ptr,
+                                                    const char *hostname,
+                                                    in_port_t port,
+                                                    uint32_t weight)
+{
+  if (! port)
+    port= MEMCACHED_DEFAULT_PORT;
+
+  if (! hostname)
+    hostname= "localhost";
+
+  return server_add(ptr, hostname, port, weight, MEMCACHED_CONNECTION_TCP);
+}
+
+static memcached_return_t server_add(memcached_st *ptr, const char *hostname,
+                                     in_port_t port,
+                                     uint32_t weight,
+                                     memcached_connection_t type)
+{
+  memcached_server_st *new_host_list;
+  memcached_server_write_instance_st instance;
+
+  if ( (ptr->flags.use_udp && type != MEMCACHED_CONNECTION_UDP)
+      || ( (type == MEMCACHED_CONNECTION_UDP) && (! ptr->flags.use_udp) ) )
+    return MEMCACHED_INVALID_HOST_PROTOCOL;
+
+  new_host_list= static_cast<memcached_server_st*>(libmemcached_realloc(ptr, memcached_server_list(ptr),
+                                                                       sizeof(memcached_server_st) * (ptr->number_of_hosts + 1)));
+
+  if (new_host_list == NULL)
+    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+  memcached_server_list_set(ptr, new_host_list);
+
+  /* TODO: Check return type */
+  instance= memcached_server_instance_fetch(ptr, memcached_server_count(ptr));
+  (void)memcached_server_create_with(ptr, instance, hostname, port, weight, type);
+  ptr->number_of_hosts++;
+
+  instance= memcached_server_instance_fetch(ptr, 0);
+  memcached_servers_set_count(instance, memcached_server_count(ptr));
+
+  return run_distribution(ptr);
+}
index f243f12fc844ebb9f340f25d6626d26ab40cf2f6..28c5513a4cbc7742ff856176ec720b27ea7cdc90 100644 (file)
@@ -71,104 +71,73 @@ nobase_include_HEADERS+= \
                         libmemcached/visibility.h \
                         libmemcached/watchpoint.h
 
-lib_LTLIBRARIES+= libmemcached/libmemcachedprotocol.la
-libmemcached_libmemcachedprotocol_la_SOURCES =  \
-                                               libmemcached/protocol/ascii_handler.c \
-                                               libmemcached/protocol/binary_handler.c \
-                                               libmemcached/protocol/cache.c \
-                                               libmemcached/protocol/pedantic.c \
-                                               libmemcached/protocol/protocol_handler.c
-
-libmemcached_libmemcachedprotocol_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION} ${PTHREAD_CFLAGS}
-libmemcached_libmemcachedprotocol_la_LDFLAGS= ${AM_LDFLAGS} ${PTHREAD_LIBS} -version-info ${MEMCACHED_PROTOCAL_LIBRARY_VERSION}
-
-noinst_LTLIBRARIES+= \
-                    libmemcached/libmemcachedcallbacks.la
-
-libmemcached_libmemcachedcallbacks_la_CFLAGS = ${AM_CFLAGS} ${NO_STRICT_ALIASING}
-libmemcached_libmemcachedcallbacks_la_SOURCES = libmemcached/callback.c
-
 # This noinst lib contains things we want to be ABI private but still want to
 # either use in client programs or be able to test in test cases
 # These symbols will not be exposed in the shipped .so
 noinst_LTLIBRARIES+= libmemcached/libmemcachedinternal.la
 libmemcached_libmemcachedinternal_la_SOURCES= \
                                              libmemcached/error.cc \
-                                             libmemcached/string.c
+                                             libmemcached/string.cc
 
 lib_LTLIBRARIES+= libmemcached/libmemcached.la
-libmemcached_libmemcached_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION}
+libmemcached_libmemcached_la_CFLAGS= \
+                                    ${AM_CFLAGS} \
+                                    ${NO_CONVERSION} \
+                                    -DBUILDING_LIBMEMCACHED
+
+libmemcached_libmemcached_la_CXXFLAGS= \
+                                      ${AM_CXXFLAGS} \
+                                      ${NO_CONVERSION} \
+                                      -DBUILDING_LIBMEMCACHED
+
 libmemcached_libmemcached_la_SOURCES+= \
-                                      libmemcached/allocators.c \
-                                      libmemcached/analyze.c \
+                                      ${libhashkit_libhashkit_la_SOURCES} \
+                                      libmemcached/allocators.cc \
+                                      libmemcached/analyze.cc \
                                       libmemcached/array.c \
-                                      libmemcached/auto.c \
-                                      libmemcached/behavior.c \
-                                      libmemcached/connect.c \
-                                      libmemcached/delete.c \
-                                      libmemcached/do.c \
-                                      libmemcached/dump.c \
+                                      libmemcached/auto.cc \
+                                      libmemcached/behavior.cc \
+                                      libmemcached/byteorder.cc \
+                                      libmemcached/callback.cc \
+                                      libmemcached/connect.cc \
+                                      libmemcached/delete.cc \
+                                      libmemcached/do.cc \
+                                      libmemcached/dump.cc \
+                                      libmemcached/error.cc \
                                       libmemcached/fetch.c \
-                                      libmemcached/flush.c \
-                                      libmemcached/flush_buffers.c \
-                                      libmemcached/get.c \
-                                      libmemcached/hash.c \
-                                      libmemcached/hosts.c \
+                                      libmemcached/flush.cc \
+                                      libmemcached/flush_buffers.cc \
+                                      libmemcached/get.cc \
+                                      libmemcached/hash.cc \
+                                      libmemcached/hosts.cc \
                                       libmemcached/initialize_query.cc \
-                                      libmemcached/io.c \
-                                      libmemcached/key.c \
-                                      libmemcached/memcached.c \
+                                      libmemcached/io.cc \
+                                      libmemcached/key.cc \
+                                      libmemcached/memcached.cc \
                                       libmemcached/options.cc \
-                                      libmemcached/parse.c \
+                                      libmemcached/parse.cc \
                                       libmemcached/prefix_key.cc \
-                                      libmemcached/purge.c \
-                                      libmemcached/quit.c \
-                                      libmemcached/response.c \
-                                      libmemcached/result.c \
-                                      libmemcached/server.c \
-                                      libmemcached/server_list.c \
-                                      libmemcached/stats.c \
-                                      libmemcached/storage.c \
-                                      libmemcached/strerror.c \
-                                      libmemcached/verbosity.c \
-                                      libmemcached/version.c \
+                                      libmemcached/purge.cc \
+                                      libmemcached/quit.cc \
+                                      libmemcached/response.cc \
+                                      libmemcached/result.cc \
+                                      libmemcached/server.cc \
+                                      libmemcached/server_list.cc \
+                                      libmemcached/stats.cc \
+                                      libmemcached/storage.cc \
+                                      libmemcached/strerror.cc \
+                                      libmemcached/string.cc \
+                                      libmemcached/verbosity.cc \
+                                      libmemcached/version.cc \
                                       libmemcached/virtual_bucket.c
 
 libmemcached/options.cc: libmemcached/options/parser.h
 
 
-libmemcached_libmemcached_la_DEPENDENCIES= libmemcached/libmemcachedcallbacks.la libmemcached/libmemcachedinternal.la libhashkit/libhashkitinc.la
-libmemcached_libmemcached_la_LIBADD= $(LIBM) libmemcached/libmemcachedcallbacks.la libmemcached/libmemcachedinternal.la libhashkit/libhashkitinc.la
+libmemcached_libmemcached_la_DEPENDENCIES=
+libmemcached_libmemcached_la_LIBADD= $(LIBM)
 libmemcached_libmemcached_la_LDFLAGS= ${AM_LDFLAGS} -version-info ${MEMCACHED_LIBRARY_VERSION}
 
-if BUILD_LIBMEMCACHEDUTIL
-nobase_include_HEADERS+= \
-                        libmemcached/memcached_util.h \
-                        libmemcached/util.h \
-                        libmemcached/util/ping.h \
-                        libmemcached/util/pool.h \
-                        libmemcached/util/version.h
-lib_LTLIBRARIES+= libmemcached/libmemcachedutil.la
-endif
-
-libmemcached_libmemcachedutil_la_SOURCES= \
-                                         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}
-libmemcached_libmemcachedutil_la_DEPENDENCIES= libmemcached/libmemcached.la
-
-if BUILD_BYTEORDER
-noinst_LTLIBRARIES += libmemcached/libbyteorder.la
-libmemcached_libbyteorder_la_SOURCES= libmemcached/byteorder.c
-libmemcached_libmemcached_la_LIBADD += libmemcached/libbyteorder.la
-libmemcached_libmemcached_la_DEPENDENCIES+= libmemcached/libbyteorder.la
-libmemcached_libmemcachedprotocol_la_LIBADD=libmemcached/libbyteorder.la
-libmemcached_libmemcachedprotocol_la_DEPENDENCIES=libmemcached/libbyteorder.la
-endif
-
 if HAVE_SASL
 libmemcached_libmemcached_la_LDFLAGS+= $(LTLIBSASL) $(LTLIBSASL2)
 libmemcached_libmemcached_la_SOURCES += libmemcached/sasl.c
index abc8dfdcc906f0c8994f5ab997525e2e772c0d52..31a15fbccc4f9d0d4ab994edd3217dbeab880970 100644 (file)
  */
 
 #include <libmemcached/common.h>
-#include <libmemcached/initialize_query.h>
 
 memcached_return_t initialize_query(memcached_st *self)
 {
-  if (! self)
+  if (not self)
     return MEMCACHED_INVALID_ARGUMENTS;
 
+  self->query_id++;
+
   if (self->state.is_time_for_rebuild)
   {
     memcached_reset(self);
@@ -52,15 +53,12 @@ memcached_return_t initialize_query(memcached_st *self)
     return memcached_set_error(self, MEMCACHED_NO_SERVERS, NULL);
   }
 
-
-  self->query_id++;
-
   return MEMCACHED_SUCCESS;
 }
 
 memcached_return_t initialize_const_query(const memcached_st *self)
 {
-  if (! self)
+  if (not self)
     return MEMCACHED_INVALID_ARGUMENTS;
 
   if (memcached_server_count(self) == 0)
index 743bf870afdf48acbe407ecd6f8c6d30aa49eb5d..67ae67d59f7e7d2ce0b7e81e4e0cf7603685ef5b 100644 (file)
@@ -1,18 +1,41 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 Brian Aker All rights reserved.
  *
- * Summary: Internal functions used by the library. Not for public use!
+ *  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.
  *
  */
 
-#ifndef __LIBMEMCACHED_INTERNAL_H__
-#define __LIBMEMCACHED_INTERNAL_H__
-
-#if defined(BUILDING_LIBMEMCACHED)
+#pragma once
 
 #ifdef __cplusplus
 extern "C" {
@@ -21,6 +44,3 @@ extern "C" {
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* BUILDING_LIBMEMCACHED */
-#endif /* __LIBMEMCACHED_INTERNAL_H__ */
diff --git a/libmemcached/io.c b/libmemcached/io.c
deleted file mode 100644 (file)
index 5acbbd5..0000000
+++ /dev/null
@@ -1,806 +0,0 @@
-/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- * 
- *  LibMemcached
- *
- *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *  Copyright (C) 2006-2009 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"
-
-typedef enum {
-  MEM_READ,
-  MEM_WRITE
-} memc_read_or_write;
-
-static ssize_t io_flush(memcached_server_write_instance_st ptr,
-                        const bool with_flush,
-                        memcached_return_t *error);
-static void increment_udp_message_id(memcached_server_write_instance_st ptr);
-
-static memcached_return_t io_wait(memcached_server_write_instance_st ptr,
-                                  memc_read_or_write read_or_write)
-{
-  struct pollfd fds= {
-    .fd= ptr->fd,
-    .events = POLLIN
-  };
-  int error;
-
-  if (read_or_write == MEM_WRITE) /* write */
-  {
-    fds.events= POLLOUT;
-    WATCHPOINT_SET(ptr->io_wait_count.write++);
-  }
-  else
-  {
-    WATCHPOINT_SET(ptr->io_wait_count.read++);
-  }
-
-  /*
-   ** We are going to block on write, but at least on Solaris we might block
-   ** on write if we haven't read anything from our input buffer..
-   ** Try to purge the input buffer if we don't do any flow control in the
-   ** application layer (just sending a lot of data etc)
-   ** The test is moved down in the purge function to avoid duplication of
-   ** the test.
- */
-  if (read_or_write == MEM_WRITE)
-  {
-    memcached_return_t rc= memcached_purge(ptr);
-    if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
-      return MEMCACHED_FAILURE;
-  }
-
-  size_t loop_max= 5;
-  while (--loop_max) // While loop is for ERESTART or EINTR
-  {
-    error= poll(&fds, 1, ptr->root->poll_timeout);
-
-    switch (error)
-    {
-    case 1: // Success!
-      WATCHPOINT_IF_LABELED_NUMBER(read_or_write && loop_max < 4, "read() times we had to loop, decremented down from 5", loop_max);
-      WATCHPOINT_IF_LABELED_NUMBER(!read_or_write && loop_max < 4, "write() times we had to loop, decremented down from 5", loop_max);
-
-      return MEMCACHED_SUCCESS;
-    case 0: // Timeout occured, we let the while() loop do its thing.
-      return MEMCACHED_TIMEOUT;
-    default:
-      WATCHPOINT_ERRNO(get_socket_errno());
-      switch (get_socket_errno())
-      {
-#ifdef TARGET_OS_LINUX
-      case ERESTART:
-#endif
-      case EINTR:
-        break;
-      default:
-        if (fds.revents & POLLERR)
-        {
-          int err;
-          socklen_t len= sizeof (err);
-          (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
-          ptr->cached_errno= (err == 0) ? get_socket_errno() : err;
-        }
-        else
-        {
-          ptr->cached_errno= get_socket_errno();
-        }
-        memcached_quit_server(ptr, true);
-
-        return MEMCACHED_FAILURE;
-      }
-    }
-  }
-
-  /* Imposssible for anything other then -1 */
-  WATCHPOINT_ASSERT(error == -1);
-  ptr->cached_errno= get_socket_errno();
-  memcached_quit_server(ptr, true);
-
-  return MEMCACHED_FAILURE;
-}
-
-memcached_return_t memcached_io_wait_for_write(memcached_server_write_instance_st ptr)
-{
-  return io_wait(ptr, MEM_WRITE);
-}
-
-/**
- * Try to fill the input buffer for a server with as much
- * data as possible.
- *
- * @param ptr the server to pack
- */
-static bool repack_input_buffer(memcached_server_write_instance_st ptr)
-{
-  if (ptr->read_ptr != ptr->read_buffer)
-  {
-    /* Move all of the data to the beginning of the buffer so
-     ** that we can fit more data into the buffer...
-   */
-    memmove(ptr->read_buffer, ptr->read_ptr, ptr->read_buffer_length);
-    ptr->read_ptr= ptr->read_buffer;
-    ptr->read_data_length= ptr->read_buffer_length;
-  }
-
-  /* There is room in the buffer, try to fill it! */
-  if (ptr->read_buffer_length != MEMCACHED_MAX_BUFFER)
-  {
-    /* Just try a single read to grab what's available */
-    ssize_t nr= recv(ptr->fd,
-                     ptr->read_ptr + ptr->read_data_length,
-                     MEMCACHED_MAX_BUFFER - ptr->read_data_length,
-                     0);
-
-    if (nr > 0)
-    {
-      ptr->read_data_length+= (size_t)nr;
-      ptr->read_buffer_length+= (size_t)nr;
-      return true;
-    }
-  }
-  return false;
-}
-
-/**
- * If the we have callbacks connected to this server structure
- * we may start process the input queue and fire the callbacks
- * for the incomming messages. This function is _only_ called
- * when the input buffer is full, so that we _know_ that we have
- * at least _one_ message to process.
- *
- * @param ptr the server to star processing iput messages for
- * @return true if we processed anything, false otherwise
- */
-static bool process_input_buffer(memcached_server_write_instance_st ptr)
-{
-  /*
-   ** We might be able to process some of the response messages if we
-   ** have a callback set up
- */
-  if (ptr->root->callbacks != NULL && ptr->root->flags.use_udp == false)
-  {
-    /*
-     * We might have responses... try to read them out and fire
-     * callbacks
-   */
-    memcached_callback_st cb= *ptr->root->callbacks;
-
-    memcached_set_processing_input((memcached_st *)ptr->root, true);
-
-    char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-    memcached_return_t error;
-    memcached_st *root= (memcached_st *)ptr->root;
-    error= memcached_response(ptr, buffer, sizeof(buffer),
-                              &root->result);
-
-    memcached_set_processing_input(root, false);
-
-    if (error == MEMCACHED_SUCCESS)
-    {
-      for (unsigned int x= 0; x < cb.number_of_callback; x++)
-      {
-        error= (*cb.callback[x])(ptr->root, &root->result, cb.context);
-        if (error != MEMCACHED_SUCCESS)
-          break;
-      }
-
-      /* @todo what should I do with the error message??? */
-    }
-    /* @todo what should I do with other error messages?? */
-    return true;
-  }
-
-  return false;
-}
-
-#if 0 // Dead code, this should be removed.
-void memcached_io_preread(memcached_st *ptr)
-{
-  unsigned int x;
-
-  return;
-
-  for (x= 0; x < memcached_server_count(ptr); x++)
-  {
-    if (memcached_server_response_count(ptr, x) &&
-        ptr->hosts[x].read_data_length < MEMCACHED_MAX_BUFFER )
-    {
-      size_t data_read;
-
-      data_read= recv(ptr->hosts[x].fd,
-                      ptr->hosts[x].read_ptr + ptr->hosts[x].read_data_length,
-                      MEMCACHED_MAX_BUFFER - ptr->hosts[x].read_data_length, 0);
-      if (data_read == SOCKET_ERROR)
-        continue;
-
-      ptr->hosts[x].read_buffer_length+= data_read;
-      ptr->hosts[x].read_data_length+= data_read;
-    }
-  }
-}
-#endif
-
-memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr,
-                                     void *buffer, size_t length, ssize_t *nread)
-{
-  char *buffer_ptr;
-
-  buffer_ptr= buffer;
-
-  while (length)
-  {
-    if (!ptr->read_buffer_length)
-    {
-      ssize_t data_read;
-
-      while (1)
-      {
-        data_read= recv(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER, 0);
-        if (data_read > 0)
-        {
-          break;
-        }
-        else if (data_read == SOCKET_ERROR)
-        {
-          ptr->cached_errno= get_socket_errno();
-          memcached_return_t rc= MEMCACHED_ERRNO;
-          switch (get_socket_errno())
-          {
-          case EWOULDBLOCK:
-#ifdef USE_EAGAIN
-          case EAGAIN:
-#endif
-          case EINTR:
-#ifdef TARGET_OS_LINUX
-          case ERESTART:
-#endif
-            if ((rc= io_wait(ptr, MEM_READ)) == MEMCACHED_SUCCESS)
-              continue;
-            /* fall through */
-
-          default:
-            {
-              memcached_quit_server(ptr, true);
-              *nread= -1;
-              return rc;
-            }
-          }
-        }
-        else
-        {
-          /*
-            EOF. Any data received so far is incomplete
-            so discard it. This always reads by byte in case of TCP
-            and protocol enforcement happens at memcached_response()
-            looking for '\n'. We do not care for UDB which requests 8 bytes
-            at once. Generally, this means that connection went away. Since
-            for blocking I/O we do not return 0 and for non-blocking case
-            it will return EGAIN if data is not immediatly available.
-          */
-          WATCHPOINT_STRING("We had a zero length recv()");
-          memcached_quit_server(ptr, true);
-          *nread= -1;
-          return MEMCACHED_UNKNOWN_READ_FAILURE;
-        }
-      }
-
-      ptr->io_bytes_sent = 0;
-      ptr->read_data_length= (size_t) data_read;
-      ptr->read_buffer_length= (size_t) data_read;
-      ptr->read_ptr= ptr->read_buffer;
-    }
-
-    if (length > 1)
-    {
-      size_t difference;
-
-      difference= (length > ptr->read_buffer_length) ? ptr->read_buffer_length : length;
-
-      memcpy(buffer_ptr, ptr->read_ptr, difference);
-      length -= difference;
-      ptr->read_ptr+= difference;
-      ptr->read_buffer_length-= difference;
-      buffer_ptr+= difference;
-    }
-    else
-    {
-      *buffer_ptr= *ptr->read_ptr;
-      ptr->read_ptr++;
-      ptr->read_buffer_length--;
-      buffer_ptr++;
-      break;
-    }
-  }
-
-  ptr->server_failure_counter= 0;
-  *nread = (ssize_t)(buffer_ptr - (char*)buffer);
-  return MEMCACHED_SUCCESS;
-}
-
-static ssize_t _io_write(memcached_server_write_instance_st ptr,
-                         const void *buffer, size_t length, bool with_flush)
-{
-  size_t original_length;
-  const char* buffer_ptr;
-
-  WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
-
-  original_length= length;
-  buffer_ptr= buffer;
-
-  while (length)
-  {
-    char *write_ptr;
-    size_t should_write;
-    size_t buffer_end;
-
-    if (ptr->type == MEMCACHED_CONNECTION_UDP)
-    {
-      //UDP does not support partial writes
-      buffer_end= MAX_UDP_DATAGRAM_LENGTH;
-      should_write= length;
-      if (ptr->write_buffer_offset + should_write > buffer_end)
-      {
-        return -1;
-      }
-    }
-    else
-    {
-      buffer_end= MEMCACHED_MAX_BUFFER;
-      should_write= buffer_end - ptr->write_buffer_offset;
-      should_write= (should_write < length) ? should_write : length;
-    }
-
-    write_ptr= ptr->write_buffer + ptr->write_buffer_offset;
-    memcpy(write_ptr, buffer_ptr, should_write);
-    ptr->write_buffer_offset+= should_write;
-    buffer_ptr+= should_write;
-    length-= should_write;
-
-    if (ptr->write_buffer_offset == buffer_end && ptr->type != MEMCACHED_CONNECTION_UDP)
-    {
-      memcached_return_t rc;
-      ssize_t sent_length;
-
-      WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
-      sent_length= io_flush(ptr, with_flush, &rc);
-      if (sent_length == -1)
-      {
-        return -1;
-      }
-
-      /* If io_flush calls memcached_purge, sent_length may be 0 */
-      unlikely (sent_length != 0)
-      {
-        WATCHPOINT_ASSERT(sent_length == (ssize_t)buffer_end);
-      }
-    }
-  }
-
-  if (with_flush)
-  {
-    memcached_return_t rc;
-    WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
-    if (io_flush(ptr, with_flush, &rc) == -1)
-    {
-      return -1;
-    }
-  }
-
-  return (ssize_t) original_length;
-}
-
-ssize_t memcached_io_write(memcached_server_write_instance_st ptr,
-                           const void *buffer, size_t length, bool with_flush)
-{
-  return _io_write(ptr, buffer, length, with_flush);
-}
-
-ssize_t memcached_io_writev(memcached_server_write_instance_st ptr,
-                            const struct libmemcached_io_vector_st *vector,
-                            size_t number_of, bool with_flush)
-{
-  ssize_t total= 0;
-
-  for (size_t x= 0; x < number_of; x++, vector++)
-  {
-    ssize_t returnable;
-
-    if ((returnable= _io_write(ptr, vector->buffer, vector->length, false)) == -1)
-    {
-      return -1;
-    }
-    total+= returnable;
-  }
-
-  if (with_flush)
-  {
-    if (memcached_io_write(ptr, NULL, 0, true) == -1)
-    {
-      return -1;
-    }
-  }
-
-  return total;
-}
-
-
-memcached_return_t memcached_io_close(memcached_server_write_instance_st ptr)
-{
-  if (ptr->fd == INVALID_SOCKET)
-  {
-    return MEMCACHED_SUCCESS;
-  }
-
-  /* in case of death shutdown to avoid blocking at close() */
-  if (shutdown(ptr->fd, SHUT_RDWR) == SOCKET_ERROR && get_socket_errno() != ENOTCONN)
-  {
-    WATCHPOINT_NUMBER(ptr->fd);
-    WATCHPOINT_ERRNO(get_socket_errno());
-    WATCHPOINT_ASSERT(get_socket_errno());
-  }
-
-  if (closesocket(ptr->fd) == SOCKET_ERROR)
-  {
-    WATCHPOINT_ERRNO(get_socket_errno());
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-memcached_server_write_instance_st memcached_io_get_readable_server(memcached_st *memc)
-{
-#define MAX_SERVERS_TO_POLL 100
-  struct pollfd fds[MAX_SERVERS_TO_POLL];
-  unsigned int host_index= 0;
-
-  for (uint32_t x= 0;
-       x< memcached_server_count(memc) && host_index < MAX_SERVERS_TO_POLL;
-       ++x)
-  {
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(memc, x);
-
-    if (instance->read_buffer_length > 0) /* I have data in the buffer */
-      return instance;
-
-    if (memcached_server_response_count(instance) > 0)
-    {
-      fds[host_index].events = POLLIN;
-      fds[host_index].revents = 0;
-      fds[host_index].fd = instance->fd;
-      ++host_index;
-    }
-  }
-
-  if (host_index < 2)
-  {
-    /* We have 0 or 1 server with pending events.. */
-    for (uint32_t x= 0; x< memcached_server_count(memc); ++x)
-    {
-      memcached_server_write_instance_st instance=
-        memcached_server_instance_fetch(memc, x);
-
-      if (memcached_server_response_count(instance) > 0)
-      {
-        return instance;
-      }
-    }
-
-    return NULL;
-  }
-
-  int err= poll(fds, host_index, memc->poll_timeout);
-  switch (err) {
-  case -1:
-    memcached_set_errno(memc, get_socket_errno(), NULL);
-    /* FALLTHROUGH */
-  case 0:
-    break;
-  default:
-    for (size_t x= 0; x < host_index; ++x)
-    {
-      if (fds[x].revents & POLLIN)
-      {
-        for (uint32_t y= 0; y < memcached_server_count(memc); ++y)
-        {
-          memcached_server_write_instance_st instance=
-            memcached_server_instance_fetch(memc, y);
-
-          if (instance->fd == fds[x].fd)
-            return instance;
-        }
-      }
-    }
-  }
-
-  return NULL;
-}
-
-static ssize_t io_flush(memcached_server_write_instance_st ptr,
-                        const bool with_flush,
-                        memcached_return_t *error)
-{
-  /*
-   ** We might want to purge the input buffer if we haven't consumed
-   ** any output yet... The test for the limits is the purge is inline
-   ** in the purge function to avoid duplicating the logic..
- */
-  {
-    memcached_return_t rc;
-    WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
-    rc= memcached_purge(ptr);
-
-    if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
-    {
-      return -1;
-    }
-  }
-  ssize_t sent_length;
-  size_t return_length;
-  char *local_write_ptr= ptr->write_buffer;
-  size_t write_length= ptr->write_buffer_offset;
-
-  *error= MEMCACHED_SUCCESS;
-
-  WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
-
-  // UDP Sanity check, make sure that we are not sending somthing too big
-  if (ptr->type == MEMCACHED_CONNECTION_UDP && write_length > MAX_UDP_DATAGRAM_LENGTH)
-  {
-    return -1;
-  }
-
-  if (ptr->write_buffer_offset == 0 || (ptr->type == MEMCACHED_CONNECTION_UDP
-                                        && ptr->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH))
-    return 0;
-
-  /* Looking for memory overflows */
-#if defined(DEBUG)
-  if (write_length == MEMCACHED_MAX_BUFFER)
-    WATCHPOINT_ASSERT(ptr->write_buffer == local_write_ptr);
-  WATCHPOINT_ASSERT((ptr->write_buffer + MEMCACHED_MAX_BUFFER) >= (local_write_ptr + write_length));
-#endif
-
-  return_length= 0;
-  while (write_length)
-  {
-    WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
-    WATCHPOINT_ASSERT(write_length > 0);
-    sent_length= 0;
-    if (ptr->type == MEMCACHED_CONNECTION_UDP)
-      increment_udp_message_id(ptr);
-
-    WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
-    if (with_flush)
-    {
-      sent_length= send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT);
-    }
-    else
-    {
-      sent_length= send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT|MSG_MORE);
-    }
-
-    if (sent_length == SOCKET_ERROR)
-    {
-      ptr->cached_errno= get_socket_errno();
-#if 0 // @todo I should look at why we hit this bit of code hard frequently
-      WATCHPOINT_ERRNO(get_socket_errno());
-      WATCHPOINT_NUMBER(get_socket_errno());
-#endif
-      switch (get_socket_errno())
-      {
-      case ENOBUFS:
-        continue;
-      case EWOULDBLOCK:
-#ifdef USE_EAGAIN
-      case EAGAIN:
-#endif
-        {
-          /*
-           * We may be blocked on write because the input buffer
-           * is full. Let's check if we have room in our input
-           * buffer for more data and retry the write before
-           * waiting..
-         */
-          if (repack_input_buffer(ptr) ||
-              process_input_buffer(ptr))
-            continue;
-
-          memcached_return_t rc;
-          rc= io_wait(ptr, MEM_WRITE);
-
-          if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_TIMEOUT)
-            continue;
-
-          memcached_quit_server(ptr, true);
-          return -1;
-        }
-      case ENOTCONN:
-      case EPIPE:
-      default:
-        memcached_quit_server(ptr, true);
-        *error= MEMCACHED_ERRNO;
-        WATCHPOINT_ASSERT(ptr->fd == -1);
-        return -1;
-      }
-    }
-
-    if (ptr->type == MEMCACHED_CONNECTION_UDP &&
-        (size_t)sent_length != write_length)
-    {
-      memcached_quit_server(ptr, true);
-      return -1;
-    }
-
-    ptr->io_bytes_sent += (uint32_t) sent_length;
-
-    local_write_ptr+= sent_length;
-    write_length-= (uint32_t) sent_length;
-    return_length+= (uint32_t) sent_length;
-  }
-
-  WATCHPOINT_ASSERT(write_length == 0);
-  // Need to study this assert() WATCHPOINT_ASSERT(return_length ==
-  // ptr->write_buffer_offset);
-
-  // if we are a udp server, the begining of the buffer is reserverd for
-  // the upd frame header
-  if (ptr->type == MEMCACHED_CONNECTION_UDP)
-    ptr->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
-  else
-    ptr->write_buffer_offset= 0;
-
-  return (ssize_t) return_length;
-}
-
-/*
-  Eventually we will just kill off the server with the problem.
-*/
-void memcached_io_reset(memcached_server_write_instance_st ptr)
-{
-  memcached_quit_server(ptr, true);
-}
-
-/**
- * Read a given number of bytes from the server and place it into a specific
- * buffer. Reset the IO channel on this server if an error occurs.
- */
-memcached_return_t memcached_safe_read(memcached_server_write_instance_st ptr,
-                                       void *dta,
-                                       size_t size)
-{
-  size_t offset= 0;
-  char *data= dta;
-
-  while (offset < size)
-  {
-    ssize_t nread;
-    memcached_return_t rc= memcached_io_read(ptr, data + offset, size - offset,
-                                             &nread);
-    if (rc != MEMCACHED_SUCCESS)
-      return rc;
-
-    offset+= (size_t) nread;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr,
-                                         char *buffer_ptr,
-                                         size_t size)
-{
-  bool line_complete= false;
-  size_t total_nr= 0;
-
-  while (!line_complete)
-  {
-    if (ptr->read_buffer_length == 0)
-    {
-      /*
-       * We don't have any data in the buffer, so let's fill the read
-       * buffer. Call the standard read function to avoid duplicating
-       * the logic.
-     */
-      ssize_t nread;
-      memcached_return_t rc= memcached_io_read(ptr, buffer_ptr, 1, &nread);
-      if (rc != MEMCACHED_SUCCESS)
-        return rc;
-
-      if (*buffer_ptr == '\n')
-        line_complete= true;
-
-      ++buffer_ptr;
-      ++total_nr;
-    }
-
-    /* Now let's look in the buffer and copy as we go! */
-    while (ptr->read_buffer_length && total_nr < size && !line_complete)
-    {
-      *buffer_ptr = *ptr->read_ptr;
-      if (*buffer_ptr == '\n')
-        line_complete = true;
-      --ptr->read_buffer_length;
-      ++ptr->read_ptr;
-      ++total_nr;
-      ++buffer_ptr;
-    }
-
-    if (total_nr == size)
-      return MEMCACHED_PROTOCOL_ERROR;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-/*
- * The udp request id consists of two seperate sections
- *   1) The thread id
- *   2) The message number
- * The thread id should only be set when the memcached_st struct is created
- * and should not be changed.
- *
- * The message num is incremented for each new message we send, this function
- * extracts the message number from message_id, increments it and then
- * writes the new value back into the header
- */
-static void increment_udp_message_id(memcached_server_write_instance_st ptr)
-{
-  struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer;
-  uint16_t cur_req= get_udp_datagram_request_id(header);
-  int msg_num= get_msg_num_from_request_id(cur_req);
-  int thread_id= get_thread_id_from_request_id(cur_req);
-
-  if (((++msg_num) & UDP_REQUEST_ID_THREAD_MASK) != 0)
-    msg_num= 0;
-
-  header->request_id= htons((uint16_t) (thread_id | msg_num));
-}
-
-memcached_return_t memcached_io_init_udp_header(memcached_server_write_instance_st ptr, uint16_t thread_id)
-{
-  if (thread_id > UDP_REQUEST_ID_MAX_THREAD_ID)
-    return MEMCACHED_FAILURE;
-
-  struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer;
-  header->request_id= htons((uint16_t) (generate_udp_request_thread_id(thread_id)));
-  header->num_datagrams= htons(1);
-  header->sequence_number= htons(0);
-
-  return MEMCACHED_SUCCESS;
-}
diff --git a/libmemcached/io.cc b/libmemcached/io.cc
new file mode 100644 (file)
index 0000000..74aa4a2
--- /dev/null
@@ -0,0 +1,806 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  LibMemcached
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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"
+
+typedef enum {
+  MEM_READ,
+  MEM_WRITE
+} memc_read_or_write;
+
+static ssize_t io_flush(memcached_server_write_instance_st ptr,
+                        const bool with_flush,
+                        memcached_return_t *error);
+static void increment_udp_message_id(memcached_server_write_instance_st ptr);
+
+static memcached_return_t io_wait(memcached_server_write_instance_st ptr,
+                                  memc_read_or_write read_or_write)
+{
+  struct pollfd fds;
+  fds.fd= ptr->fd;
+  fds.events= POLLIN;
+
+  int error;
+
+  if (read_or_write == MEM_WRITE) /* write */
+  {
+    fds.events= POLLOUT;
+    WATCHPOINT_SET(ptr->io_wait_count.write++);
+  }
+  else
+  {
+    WATCHPOINT_SET(ptr->io_wait_count.read++);
+  }
+
+  /*
+   ** We are going to block on write, but at least on Solaris we might block
+   ** on write if we haven't read anything from our input buffer..
+   ** Try to purge the input buffer if we don't do any flow control in the
+   ** application layer (just sending a lot of data etc)
+   ** The test is moved down in the purge function to avoid duplication of
+   ** the test.
+ */
+  if (read_or_write == MEM_WRITE)
+  {
+    memcached_return_t rc= memcached_purge(ptr);
+    if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
+      return MEMCACHED_FAILURE;
+  }
+
+  size_t loop_max= 5;
+  while (--loop_max) // While loop is for ERESTART or EINTR
+  {
+    error= poll(&fds, 1, ptr->root->poll_timeout);
+
+    switch (error)
+    {
+    case 1: // Success!
+      WATCHPOINT_IF_LABELED_NUMBER(read_or_write && loop_max < 4, "read() times we had to loop, decremented down from 5", loop_max);
+      WATCHPOINT_IF_LABELED_NUMBER(!read_or_write && loop_max < 4, "write() times we had to loop, decremented down from 5", loop_max);
+
+      return MEMCACHED_SUCCESS;
+    case 0: // Timeout occured, we let the while() loop do its thing.
+      return MEMCACHED_TIMEOUT;
+    default:
+      WATCHPOINT_ERRNO(get_socket_errno());
+      switch (get_socket_errno())
+      {
+#ifdef TARGET_OS_LINUX
+      case ERESTART:
+#endif
+      case EINTR:
+        break;
+      default:
+        if (fds.revents & POLLERR)
+        {
+          int err;
+          socklen_t len= sizeof (err);
+          (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
+          ptr->cached_errno= (err == 0) ? get_socket_errno() : err;
+        }
+        else
+        {
+          ptr->cached_errno= get_socket_errno();
+        }
+        memcached_quit_server(ptr, true);
+
+        return MEMCACHED_FAILURE;
+      }
+    }
+  }
+
+  /* Imposssible for anything other then -1 */
+  WATCHPOINT_ASSERT(error == -1);
+  ptr->cached_errno= get_socket_errno();
+  memcached_quit_server(ptr, true);
+
+  return MEMCACHED_FAILURE;
+}
+
+memcached_return_t memcached_io_wait_for_write(memcached_server_write_instance_st ptr)
+{
+  return io_wait(ptr, MEM_WRITE);
+}
+
+/**
+ * Try to fill the input buffer for a server with as much
+ * data as possible.
+ *
+ * @param ptr the server to pack
+ */
+static bool repack_input_buffer(memcached_server_write_instance_st ptr)
+{
+  if (ptr->read_ptr != ptr->read_buffer)
+  {
+    /* Move all of the data to the beginning of the buffer so
+     ** that we can fit more data into the buffer...
+   */
+    memmove(ptr->read_buffer, ptr->read_ptr, ptr->read_buffer_length);
+    ptr->read_ptr= ptr->read_buffer;
+    ptr->read_data_length= ptr->read_buffer_length;
+  }
+
+  /* There is room in the buffer, try to fill it! */
+  if (ptr->read_buffer_length != MEMCACHED_MAX_BUFFER)
+  {
+    /* Just try a single read to grab what's available */
+    ssize_t nr= recv(ptr->fd,
+                     ptr->read_ptr + ptr->read_data_length,
+                     MEMCACHED_MAX_BUFFER - ptr->read_data_length,
+                     0);
+
+    if (nr > 0)
+    {
+      ptr->read_data_length+= (size_t)nr;
+      ptr->read_buffer_length+= (size_t)nr;
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ * If the we have callbacks connected to this server structure
+ * we may start process the input queue and fire the callbacks
+ * for the incomming messages. This function is _only_ called
+ * when the input buffer is full, so that we _know_ that we have
+ * at least _one_ message to process.
+ *
+ * @param ptr the server to star processing iput messages for
+ * @return true if we processed anything, false otherwise
+ */
+static bool process_input_buffer(memcached_server_write_instance_st ptr)
+{
+  /*
+   ** We might be able to process some of the response messages if we
+   ** have a callback set up
+ */
+  if (ptr->root->callbacks != NULL && ptr->root->flags.use_udp == false)
+  {
+    /*
+     * We might have responses... try to read them out and fire
+     * callbacks
+   */
+    memcached_callback_st cb= *ptr->root->callbacks;
+
+    memcached_set_processing_input((memcached_st *)ptr->root, true);
+
+    char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+    memcached_return_t error;
+    memcached_st *root= (memcached_st *)ptr->root;
+    error= memcached_response(ptr, buffer, sizeof(buffer),
+                              &root->result);
+
+    memcached_set_processing_input(root, false);
+
+    if (error == MEMCACHED_SUCCESS)
+    {
+      for (unsigned int x= 0; x < cb.number_of_callback; x++)
+      {
+        error= (*cb.callback[x])(ptr->root, &root->result, cb.context);
+        if (error != MEMCACHED_SUCCESS)
+          break;
+      }
+
+      /* @todo what should I do with the error message??? */
+    }
+    /* @todo what should I do with other error messages?? */
+    return true;
+  }
+
+  return false;
+}
+
+#if 0 // Dead code, this should be removed.
+void memcached_io_preread(memcached_st *ptr)
+{
+  unsigned int x;
+
+  return;
+
+  for (x= 0; x < memcached_server_count(ptr); x++)
+  {
+    if (memcached_server_response_count(ptr, x) &&
+        ptr->hosts[x].read_data_length < MEMCACHED_MAX_BUFFER )
+    {
+      size_t data_read;
+
+      data_read= recv(ptr->hosts[x].fd,
+                      ptr->hosts[x].read_ptr + ptr->hosts[x].read_data_length,
+                      MEMCACHED_MAX_BUFFER - ptr->hosts[x].read_data_length, 0);
+      if (data_read == SOCKET_ERROR)
+        continue;
+
+      ptr->hosts[x].read_buffer_length+= data_read;
+      ptr->hosts[x].read_data_length+= data_read;
+    }
+  }
+}
+#endif
+
+memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr,
+                                     void *buffer, size_t length, ssize_t *nread)
+{
+  char *buffer_ptr;
+
+  buffer_ptr= static_cast<char *>(buffer);
+
+  while (length)
+  {
+    if (not ptr->read_buffer_length)
+    {
+      ssize_t data_read;
+
+      while (1)
+      {
+        data_read= recv(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER, 0);
+        if (data_read > 0)
+        {
+          break;
+        }
+        else if (data_read == SOCKET_ERROR)
+        {
+          ptr->cached_errno= get_socket_errno();
+          memcached_return_t rc= MEMCACHED_ERRNO;
+          switch (get_socket_errno())
+          {
+          case EWOULDBLOCK:
+#ifdef USE_EAGAIN
+          case EAGAIN:
+#endif
+          case EINTR:
+#ifdef TARGET_OS_LINUX
+          case ERESTART:
+#endif
+            if ((rc= io_wait(ptr, MEM_READ)) == MEMCACHED_SUCCESS)
+              continue;
+            /* fall through */
+
+          default:
+            {
+              memcached_quit_server(ptr, true);
+              *nread= -1;
+              return rc;
+            }
+          }
+        }
+        else
+        {
+          /*
+            EOF. Any data received so far is incomplete
+            so discard it. This always reads by byte in case of TCP
+            and protocol enforcement happens at memcached_response()
+            looking for '\n'. We do not care for UDB which requests 8 bytes
+            at once. Generally, this means that connection went away. Since
+            for blocking I/O we do not return 0 and for non-blocking case
+            it will return EGAIN if data is not immediatly available.
+          */
+          WATCHPOINT_STRING("We had a zero length recv()");
+          memcached_quit_server(ptr, true);
+          *nread= -1;
+          return MEMCACHED_UNKNOWN_READ_FAILURE;
+        }
+      }
+
+      ptr->io_bytes_sent = 0;
+      ptr->read_data_length= (size_t) data_read;
+      ptr->read_buffer_length= (size_t) data_read;
+      ptr->read_ptr= ptr->read_buffer;
+    }
+
+    if (length > 1)
+    {
+      size_t difference;
+
+      difference= (length > ptr->read_buffer_length) ? ptr->read_buffer_length : length;
+
+      memcpy(buffer_ptr, ptr->read_ptr, difference);
+      length -= difference;
+      ptr->read_ptr+= difference;
+      ptr->read_buffer_length-= difference;
+      buffer_ptr+= difference;
+    }
+    else
+    {
+      *buffer_ptr= *ptr->read_ptr;
+      ptr->read_ptr++;
+      ptr->read_buffer_length--;
+      buffer_ptr++;
+      break;
+    }
+  }
+
+  ptr->server_failure_counter= 0;
+  *nread = (ssize_t)(buffer_ptr - (char*)buffer);
+  return MEMCACHED_SUCCESS;
+}
+
+static ssize_t _io_write(memcached_server_write_instance_st ptr,
+                         const void *buffer, size_t length, bool with_flush)
+{
+  size_t original_length;
+  const char* buffer_ptr;
+
+  WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+
+  original_length= length;
+  buffer_ptr= static_cast<const char *>(buffer);
+
+  while (length)
+  {
+    char *write_ptr;
+    size_t should_write;
+    size_t buffer_end;
+
+    if (ptr->type == MEMCACHED_CONNECTION_UDP)
+    {
+      //UDP does not support partial writes
+      buffer_end= MAX_UDP_DATAGRAM_LENGTH;
+      should_write= length;
+      if (ptr->write_buffer_offset + should_write > buffer_end)
+      {
+        return -1;
+      }
+    }
+    else
+    {
+      buffer_end= MEMCACHED_MAX_BUFFER;
+      should_write= buffer_end - ptr->write_buffer_offset;
+      should_write= (should_write < length) ? should_write : length;
+    }
+
+    write_ptr= ptr->write_buffer + ptr->write_buffer_offset;
+    memcpy(write_ptr, buffer_ptr, should_write);
+    ptr->write_buffer_offset+= should_write;
+    buffer_ptr+= should_write;
+    length-= should_write;
+
+    if (ptr->write_buffer_offset == buffer_end && ptr->type != MEMCACHED_CONNECTION_UDP)
+    {
+      memcached_return_t rc;
+      ssize_t sent_length;
+
+      WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+      sent_length= io_flush(ptr, with_flush, &rc);
+      if (sent_length == -1)
+      {
+        return -1;
+      }
+
+      /* If io_flush calls memcached_purge, sent_length may be 0 */
+      unlikely (sent_length != 0)
+      {
+        WATCHPOINT_ASSERT(sent_length == (ssize_t)buffer_end);
+      }
+    }
+  }
+
+  if (with_flush)
+  {
+    memcached_return_t rc;
+    WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+    if (io_flush(ptr, with_flush, &rc) == -1)
+    {
+      return -1;
+    }
+  }
+
+  return (ssize_t) original_length;
+}
+
+ssize_t memcached_io_write(memcached_server_write_instance_st ptr,
+                           const void *buffer, size_t length, bool with_flush)
+{
+  return _io_write(ptr, buffer, length, with_flush);
+}
+
+ssize_t memcached_io_writev(memcached_server_write_instance_st ptr,
+                            const struct libmemcached_io_vector_st *vector,
+                            size_t number_of, bool with_flush)
+{
+  ssize_t total= 0;
+
+  for (size_t x= 0; x < number_of; x++, vector++)
+  {
+    ssize_t returnable;
+
+    if ((returnable= _io_write(ptr, vector->buffer, vector->length, false)) == -1)
+    {
+      return -1;
+    }
+    total+= returnable;
+  }
+
+  if (with_flush)
+  {
+    if (memcached_io_write(ptr, NULL, 0, true) == -1)
+    {
+      return -1;
+    }
+  }
+
+  return total;
+}
+
+
+memcached_return_t memcached_io_close(memcached_server_write_instance_st ptr)
+{
+  if (ptr->fd == INVALID_SOCKET)
+  {
+    return MEMCACHED_SUCCESS;
+  }
+
+  /* in case of death shutdown to avoid blocking at close() */
+  if (shutdown(ptr->fd, SHUT_RDWR) == SOCKET_ERROR && get_socket_errno() != ENOTCONN)
+  {
+    WATCHPOINT_NUMBER(ptr->fd);
+    WATCHPOINT_ERRNO(get_socket_errno());
+    WATCHPOINT_ASSERT(get_socket_errno());
+  }
+
+  if (closesocket(ptr->fd) == SOCKET_ERROR)
+  {
+    WATCHPOINT_ERRNO(get_socket_errno());
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+memcached_server_write_instance_st memcached_io_get_readable_server(memcached_st *memc)
+{
+#define MAX_SERVERS_TO_POLL 100
+  struct pollfd fds[MAX_SERVERS_TO_POLL];
+  unsigned int host_index= 0;
+
+  for (uint32_t x= 0;
+       x< memcached_server_count(memc) && host_index < MAX_SERVERS_TO_POLL;
+       ++x)
+  {
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(memc, x);
+
+    if (instance->read_buffer_length > 0) /* I have data in the buffer */
+      return instance;
+
+    if (memcached_server_response_count(instance) > 0)
+    {
+      fds[host_index].events = POLLIN;
+      fds[host_index].revents = 0;
+      fds[host_index].fd = instance->fd;
+      ++host_index;
+    }
+  }
+
+  if (host_index < 2)
+  {
+    /* We have 0 or 1 server with pending events.. */
+    for (uint32_t x= 0; x< memcached_server_count(memc); ++x)
+    {
+      memcached_server_write_instance_st instance=
+        memcached_server_instance_fetch(memc, x);
+
+      if (memcached_server_response_count(instance) > 0)
+      {
+        return instance;
+      }
+    }
+
+    return NULL;
+  }
+
+  int err= poll(fds, host_index, memc->poll_timeout);
+  switch (err) {
+  case -1:
+    memcached_set_errno(memc, get_socket_errno(), NULL);
+    /* FALLTHROUGH */
+  case 0:
+    break;
+  default:
+    for (size_t x= 0; x < host_index; ++x)
+    {
+      if (fds[x].revents & POLLIN)
+      {
+        for (uint32_t y= 0; y < memcached_server_count(memc); ++y)
+        {
+          memcached_server_write_instance_st instance=
+            memcached_server_instance_fetch(memc, y);
+
+          if (instance->fd == fds[x].fd)
+            return instance;
+        }
+      }
+    }
+  }
+
+  return NULL;
+}
+
+static ssize_t io_flush(memcached_server_write_instance_st ptr,
+                        const bool with_flush,
+                        memcached_return_t *error)
+{
+  /*
+   ** We might want to purge the input buffer if we haven't consumed
+   ** any output yet... The test for the limits is the purge is inline
+   ** in the purge function to avoid duplicating the logic..
+ */
+  {
+    memcached_return_t rc;
+    WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+    rc= memcached_purge(ptr);
+
+    if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
+    {
+      return -1;
+    }
+  }
+  ssize_t sent_length;
+  size_t return_length;
+  char *local_write_ptr= ptr->write_buffer;
+  size_t write_length= ptr->write_buffer_offset;
+
+  *error= MEMCACHED_SUCCESS;
+
+  WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+
+  // UDP Sanity check, make sure that we are not sending somthing too big
+  if (ptr->type == MEMCACHED_CONNECTION_UDP && write_length > MAX_UDP_DATAGRAM_LENGTH)
+  {
+    return -1;
+  }
+
+  if (ptr->write_buffer_offset == 0 || (ptr->type == MEMCACHED_CONNECTION_UDP
+                                        && ptr->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH))
+    return 0;
+
+  /* Looking for memory overflows */
+#if defined(DEBUG)
+  if (write_length == MEMCACHED_MAX_BUFFER)
+    WATCHPOINT_ASSERT(ptr->write_buffer == local_write_ptr);
+  WATCHPOINT_ASSERT((ptr->write_buffer + MEMCACHED_MAX_BUFFER) >= (local_write_ptr + write_length));
+#endif
+
+  return_length= 0;
+  while (write_length)
+  {
+    WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+    WATCHPOINT_ASSERT(write_length > 0);
+    sent_length= 0;
+    if (ptr->type == MEMCACHED_CONNECTION_UDP)
+      increment_udp_message_id(ptr);
+
+    WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
+    if (with_flush)
+    {
+      sent_length= send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT);
+    }
+    else
+    {
+      sent_length= send(ptr->fd, local_write_ptr, write_length, MSG_NOSIGNAL|MSG_DONTWAIT|MSG_MORE);
+    }
+
+    if (sent_length == SOCKET_ERROR)
+    {
+      ptr->cached_errno= get_socket_errno();
+#if 0 // @todo I should look at why we hit this bit of code hard frequently
+      WATCHPOINT_ERRNO(get_socket_errno());
+      WATCHPOINT_NUMBER(get_socket_errno());
+#endif
+      switch (get_socket_errno())
+      {
+      case ENOBUFS:
+        continue;
+      case EWOULDBLOCK:
+#ifdef USE_EAGAIN
+      case EAGAIN:
+#endif
+        {
+          /*
+           * We may be blocked on write because the input buffer
+           * is full. Let's check if we have room in our input
+           * buffer for more data and retry the write before
+           * waiting..
+         */
+          if (repack_input_buffer(ptr) ||
+              process_input_buffer(ptr))
+            continue;
+
+          memcached_return_t rc;
+          rc= io_wait(ptr, MEM_WRITE);
+
+          if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_TIMEOUT)
+            continue;
+
+          memcached_quit_server(ptr, true);
+          return -1;
+        }
+      case ENOTCONN:
+      case EPIPE:
+      default:
+        memcached_quit_server(ptr, true);
+        *error= MEMCACHED_ERRNO;
+        WATCHPOINT_ASSERT(ptr->fd == -1);
+        return -1;
+      }
+    }
+
+    if (ptr->type == MEMCACHED_CONNECTION_UDP &&
+        (size_t)sent_length != write_length)
+    {
+      memcached_quit_server(ptr, true);
+      return -1;
+    }
+
+    ptr->io_bytes_sent += (uint32_t) sent_length;
+
+    local_write_ptr+= sent_length;
+    write_length-= (uint32_t) sent_length;
+    return_length+= (uint32_t) sent_length;
+  }
+
+  WATCHPOINT_ASSERT(write_length == 0);
+  // Need to study this assert() WATCHPOINT_ASSERT(return_length ==
+  // ptr->write_buffer_offset);
+
+  // if we are a udp server, the begining of the buffer is reserverd for
+  // the upd frame header
+  if (ptr->type == MEMCACHED_CONNECTION_UDP)
+    ptr->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
+  else
+    ptr->write_buffer_offset= 0;
+
+  return (ssize_t) return_length;
+}
+
+/*
+  Eventually we will just kill off the server with the problem.
+*/
+void memcached_io_reset(memcached_server_write_instance_st ptr)
+{
+  memcached_quit_server(ptr, true);
+}
+
+/**
+ * Read a given number of bytes from the server and place it into a specific
+ * buffer. Reset the IO channel on this server if an error occurs.
+ */
+memcached_return_t memcached_safe_read(memcached_server_write_instance_st ptr,
+                                       void *dta,
+                                       size_t size)
+{
+  size_t offset= 0;
+  char *data= static_cast<char *>(dta);
+
+  while (offset < size)
+  {
+    ssize_t nread;
+    memcached_return_t rc= memcached_io_read(ptr, data + offset, size - offset,
+                                             &nread);
+    if (rc != MEMCACHED_SUCCESS)
+      return rc;
+
+    offset+= (size_t) nread;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_io_readline(memcached_server_write_instance_st ptr,
+                                         char *buffer_ptr,
+                                         size_t size)
+{
+  bool line_complete= false;
+  size_t total_nr= 0;
+
+  while (!line_complete)
+  {
+    if (ptr->read_buffer_length == 0)
+    {
+      /*
+       * We don't have any data in the buffer, so let's fill the read
+       * buffer. Call the standard read function to avoid duplicating
+       * the logic.
+     */
+      ssize_t nread;
+      memcached_return_t rc= memcached_io_read(ptr, buffer_ptr, 1, &nread);
+      if (rc != MEMCACHED_SUCCESS)
+        return rc;
+
+      if (*buffer_ptr == '\n')
+        line_complete= true;
+
+      ++buffer_ptr;
+      ++total_nr;
+    }
+
+    /* Now let's look in the buffer and copy as we go! */
+    while (ptr->read_buffer_length && total_nr < size && !line_complete)
+    {
+      *buffer_ptr = *ptr->read_ptr;
+      if (*buffer_ptr == '\n')
+        line_complete = true;
+      --ptr->read_buffer_length;
+      ++ptr->read_ptr;
+      ++total_nr;
+      ++buffer_ptr;
+    }
+
+    if (total_nr == size)
+      return MEMCACHED_PROTOCOL_ERROR;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+/*
+ * The udp request id consists of two seperate sections
+ *   1) The thread id
+ *   2) The message number
+ * The thread id should only be set when the memcached_st struct is created
+ * and should not be changed.
+ *
+ * The message num is incremented for each new message we send, this function
+ * extracts the message number from message_id, increments it and then
+ * writes the new value back into the header
+ */
+static void increment_udp_message_id(memcached_server_write_instance_st ptr)
+{
+  struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer;
+  uint16_t cur_req= get_udp_datagram_request_id(header);
+  int msg_num= get_msg_num_from_request_id(cur_req);
+  int thread_id= get_thread_id_from_request_id(cur_req);
+
+  if (((++msg_num) & UDP_REQUEST_ID_THREAD_MASK) != 0)
+    msg_num= 0;
+
+  header->request_id= htons((uint16_t) (thread_id | msg_num));
+}
+
+memcached_return_t memcached_io_init_udp_header(memcached_server_write_instance_st ptr, uint16_t thread_id)
+{
+  if (thread_id > UDP_REQUEST_ID_MAX_THREAD_ID)
+    return MEMCACHED_FAILURE;
+
+  struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer;
+  header->request_id= htons((uint16_t) (generate_udp_request_thread_id(thread_id)));
+  header->num_datagrams= htons(1);
+  header->sequence_number= htons(0);
+
+  return MEMCACHED_SUCCESS;
+}
index 85d56b16d70539e93fede37a7cabcc230488566a..a5d344748671e4f17519ca835d3b1618270355aa 100644 (file)
  *
  */
 
-#ifndef __LIBMEMCACHED_IO_H__
-#define __LIBMEMCACHED_IO_H__
+#pragma once
 
-#if defined(BUILDING_LIBMEMCACHED)
-
-#include "libmemcached/memcached.h"
+#include <libmemcached/memcached.h>
 
 #define MAX_UDP_DATAGRAM_LENGTH 1400
 #define UDP_DATAGRAM_HEADER_LENGTH 8
@@ -117,7 +114,3 @@ memcached_server_write_instance_st memcached_io_get_readable_server(memcached_st
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* BUILDING_LIBMEMCACHED */
-
-#endif /* __LIBMEMCACHED_IO_H__ */
diff --git a/libmemcached/key.c b/libmemcached/key.c
deleted file mode 100644 (file)
index 76a7d8e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#include "common.h"
-
-memcached_return_t memcached_key_test(const char * const *keys,
-                                      const size_t *key_length,
-                                      size_t number_of_keys)
-{
-  uint32_t x;
-  memcached_return_t rc;
-
-  for (x= 0; x < number_of_keys; x++)
-  {
-    size_t y;
-
-    rc= memcached_validate_key_length(*(key_length + x), false);
-    if (rc != MEMCACHED_SUCCESS)
-      return rc;
-    for (y= 0; y < *(key_length + x); y++)
-    {
-      if ((isgraph(keys[x][y])) == 0)
-        return MEMCACHED_BAD_KEY_PROVIDED;
-    }
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
diff --git a/libmemcached/key.cc b/libmemcached/key.cc
new file mode 100644 (file)
index 0000000..c2c2b14
--- /dev/null
@@ -0,0 +1,23 @@
+#include "common.h"
+
+memcached_return_t memcached_key_test(const char * const *keys,
+                                      const size_t *key_length,
+                                      size_t number_of_keys)
+{
+  for (uint32_t x= 0; x < number_of_keys; x++)
+  {
+    memcached_return_t rc;
+    rc= memcached_validate_key_length(*(key_length + x), false);
+    if (rc != MEMCACHED_SUCCESS)
+      return rc;
+    for (size_t y= 0; y < *(key_length + x); y++)
+    {
+      if ((isgraph(keys[x][y])) == 0)
+        return MEMCACHED_BAD_KEY_PROVIDED;
+    }
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
diff --git a/libmemcached/memcached.c b/libmemcached/memcached.c
deleted file mode 100644 (file)
index c57b257..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- * 
- *  Libmemcached library
- *
- *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
- *  Copyright (C) 2006-2009 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/virtual_bucket.h>
-
-static const memcached_st global_copy= {
-  .state= {
-    .is_purging= false,
-    .is_processing_input= false,
-    .is_time_for_rebuild= false,
-  },
-  .flags= {
-    .auto_eject_hosts= false,
-    .binary_protocol= false,
-    .buffer_requests= false,
-    .hash_with_prefix_key= false,
-    .no_block= false,
-    .no_reply= false,
-    .randomize_replica_read= false,
-    .support_cas= false,
-    .tcp_nodelay= false,
-    .use_sort_hosts= false,
-    .use_udp= false,
-    .verify_key= false,
-    .tcp_keepalive= false,
-  },
-};
-
-static inline bool _memcached_init(memcached_st *self)
-{
-  self->state= global_copy.state;
-  self->flags= global_copy.flags;
-  self->virtual_bucket= NULL;
-
-  self->distribution= MEMCACHED_DISTRIBUTION_MODULA;
-
-  hashkit_st *hash_ptr;
-  hash_ptr= hashkit_create(&self->hashkit);
-  if (! hash_ptr)
-    return false;
-
-  self->ketama.continuum= NULL;
-  self->ketama.continuum_count= 0;
-  self->ketama.continuum_points_counter= 0;
-  self->ketama.next_distribution_rebuild= 0;
-  self->ketama.weighted= false;
-
-  self->number_of_hosts= 0;
-  self->servers= NULL;
-  self->last_disconnected_server= NULL;
-
-  self->snd_timeout= 0;
-  self->rcv_timeout= 0;
-  self->server_failure_limit= 0;
-  self->query_id= 0;
-
-  /* TODO, Document why we picked these defaults */
-  self->io_msg_watermark= 500;
-  self->io_bytes_watermark= 65 * 1024;
-
-  self->tcp_keepidle= 0;
-
-  self->io_key_prefetch= 0;
-  self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
-  self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
-  self->retry_timeout= 0;
-
-  self->send_size= -1;
-  self->recv_size= -1;
-
-  self->user_data= NULL;
-  self->number_of_replicas= 0;
-  hash_ptr= hashkit_create(&self->distribution_hashkit);
-  if (! hash_ptr)
-    return false;
-
-  self->allocators= memcached_allocators_return_default();
-
-  self->on_clone= NULL;
-  self->on_cleanup= NULL;
-  self->get_key_failure= NULL;
-  self->delete_trigger= NULL;
-  self->callbacks= NULL;
-  self->sasl.callbacks= NULL;
-  self->sasl.is_allocated= false;
-
-  self->error_messages= NULL;
-  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;
-}
-
-static void _free(memcached_st *ptr, bool release_st)
-{
-  /* If we have anything open, lets close it now */
-  send_quit(ptr);
-  memcached_server_list_free(memcached_server_list(ptr));
-  memcached_result_free(&ptr->result);
-
-  memcached_virtual_bucket_free(ptr);
-
-  if (ptr->last_disconnected_server)
-    memcached_server_free(ptr->last_disconnected_server);
-
-  if (ptr->on_cleanup)
-    ptr->on_cleanup(ptr);
-
-  if (ptr->ketama.continuum)
-    libmemcached_free(ptr, ptr->ketama.continuum);
-
-  memcached_array_free(ptr->prefix_key);
-  ptr->prefix_key= NULL;
-
-  memcached_error_free(ptr);
-
-  if (ptr->sasl.callbacks)
-  {
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
-    memcached_destroy_sasl_auth_data(ptr);
-#endif
-  }
-
-  if (release_st)
-  {
-    memcached_array_free(ptr->configure.filename);
-    ptr->configure.filename= NULL;
-  }
-
-  if (memcached_is_allocated(ptr) && release_st)
-  {
-    libmemcached_free(ptr, ptr);
-  }
-}
-
-memcached_st *memcached_create(memcached_st *ptr)
-{
-  if (ptr == NULL)
-  {
-    ptr= (memcached_st *)malloc(sizeof(memcached_st));
-
-    if (! ptr)
-    {
-      return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
-    }
-
-    ptr->options.is_allocated= true;
-  }
-  else
-  {
-    ptr->options.is_allocated= false;
-  }
-
-#if 0
-  memcached_set_purging(ptr, false);
-  memcached_set_processing_input(ptr, false);
-#endif
-
-  if (! _memcached_init(ptr))
-  {
-    memcached_free(ptr);
-    return NULL;
-  }
-
-  if (! memcached_result_create(ptr, &ptr->result))
-  {
-    memcached_free(ptr);
-    return NULL;
-  }
-
-  WATCHPOINT_ASSERT_INITIALIZED(&ptr->result);
-
-  return ptr;
-}
-
-memcached_st *memcached(const char *string, size_t length)
-{
-  if (! length || ! string)
-  {
-    errno= EINVAL;
-    return NULL;
-  }
-
-  memcached_st *self= memcached_create(NULL);
-  if (! self)
-  {
-    errno= ENOMEM;
-    return NULL;
-  }
-
-  memcached_return_t rc;
-  rc= memcached_parse_configuration(self, string, length);
-
-  if (rc == MEMCACHED_SUCCESS && memcached_parse_filename(self))
-  {
-    rc= memcached_parse_configure_file(self, memcached_parse_filename(self), memcached_parse_filename_length(self));
-  }
-    
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    memcached_free(self);
-    errno= EINVAL;
-    return NULL;
-  }
-
-  errno= 0;
-
-  return self;
-}
-
-memcached_return_t memcached_reset(memcached_st *ptr)
-{
-  WATCHPOINT_ASSERT(ptr);
-  if (! ptr)
-    return MEMCACHED_INVALID_ARGUMENTS;
-
-  bool stored_is_allocated= memcached_is_allocated(ptr);
-  uint64_t query_id= ptr->query_id;
-  _free(ptr, false);
-  memcached_create(ptr);
-  memcached_set_allocated(ptr, stored_is_allocated);
-  ptr->query_id= query_id;
-
-  if (ptr->configure.filename)
-  {
-    return memcached_parse_configure_file(ptr, memcached_param_array(ptr->configure.filename));
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-void memcached_servers_reset(memcached_st *ptr)
-{
-  if (! ptr)
-    return;
-
-  memcached_server_list_free(memcached_server_list(ptr));
-
-  memcached_server_list_set(ptr, NULL);
-  ptr->number_of_hosts= 0;
-  if (ptr->last_disconnected_server)
-  {
-    memcached_server_free(ptr->last_disconnected_server);
-  }
-  ptr->last_disconnected_server= NULL;
-  ptr->server_failure_limit= 0;
-}
-
-void memcached_reset_last_disconnected_server(memcached_st *ptr)
-{
-  if (! ptr)
-    return;
-
-  if (ptr->last_disconnected_server)
-  {
-    memcached_server_free(ptr->last_disconnected_server);
-    ptr->last_disconnected_server= NULL;
-  }
-}
-
-void memcached_free(memcached_st *ptr)
-{
-  if (! ptr)
-    return;
-
-  _free(ptr, true);
-}
-
-/*
-  clone is the destination, while source is the structure to clone.
-  If source is NULL the call is the same as if a memcached_create() was
-  called.
-*/
-memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source)
-{
-  memcached_return_t rc= MEMCACHED_SUCCESS;
-  memcached_st *new_clone;
-
-  if (source == NULL)
-    return memcached_create(clone);
-
-  if (clone && memcached_is_allocated(clone))
-  {
-    return NULL;
-  }
-
-  new_clone= memcached_create(clone);
-
-  if (new_clone == NULL)
-    return NULL;
-
-  new_clone->flags= source->flags;
-  new_clone->send_size= source->send_size;
-  new_clone->recv_size= source->recv_size;
-  new_clone->poll_timeout= source->poll_timeout;
-  new_clone->connect_timeout= source->connect_timeout;
-  new_clone->retry_timeout= source->retry_timeout;
-  new_clone->distribution= source->distribution;
-
-  hashkit_st *hash_ptr;
-
-  hash_ptr= hashkit_clone(&new_clone->hashkit, &source->hashkit);
-  if (! hash_ptr)
-  {
-    memcached_free(new_clone);
-    return NULL;
-  }
-
-  hash_ptr= hashkit_clone(&new_clone->distribution_hashkit, &source->distribution_hashkit);
-  if (! hash_ptr)
-  {
-    memcached_free(new_clone);
-    return NULL;
-  }
-
-  new_clone->user_data= source->user_data;
-
-  new_clone->snd_timeout= source->snd_timeout;
-  new_clone->rcv_timeout= source->rcv_timeout;
-
-  new_clone->on_clone= source->on_clone;
-  new_clone->on_cleanup= source->on_cleanup;
-
-  new_clone->allocators= source->allocators;
-
-  new_clone->get_key_failure= source->get_key_failure;
-  new_clone->delete_trigger= source->delete_trigger;
-  new_clone->server_failure_limit= source->server_failure_limit;
-  new_clone->io_msg_watermark= source->io_msg_watermark;
-  new_clone->io_bytes_watermark= source->io_bytes_watermark;
-  new_clone->io_key_prefetch= source->io_key_prefetch;
-  new_clone->number_of_replicas= source->number_of_replicas;
-  new_clone->tcp_keepidle= source->tcp_keepidle;
-
-  if (memcached_server_count(source))
-    rc= memcached_push(new_clone, source);
-
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    memcached_free(new_clone);
-
-    return NULL;
-  }
-
-
-  new_clone->prefix_key= memcached_array_clone(new_clone, source->prefix_key);
-
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
-  if (source->sasl.callbacks)
-  {
-    if (memcached_clone_sasl(new_clone, source) != MEMCACHED_SUCCESS)
-    {
-      memcached_free(new_clone);
-      return NULL;
-    }
-  }
-#endif
-
-  rc= run_distribution(new_clone);
-
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    memcached_free(new_clone);
-
-    return NULL;
-  }
-
-  if (source->on_clone)
-    source->on_clone(new_clone, source);
-
-  return new_clone;
-}
-
-void *memcached_get_user_data(const memcached_st *ptr)
-{
-  return ptr->user_data;
-}
-
-void *memcached_set_user_data(memcached_st *ptr, void *data)
-{
-  void *ret= ptr->user_data;
-  ptr->user_data= data;
-
-  return ret;
-}
-
-memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source)
-{
-  return memcached_server_push(destination, source->servers);
-}
-
-memcached_server_write_instance_st memcached_server_instance_fetch(memcached_st *ptr, uint32_t server_key)
-{
-  return &ptr->servers[server_key];
-}
-
-memcached_server_instance_st memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key)
-{
-  return &ptr->servers[server_key];
-}
diff --git a/libmemcached/memcached.cc b/libmemcached/memcached.cc
new file mode 100644 (file)
index 0000000..1197dd5
--- /dev/null
@@ -0,0 +1,464 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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/virtual_bucket.h>
+
+#if 0
+static const memcached_st global_copy= {
+  .state= {
+    .is_purging= false, // .is_purging
+    .is_processing_input= false, // is_processing_input
+    .is_time_for_rebuild= false,
+  },
+  .flags= {
+    .auto_eject_hosts= false,
+    .binary_protocol= false,
+    .buffer_requests= false,
+    .hash_with_prefix_key= false,
+    .no_block= false,
+    .no_reply= false,
+    .randomize_replica_read= false,
+    .support_cas= false,
+    .tcp_nodelay= false,
+    .use_sort_hosts= false,
+    .use_udp= false,
+    .verify_key= false,
+    .tcp_keepalive= false,
+  },
+};
+#endif
+
+static inline bool _memcached_init(memcached_st *self)
+{
+  self->state.is_purging= false;
+  self->state.is_processing_input= false;
+  self->state.is_time_for_rebuild= false;
+
+  self->flags.auto_eject_hosts= false;
+  self->flags.binary_protocol= false;
+  self->flags.buffer_requests= false;
+  self->flags.hash_with_prefix_key= false;
+  self->flags.no_block= false;
+  self->flags.no_reply= false;
+  self->flags.randomize_replica_read= false;
+  self->flags.support_cas= false;
+  self->flags.tcp_nodelay= false;
+  self->flags.use_sort_hosts= false;
+  self->flags.use_udp= false;
+  self->flags.verify_key= false;
+  self->flags.tcp_keepalive= false;
+
+  self->virtual_bucket= NULL;
+
+  self->distribution= MEMCACHED_DISTRIBUTION_MODULA;
+
+  hashkit_st *hash_ptr;
+  hash_ptr= hashkit_create(&self->hashkit);
+  if (! hash_ptr)
+    return false;
+
+  self->ketama.continuum= NULL;
+  self->ketama.continuum_count= 0;
+  self->ketama.continuum_points_counter= 0;
+  self->ketama.next_distribution_rebuild= 0;
+  self->ketama.weighted= false;
+
+  self->number_of_hosts= 0;
+  self->servers= NULL;
+  self->last_disconnected_server= NULL;
+
+  self->snd_timeout= 0;
+  self->rcv_timeout= 0;
+  self->server_failure_limit= 0;
+  self->query_id= 1; // 0 is considered invalid
+
+  /* TODO, Document why we picked these defaults */
+  self->io_msg_watermark= 500;
+  self->io_bytes_watermark= 65 * 1024;
+
+  self->tcp_keepidle= 0;
+
+  self->io_key_prefetch= 0;
+  self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
+  self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
+  self->retry_timeout= 0;
+
+  self->send_size= -1;
+  self->recv_size= -1;
+
+  self->user_data= NULL;
+  self->number_of_replicas= 0;
+  hash_ptr= hashkit_create(&self->distribution_hashkit);
+  if (! hash_ptr)
+    return false;
+
+  self->allocators= memcached_allocators_return_default();
+
+  self->on_clone= NULL;
+  self->on_cleanup= NULL;
+  self->get_key_failure= NULL;
+  self->delete_trigger= NULL;
+  self->callbacks= NULL;
+  self->sasl.callbacks= NULL;
+  self->sasl.is_allocated= false;
+
+  self->error_messages= NULL;
+  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;
+}
+
+static void _free(memcached_st *ptr, bool release_st)
+{
+  /* If we have anything open, lets close it now */
+  send_quit(ptr);
+  memcached_server_list_free(memcached_server_list(ptr));
+  memcached_result_free(&ptr->result);
+
+  memcached_virtual_bucket_free(ptr);
+
+  if (ptr->last_disconnected_server)
+    memcached_server_free(ptr->last_disconnected_server);
+
+  if (ptr->on_cleanup)
+    ptr->on_cleanup(ptr);
+
+  if (ptr->ketama.continuum)
+    libmemcached_free(ptr, ptr->ketama.continuum);
+
+  memcached_array_free(ptr->prefix_key);
+  ptr->prefix_key= NULL;
+
+  memcached_error_free(ptr);
+
+  if (ptr->sasl.callbacks)
+  {
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+    memcached_destroy_sasl_auth_data(ptr);
+#endif
+  }
+
+  if (release_st)
+  {
+    memcached_array_free(ptr->configure.filename);
+    ptr->configure.filename= NULL;
+  }
+
+  if (memcached_is_allocated(ptr) && release_st)
+  {
+    libmemcached_free(ptr, ptr);
+  }
+}
+
+memcached_st *memcached_create(memcached_st *ptr)
+{
+  if (ptr == NULL)
+  {
+    ptr= (memcached_st *)malloc(sizeof(memcached_st));
+
+    if (! ptr)
+    {
+      return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
+    }
+
+    ptr->options.is_allocated= true;
+  }
+  else
+  {
+    ptr->options.is_allocated= false;
+  }
+
+#if 0
+  memcached_set_purging(ptr, false);
+  memcached_set_processing_input(ptr, false);
+#endif
+
+  if (! _memcached_init(ptr))
+  {
+    memcached_free(ptr);
+    return NULL;
+  }
+
+  if (! memcached_result_create(ptr, &ptr->result))
+  {
+    memcached_free(ptr);
+    return NULL;
+  }
+
+  WATCHPOINT_ASSERT_INITIALIZED(&ptr->result);
+
+  return ptr;
+}
+
+memcached_st *memcached(const char *string, size_t length)
+{
+  if (! length || ! string)
+  {
+    errno= EINVAL;
+    return NULL;
+  }
+
+  memcached_st *self= memcached_create(NULL);
+  if (! self)
+  {
+    errno= ENOMEM;
+    return NULL;
+  }
+
+  memcached_return_t rc;
+  rc= memcached_parse_configuration(self, string, length);
+
+  if (rc == MEMCACHED_SUCCESS && memcached_parse_filename(self))
+  {
+    rc= memcached_parse_configure_file(self, memcached_parse_filename(self), memcached_parse_filename_length(self));
+  }
+    
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    memcached_free(self);
+    errno= EINVAL;
+    return NULL;
+  }
+
+  errno= 0;
+
+  return self;
+}
+
+memcached_return_t memcached_reset(memcached_st *ptr)
+{
+  WATCHPOINT_ASSERT(ptr);
+  if (not ptr)
+    return MEMCACHED_INVALID_ARGUMENTS;
+
+  bool stored_is_allocated= memcached_is_allocated(ptr);
+  uint64_t query_id= ptr->query_id;
+  _free(ptr, false);
+  memcached_create(ptr);
+  memcached_set_allocated(ptr, stored_is_allocated);
+  ptr->query_id= query_id;
+
+  if (ptr->configure.filename)
+  {
+    return memcached_parse_configure_file(ptr, memcached_param_array(ptr->configure.filename));
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+void memcached_servers_reset(memcached_st *ptr)
+{
+  if (! ptr)
+    return;
+
+  memcached_server_list_free(memcached_server_list(ptr));
+
+  memcached_server_list_set(ptr, NULL);
+  ptr->number_of_hosts= 0;
+  if (ptr->last_disconnected_server)
+  {
+    memcached_server_free(ptr->last_disconnected_server);
+  }
+  ptr->last_disconnected_server= NULL;
+  ptr->server_failure_limit= 0;
+}
+
+void memcached_reset_last_disconnected_server(memcached_st *ptr)
+{
+  if (! ptr)
+    return;
+
+  if (ptr->last_disconnected_server)
+  {
+    memcached_server_free(ptr->last_disconnected_server);
+    ptr->last_disconnected_server= NULL;
+  }
+}
+
+void memcached_free(memcached_st *ptr)
+{
+  if (! ptr)
+    return;
+
+  _free(ptr, true);
+}
+
+/*
+  clone is the destination, while source is the structure to clone.
+  If source is NULL the call is the same as if a memcached_create() was
+  called.
+*/
+memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source)
+{
+  memcached_return_t rc= MEMCACHED_SUCCESS;
+  memcached_st *new_clone;
+
+  if (source == NULL)
+    return memcached_create(clone);
+
+  if (clone && memcached_is_allocated(clone))
+  {
+    return NULL;
+  }
+
+  new_clone= memcached_create(clone);
+
+  if (new_clone == NULL)
+    return NULL;
+
+  new_clone->flags= source->flags;
+  new_clone->send_size= source->send_size;
+  new_clone->recv_size= source->recv_size;
+  new_clone->poll_timeout= source->poll_timeout;
+  new_clone->connect_timeout= source->connect_timeout;
+  new_clone->retry_timeout= source->retry_timeout;
+  new_clone->distribution= source->distribution;
+
+  hashkit_st *hash_ptr;
+
+  hash_ptr= hashkit_clone(&new_clone->hashkit, &source->hashkit);
+  if (! hash_ptr)
+  {
+    memcached_free(new_clone);
+    return NULL;
+  }
+
+  hash_ptr= hashkit_clone(&new_clone->distribution_hashkit, &source->distribution_hashkit);
+  if (! hash_ptr)
+  {
+    memcached_free(new_clone);
+    return NULL;
+  }
+
+  new_clone->user_data= source->user_data;
+
+  new_clone->snd_timeout= source->snd_timeout;
+  new_clone->rcv_timeout= source->rcv_timeout;
+
+  new_clone->on_clone= source->on_clone;
+  new_clone->on_cleanup= source->on_cleanup;
+
+  new_clone->allocators= source->allocators;
+
+  new_clone->get_key_failure= source->get_key_failure;
+  new_clone->delete_trigger= source->delete_trigger;
+  new_clone->server_failure_limit= source->server_failure_limit;
+  new_clone->io_msg_watermark= source->io_msg_watermark;
+  new_clone->io_bytes_watermark= source->io_bytes_watermark;
+  new_clone->io_key_prefetch= source->io_key_prefetch;
+  new_clone->number_of_replicas= source->number_of_replicas;
+  new_clone->tcp_keepidle= source->tcp_keepidle;
+
+  if (memcached_server_count(source))
+    rc= memcached_push(new_clone, source);
+
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    memcached_free(new_clone);
+
+    return NULL;
+  }
+
+
+  new_clone->prefix_key= memcached_array_clone(new_clone, source->prefix_key);
+
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+  if (source->sasl.callbacks)
+  {
+    if (memcached_clone_sasl(new_clone, source) != MEMCACHED_SUCCESS)
+    {
+      memcached_free(new_clone);
+      return NULL;
+    }
+  }
+#endif
+
+  rc= run_distribution(new_clone);
+
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    memcached_free(new_clone);
+
+    return NULL;
+  }
+
+  if (source->on_clone)
+    source->on_clone(new_clone, source);
+
+  return new_clone;
+}
+
+void *memcached_get_user_data(const memcached_st *ptr)
+{
+  return ptr->user_data;
+}
+
+void *memcached_set_user_data(memcached_st *ptr, void *data)
+{
+  void *ret= ptr->user_data;
+  ptr->user_data= data;
+
+  return ret;
+}
+
+memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source)
+{
+  return memcached_server_push(destination, source->servers);
+}
+
+memcached_server_write_instance_st memcached_server_instance_fetch(memcached_st *ptr, uint32_t server_key)
+{
+  return &ptr->servers[server_key];
+}
+
+memcached_server_instance_st memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key)
+{
+  return &ptr->servers[server_key];
+}
+
+uint64_t memcached_query_id(const memcached_st *self)
+{
+  if (not self)
+    return 0;
+
+  return self->query_id;
+}
index 1baab961bbf7b9b348c3cb1cad386f899104ea5d..f32fe0e794cf2105a6e5864b1bca5ad8a70c3d2e 100644 (file)
@@ -57,6 +57,7 @@
 #include <libmemcached/error.h>
 #include <libmemcached/stats.h>
 #include <libhashkit/hashkit.h>
+
 // Everything above this line must be in the order specified.
 #include <libmemcached/allocators.h>
 #include <libmemcached/analyze.h>
@@ -142,13 +143,7 @@ struct memcached_st {
 
   struct memcached_virtual_bucket_t *virtual_bucket;
 
-  struct _allocators_st {
-    memcached_calloc_fn calloc;
-    memcached_free_fn free;
-    memcached_malloc_fn malloc;
-    memcached_realloc_fn realloc;
-    void *context;
-  } allocators;
+  struct memcached_allocator_t allocators;
 
   memcached_clone_fn on_clone;
   memcached_cleanup_fn on_cleanup;
@@ -210,6 +205,9 @@ memcached_server_instance_st memcached_server_instance_by_position(const memcach
 LIBMEMCACHED_API
 uint32_t memcached_server_count(const memcached_st *);
 
+LIBMEMCACHED_API
+uint64_t memcached_query_id(const memcached_st *);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 55f96c7ea7a18952142d21ae3d0963b5e827e295..b0985715ed06d5403fa5981954cd281b3c32c8de 100644 (file)
@@ -13,8 +13,6 @@
  */
 
 #pragma once
-#ifndef LIBMEMCACHEDPP_H
-#define LIBMEMCACHEDPP_H
 
 #include <libmemcached/memcached.h>
 #include <libmemcached/exception.hpp>
@@ -37,8 +35,7 @@ class Memcache
 {
 public:
 
-  Memcache()
-    :
+  Memcache() :
       servers_list(),
       memc(),
       result()
@@ -261,17 +258,12 @@ public:
    *                     this vector
    * @return true on success; false otherwise
    */
-  bool get(const std::string &key,
-           std::vector<char> &ret_val) throw (Error)
+  bool get(const std::string &key, std::vector<char> &ret_val)
   {
     uint32_t flags= 0;
     memcached_return_t rc;
     size_t value_length= 0;
 
-    if (key.empty())
-    {
-      throw(Error("the key supplied is empty!", false));
-    }
     char *value= memcached_get(&memc, key.c_str(), key.length(),
                                &value_length, &flags, &rc);
     if (value != NULL && ret_val.empty())
@@ -298,16 +290,12 @@ public:
    */
   bool getByKey(const std::string &master_key,
                 const std::string &key,
-                std::vector<char> &ret_val) throw(Error)
+                std::vector<char> &ret_val)
   {
     uint32_t flags= 0;
     memcached_return_t rc;
     size_t value_length= 0;
 
-    if (master_key.empty() || key.empty())
-    {
-      throw(Error("the master key or key supplied is empty!", false));
-    }
     char *value= memcached_get_by_key(&memc,
                                       master_key.c_str(), master_key.length(),
                                       key.c_str(), key.length(),
@@ -379,12 +367,8 @@ public:
   bool set(const std::string &key,
            const std::vector<char> &value,
            time_t expiration,
-           uint32_t flags) throw(Error)
+           uint32_t flags)
   {
-    if (key.empty() || value.empty())
-    {
-      throw(Error("the key or value supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_set(&memc,
                                        key.c_str(), key.length(),
                                        &value[0], value.size(),
@@ -407,14 +391,8 @@ public:
                 const std::string &key,
                 const std::vector<char> &value,
                 time_t expiration,
-                uint32_t flags) throw(Error)
+                uint32_t flags)
   {
-    if (master_key.empty() ||
-        key.empty() ||
-        value.empty())
-    {
-      throw(Error("the key or value supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_set_by_key(&memc, master_key.c_str(),
                                               master_key.length(),
                                               key.c_str(), key.length(),
@@ -437,12 +415,8 @@ public:
   bool setAll(std::vector<std::string> &keys,
               std::vector< std::vector<char> *> &values,
               time_t expiration,
-              uint32_t flags) throw(Error)
+              uint32_t flags)
   {
-    if (keys.size() != values.size())
-    {
-      throw(Error("The number of keys and values do not match!", false));
-    }
     bool retval= true;
     std::vector<std::string>::iterator key_it= keys.begin();
     std::vector< std::vector<char> *>::iterator val_it= values.begin();
@@ -470,23 +444,18 @@ public:
    */
   bool setAll(std::map<const std::string, std::vector<char> > &key_value_map,
               time_t expiration,
-              uint32_t flags) throw(Error)
+              uint32_t flags)
   {
-    if (key_value_map.empty())
-    {
-      throw(Error("The key/values are not properly set!", false));
-    }
     bool retval= true;
-    std::map<const std::string, std::vector<char> >::iterator it=
-      key_value_map.begin();
+    std::map<const std::string, std::vector<char> >::iterator it= key_value_map.begin();
+
     while (it != key_value_map.end())
     {
       retval= set(it->first, it->second, expiration, flags);
       if (retval == false)
       {
-        std::string err_buff("There was an error setting the key ");
-        err_buff.append(it->first);
-        throw(Error(err_buff, false));
+        // We should tell the user what the key that failed was
+        return false;
       }
       ++it;
     }
@@ -503,12 +472,8 @@ public:
    * @param[out] value store the result of the increment here
    * @return true on success; false otherwise
    */
-  bool increment(const std::string &key, uint32_t offset, uint64_t *value) throw(Error)
+  bool increment(const std::string &key, uint32_t offset, uint64_t *value)
   {
-    if (key.empty())
-    {
-      throw(Error("the key supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_increment(&memc, key.c_str(), key.length(),
                                              offset, value);
     return (rc == MEMCACHED_SUCCESS);
@@ -525,12 +490,7 @@ public:
    * @return true on success; false otherwise
    */
   bool decrement(const std::string &key, uint32_t offset, uint64_t *value)
-    throw(Error)
   {
-    if (key.empty())
-    {
-      throw(Error("the key supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_decrement(&memc, key.c_str(),
                                              key.length(),
                                              offset, value);
@@ -547,12 +507,7 @@ public:
    * @return true on success; false otherwise
    */
   bool add(const std::string &key, const std::vector<char> &value)
-    throw(Error)
   {
-    if (key.empty() || value.empty())
-    {
-      throw(Error("the key or value supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_add(&memc, key.c_str(), key.length(),
                                        &value[0], value.size(), 0, 0);
     return (rc == MEMCACHED_SUCCESS);
@@ -570,14 +525,8 @@ public:
    */
   bool addByKey(const std::string &master_key,
                 const std::string &key,
-                const std::vector<char> &value) throw(Error)
+                const std::vector<char> &value)
   {
-    if (master_key.empty() ||
-        key.empty() ||
-        value.empty())
-    {
-      throw(Error("the master key or key supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_add_by_key(&memc,
                                               master_key.c_str(),
                                               master_key.length(),
@@ -597,13 +546,8 @@ public:
    * @param[in[ value value to replace object with
    * @return true on success; false otherwise
    */
-  bool replace(const std::string &key, const std::vector<char> &value) throw(Error)
+  bool replace(const std::string &key, const std::vector<char> &value)
   {
-    if (key.empty() ||
-        value.empty())
-    {
-      throw(Error("the key or value supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_replace(&memc, key.c_str(), key.length(),
                                            &value[0], value.size(),
                                            0, 0);
@@ -624,12 +568,6 @@ public:
                     const std::string &key,
                     const std::vector<char> &value)
   {
-    if (master_key.empty() ||
-        key.empty() ||
-        value.empty())
-    {
-      throw(Error("the master key or key supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_replace_by_key(&memc,
                                                   master_key.c_str(),
                                                   master_key.length(),
@@ -649,12 +587,7 @@ public:
    * @return true on success; false otherwise
    */
   bool prepend(const std::string &key, const std::vector<char> &value)
-    throw(Error)
   {
-    if (key.empty() || value.empty())
-    {
-      throw(Error("the key or value supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_prepend(&memc, key.c_str(), key.length(),
                                            &value[0], value.size(), 0, 0);
     return (rc == MEMCACHED_SUCCESS);
@@ -673,14 +606,7 @@ public:
   bool prependByKey(const std::string &master_key,
                     const std::string &key,
                     const std::vector<char> &value)
-      throw(Error)
   {
-    if (master_key.empty() ||
-        key.empty() ||
-        value.empty())
-    {
-      throw(Error("the master key or key supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_prepend_by_key(&memc,
                                                   master_key.c_str(),
                                                   master_key.length(),
@@ -701,18 +627,13 @@ public:
    * @return true on success; false otherwise
    */
   bool append(const std::string &key, const std::vector<char> &value)
-    throw(Error)
   {
-    if (key.empty() || value.empty())
-    {
-      throw(Error("the key or value supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_append(&memc,
-                                          key.c_str(),
-                                          key.length(),
-                                          &value[0],
-                                          value.size(),
-                                          0, 0);
+                                            key.c_str(),
+                                            key.length(),
+                                            &value[0],
+                                            value.size(),
+                                            0, 0);
     return (rc == MEMCACHED_SUCCESS);
   }
 
@@ -729,22 +650,15 @@ public:
   bool appendByKey(const std::string &master_key,
                    const std::string &key,
                    const std::vector<char> &value)
-    throw(Error)
   {
-    if (master_key.empty() ||
-        key.empty() ||
-        value.empty())
-    {
-      throw(Error("the master key or key supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_append_by_key(&memc,
-                                                 master_key.c_str(),
-                                                 master_key.length(),
-                                                 key.c_str(),
-                                                 key.length(),
-                                                 &value[0],
-                                                 value.size(),
-                                                 0, 0);
+                                                   master_key.c_str(),
+                                                   master_key.length(),
+                                                   key.c_str(),
+                                                   key.length(),
+                                                   &value[0],
+                                                   value.size(),
+                                                   0, 0);
     return (rc == MEMCACHED_SUCCESS);
   }
 
@@ -758,12 +672,8 @@ public:
    */
   bool cas(const std::string &key,
            const std::vector<char> &value,
-           uint64_t cas_arg) throw(Error)
+           uint64_t cas_arg)
   {
-    if (key.empty() || value.empty())
-    {
-      throw(Error("the key or value supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_cas(&memc, key.c_str(), key.length(),
                                        &value[0], value.size(),
                                        0, 0, cas_arg);
@@ -783,14 +693,8 @@ public:
   bool casByKey(const std::string &master_key,
                 const std::string &key,
                 const std::vector<char> &value,
-                uint64_t cas_arg) throw(Error)
+                uint64_t cas_arg)
   {
-    if (master_key.empty() ||
-        key.empty() ||
-        value.empty())
-    {
-      throw(Error("the master key, key or value supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_cas_by_key(&memc,
                                               master_key.c_str(),
                                               master_key.length(),
@@ -808,12 +712,8 @@ public:
    * @param[in] key key of object to delete
    * @return true on success; false otherwise
    */
-  bool remove(const std::string &key) throw(Error)
+  bool remove(const std::string &key)
   {
-    if (key.empty())
-    {
-      throw(Error("the key supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_delete(&memc, key.c_str(), key.length(), 0);
     return (rc == MEMCACHED_SUCCESS);
   }
@@ -825,13 +725,8 @@ public:
    * @param[in] expiration time to delete the object after
    * @return true on success; false otherwise
    */
-  bool remove(const std::string &key,
-              time_t expiration) throw(Error)
+  bool remove(const std::string &key, time_t expiration)
   {
-    if (key.empty())
-    {
-      throw(Error("the key supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_delete(&memc,
                                           key.c_str(),
                                           key.length(),
@@ -847,12 +742,8 @@ public:
    * @return true on success; false otherwise
    */
   bool removeByKey(const std::string &master_key,
-                   const std::string &key) throw(Error)
+                   const std::string &key)
   {
-    if (master_key.empty() || key.empty())
-    {
-      throw(Error("the master key or key supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_delete_by_key(&memc,
                                                  master_key.c_str(),
                                                  master_key.length(),
@@ -872,12 +763,8 @@ public:
    */
   bool removeByKey(const std::string &master_key,
                    const std::string &key,
-                   time_t expiration) throw(Error)
+                   time_t expiration)
   {
-    if (master_key.empty() || key.empty())
-    {
-      throw(Error("the master key or key supplied is empty!", false));
-    }
     memcached_return_t rc= memcached_delete_by_key(&memc,
                                                  master_key.c_str(),
                                                  master_key.length(),
@@ -900,27 +787,6 @@ public:
     return (rc == MEMCACHED_SUCCESS);
   }
 
-  /**
-   * Callback function for result sets. It passes the result
-   * sets to the list of functions provided.
-   *
-   * @param[in] callback list of callback functions
-   * @param[in] context pointer to memory reference that is
-   *                    supplied to the calling function
-   * @param[in] num_of_callbacks number of callback functions
-   * @return true on success; false otherwise
-   */
-  bool fetchExecute(memcached_execute_fn *callback,
-                    void *context,
-                    uint32_t num_of_callbacks)
-  {
-    memcached_return_t rc= memcached_fetch_execute(&memc,
-                                                 callback,
-                                                 context,
-                                                 num_of_callbacks);
-    return (rc == MEMCACHED_SUCCESS);
-  }
-
   /**
    * Get the library version string.
    * @return std::string containing a copy of the library version string.
@@ -996,5 +862,3 @@ private:
 };
 
 }
-
-#endif /* LIBMEMCACHEDPP_H */
index 4509bbcbb487efd292dcfcb6563839fb10be9652..7a253ae7d616e80309507afc0834beb092290cd9 100644 (file)
@@ -218,12 +218,13 @@ extern "C"
     /**
      * Definition of a request-packet containing no extras
      */
-    typedef union {
+    union protocol_binary_request_no_extras {
         struct {
             protocol_binary_request_header header;
         } message;
         uint8_t bytes[sizeof(protocol_binary_request_header)];
-    } protocol_binary_request_no_extras;
+    };
+    typedef union protocol_binary_request_no_extras protocol_binary_request_no_extras;
 
     /**
      * Definition of a response-packet containing no extras
index bbca66c855e23600646de64c627a585c8f8b5e39..226284d960ded8664d1105959a676f2f63a7a27a 100644 (file)
@@ -90,7 +90,7 @@ public:
 
   const char *set_hostname(const char *str, size_t size)
   {
-    size_t copy_length= std::min((size_t)NI_MAXHOST, size);
+    size_t copy_length= (size_t)NI_MAXHOST > size ? size : (size_t)NI_MAXHOST;
     memcpy(_hostname, str, copy_length);
     _hostname[copy_length]= 0;
 
diff --git a/libmemcached/parse.c b/libmemcached/parse.c
deleted file mode 100644 (file)
index 85860ef..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/* 
-  I debated about putting this in the client library since it does an 
-  action I don't really believe belongs in the library.
-
-  Frankly its too damn useful not to be here though.
-*/
-
-#include "common.h"
-
-memcached_server_list_st memcached_servers_parse(const char *server_strings)
-{
-  char *string;
-  const char *begin_ptr;
-  const char *end_ptr;
-  memcached_server_st *servers= NULL;
-  memcached_return_t rc;
-
-  WATCHPOINT_ASSERT(server_strings);
-
-  end_ptr= server_strings + strlen(server_strings);
-
-  for (begin_ptr= server_strings, string= index(server_strings, ','); 
-       begin_ptr != end_ptr; 
-       string= index(begin_ptr, ','))
-  {
-    char buffer[HUGE_STRING_LEN];
-    char *ptr, *ptr2;
-    uint32_t weight= 0;
-
-    if (string)
-    {
-      memcpy(buffer, begin_ptr, (size_t) (string - begin_ptr));
-      buffer[(unsigned int)(string - begin_ptr)]= 0;
-      begin_ptr= string+1;
-    }
-    else
-    {
-      size_t length= strlen(begin_ptr);
-      memcpy(buffer, begin_ptr, length);
-      buffer[length]= 0;
-      begin_ptr= end_ptr;
-    }
-
-    ptr= index(buffer, ':');
-
-    in_port_t port= 0;
-    if (ptr)
-    {
-      ptr[0]= 0;
-
-      ptr++;
-
-      port= (in_port_t) strtoul(ptr, (char **)NULL, 10);
-
-      ptr2= index(ptr, ' ');
-      if (! ptr2)
-        ptr2= index(ptr, ':');
-
-      if (ptr2)
-      {
-        ptr2++;
-        weight = (uint32_t) strtoul(ptr2, (char **)NULL, 10);
-      }
-    }
-
-    servers= memcached_server_list_append_with_weight(servers, buffer, port, weight, &rc);
-
-    if (isspace(*begin_ptr))
-      begin_ptr++;
-  }
-
-  return servers;
-}
diff --git a/libmemcached/parse.cc b/libmemcached/parse.cc
new file mode 100644 (file)
index 0000000..3284a4f
--- /dev/null
@@ -0,0 +1,110 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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.
+ *
+ */
+
+/* 
+  I debated about putting this in the client library since it does an 
+  action I don't really believe belongs in the library.
+
+  Frankly its too damn useful not to be here though.
+*/
+
+#include <libmemcached/common.h>
+
+memcached_server_list_st memcached_servers_parse(const char *server_strings)
+{
+  char *string;
+  const char *begin_ptr;
+  const char *end_ptr;
+  memcached_server_st *servers= NULL;
+  memcached_return_t rc;
+
+  WATCHPOINT_ASSERT(server_strings);
+
+  end_ptr= server_strings + strlen(server_strings);
+
+  for (begin_ptr= server_strings, string= (char *)index(server_strings, ','); 
+       begin_ptr != end_ptr; 
+       string= (char *)index(begin_ptr, ','))
+  {
+    char buffer[HUGE_STRING_LEN];
+    char *ptr, *ptr2;
+    uint32_t weight= 0;
+
+    if (string)
+    {
+      memcpy(buffer, begin_ptr, (size_t) (string - begin_ptr));
+      buffer[(unsigned int)(string - begin_ptr)]= 0;
+      begin_ptr= string+1;
+    }
+    else
+    {
+      size_t length= strlen(begin_ptr);
+      memcpy(buffer, begin_ptr, length);
+      buffer[length]= 0;
+      begin_ptr= end_ptr;
+    }
+
+    ptr= index(buffer, ':');
+
+    in_port_t port= 0;
+    if (ptr)
+    {
+      ptr[0]= 0;
+
+      ptr++;
+
+      port= (in_port_t) strtoul(ptr, (char **)NULL, 10);
+
+      ptr2= index(ptr, ' ');
+      if (! ptr2)
+        ptr2= index(ptr, ':');
+
+      if (ptr2)
+      {
+        ptr2++;
+        weight = (uint32_t) strtoul(ptr2, (char **)NULL, 10);
+      }
+    }
+
+    servers= memcached_server_list_append_with_weight(servers, buffer, port, weight, &rc);
+
+    if (isspace(*begin_ptr))
+      begin_ptr++;
+  }
+
+  return servers;
+}
index 465b73969766432963007dfabe7ea9e4e42b2c43..5e7307ae7cdcdbd50fc2fdfd4ab8f6326da2407d 100644 (file)
@@ -1,10 +1,48 @@
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/protocol/common.h"
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ *  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 "config.h"
+
+#include <libmemcached/protocol/common.h>
+#include <libmemcached/byteorder.h>
 
 #include <ctype.h>
-#include <string.h>
-#include <strings.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 /**
  * Try to parse a key from the string.
index 02a1a82d4eb253f92473143a07de315c825b50ca..02f8831e9617eccf21bd78471dee5294015e902f 100644 (file)
@@ -1,8 +1,40 @@
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#ifndef LIBMEMCACHED_PROTOCOL_ASCII_HANDLER_H
-#define LIBMEMCACHED_PROTOCOL_ASCII_HANDLER_H
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ *  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.
+ *
+ */
+
+#pragma once
 
 LIBMEMCACHED_LOCAL
 memcached_protocol_event_t memcached_ascii_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr);
-
-#endif
index a9e4ce95890915f0cc067c7004d8ac9944afb7a5..93fb316222276bfc859c196b0da20194492e2e59 100644 (file)
@@ -1,5 +1,41 @@
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/protocol/common.h"
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ *  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/protocol/common.h>
+#include <libmemcached/byteorder.h>
 
 #include <stdlib.h>
 #include <sys/types.h>
index a21165b2a23a534685bdce50ef72d45a44dca40d..d5a74e78c5e22d09bf8f5724ae02c927ef4f6c9d 100644 (file)
@@ -1,6 +1,40 @@
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#ifndef LIBMEMCACHED_PROTOCOL_BINARY_HANDLER_H
-#define LIBMEMCACHED_PROTOCOL_BINARY_HANDLER_H
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ *  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.
+ *
+ */
+
+#pragma once
 
 LIBMEMCACHED_LOCAL
 bool memcached_binary_protocol_pedantic_check_request(const protocol_binary_request_header *request);
@@ -11,5 +45,3 @@ bool memcached_binary_protocol_pedantic_check_response(const protocol_binary_req
 
 LIBMEMCACHED_LOCAL
 memcached_protocol_event_t memcached_binary_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr);
-
-#endif
index 185aef0b5c7f04d69835ac4a007a81c906b60dac..808a608609f1b18c9f0a43178dcd289561f878fc 100644 (file)
@@ -1,6 +1,40 @@
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#ifndef LIBMEMCACHED_PROTOCOL_COMMON_H
-#define LIBMEMCACHED_PROTOCOL_COMMON_H
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *
+ *  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.
+ *
+ */
+
+#pragma once
 
 #include "config.h"
 #if !defined(__cplusplus)
@@ -8,12 +42,7 @@
 #endif
 #include <assert.h>
 
-/* Define this here, which will turn on the visibilty controls while we're
- * building libmemcached.
- */
-#define BUILDING_LIBMEMCACHED 1
-
-#include <libmemcached/byteorder.h>
+#include <libmemcached/visibility.h>
 #include <libmemcached/protocol_handler.h>
 #include <libmemcached/protocol/cache.h>
 
@@ -132,5 +161,3 @@ struct memcached_protocol_client_st {
 
 #include "ascii_handler.h"
 #include "binary_handler.h"
-
-#endif
diff --git a/libmemcached/protocol/include.am b/libmemcached/protocol/include.am
new file mode 100644 (file)
index 0000000..9c4c1bc
--- /dev/null
@@ -0,0 +1,26 @@
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+
+
+lib_LTLIBRARIES+= libmemcached/libmemcachedprotocol.la
+libmemcached_libmemcachedprotocol_la_SOURCES=  \
+                                              libmemcached/byteorder.cc \
+                                              libmemcached/protocol/ascii_handler.c \
+                                              libmemcached/protocol/binary_handler.c \
+                                              libmemcached/protocol/cache.c \
+                                              libmemcached/protocol/pedantic.c \
+                                              libmemcached/protocol/protocol_handler.c
+
+libmemcached_libmemcachedprotocol_la_CFLAGS= \
+                                            ${AM_CFLAGS} \
+                                            ${NO_CONVERSION} \
+                                            ${PTHREAD_CFLAGS} \
+                                            -DBUILDING_LIBMEMCACHED
+
+libmemcached_libmemcachedprotocol_la_CXXFLAGS= \
+                                              ${AM_CXXFLAGS} \
+                                              ${PTHREAD_CFLAGS} \
+                                              -DBUILDING_LIBMEMCACHED
+
+libmemcached_libmemcachedprotocol_la_LDFLAGS= ${AM_LDFLAGS} ${PTHREAD_LIBS} -version-info ${MEMCACHED_PROTOCAL_LIBRARY_VERSION}
diff --git a/libmemcached/purge.c b/libmemcached/purge.c
deleted file mode 100644 (file)
index 07cd135..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#include "common.h"
-
-memcached_return_t memcached_purge(memcached_server_write_instance_st ptr)
-{
-  uint32_t x;
-  memcached_return_t ret= MEMCACHED_SUCCESS;
-  memcached_st *root= (memcached_st *)ptr->root;
-
-  if (memcached_is_purging(ptr->root) || /* already purging */
-      (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark &&
-       ptr->io_bytes_sent < ptr->root->io_bytes_watermark) ||
-      (ptr->io_bytes_sent >= ptr->root->io_bytes_watermark &&
-       memcached_server_response_count(ptr) < 2))
-  {
-    return MEMCACHED_SUCCESS;
-  }
-
-  /* memcached_io_write and memcached_response may call memcached_purge
-    so we need to be able stop any recursion.. */
-  memcached_set_purging(root, true);
-
-  WATCHPOINT_ASSERT(ptr->fd != -1);
-  /* Force a flush of the buffer to ensure that we don't have the n-1 pending
-    requests buffered up.. */
-  if (memcached_io_write(ptr, NULL, 0, true) == -1)
-  {
-    memcached_set_purging(root, true);
-
-    return MEMCACHED_WRITE_FAILURE;
-  }
-  WATCHPOINT_ASSERT(ptr->fd != -1);
-
-  uint32_t no_msg= memcached_server_response_count(ptr) - 1;
-  if (no_msg > 0)
-  {
-    memcached_result_st result;
-    memcached_result_st *result_ptr;
-    char buffer[SMALL_STRING_LEN];
-
-    /*
-     * We need to increase the timeout, because we might be waiting for
-     * data to be sent from the server (the commands was in the output buffer
-     * and just flushed
-   */
-    const int32_t timeo= ptr->root->poll_timeout;
-    root->poll_timeout= 2000;
-
-    result_ptr= memcached_result_create(root, &result);
-    WATCHPOINT_ASSERT(result_ptr);
-
-    for (x= 0; x < no_msg; x++)
-    {
-      memcached_result_reset(result_ptr);
-      memcached_return_t rc= memcached_read_one_response(ptr, buffer,
-                                                         sizeof (buffer),
-                                                         result_ptr);
-      /*
-       * Purge doesn't care for what kind of command results that is received.
-       * The only kind of errors I care about if is I'm out of sync with the
-       * protocol or have problems reading data from the network..
-     */
-      if (rc== MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_UNKNOWN_READ_FAILURE)
-      {
-        WATCHPOINT_ERROR(rc);
-        ret = rc;
-        memcached_io_reset(ptr);
-      }
-
-      if (ptr->root->callbacks != NULL)
-      {
-        memcached_callback_st cb = *ptr->root->callbacks;
-        if (rc == MEMCACHED_SUCCESS)
-        {
-          for (uint32_t y= 0; y < cb.number_of_callback; y++)
-          {
-            rc = (*cb.callback[y])(ptr->root, result_ptr, cb.context);
-            if (rc != MEMCACHED_SUCCESS)
-              break;
-          }
-        }
-      }
-    }
-
-    memcached_result_free(result_ptr);
-    root->poll_timeout= timeo;
-  }
-  memcached_set_purging(root, false);
-
-  return ret;
-}
diff --git a/libmemcached/purge.cc b/libmemcached/purge.cc
new file mode 100644 (file)
index 0000000..07cd135
--- /dev/null
@@ -0,0 +1,90 @@
+#include "common.h"
+
+memcached_return_t memcached_purge(memcached_server_write_instance_st ptr)
+{
+  uint32_t x;
+  memcached_return_t ret= MEMCACHED_SUCCESS;
+  memcached_st *root= (memcached_st *)ptr->root;
+
+  if (memcached_is_purging(ptr->root) || /* already purging */
+      (memcached_server_response_count(ptr) < ptr->root->io_msg_watermark &&
+       ptr->io_bytes_sent < ptr->root->io_bytes_watermark) ||
+      (ptr->io_bytes_sent >= ptr->root->io_bytes_watermark &&
+       memcached_server_response_count(ptr) < 2))
+  {
+    return MEMCACHED_SUCCESS;
+  }
+
+  /* memcached_io_write and memcached_response may call memcached_purge
+    so we need to be able stop any recursion.. */
+  memcached_set_purging(root, true);
+
+  WATCHPOINT_ASSERT(ptr->fd != -1);
+  /* Force a flush of the buffer to ensure that we don't have the n-1 pending
+    requests buffered up.. */
+  if (memcached_io_write(ptr, NULL, 0, true) == -1)
+  {
+    memcached_set_purging(root, true);
+
+    return MEMCACHED_WRITE_FAILURE;
+  }
+  WATCHPOINT_ASSERT(ptr->fd != -1);
+
+  uint32_t no_msg= memcached_server_response_count(ptr) - 1;
+  if (no_msg > 0)
+  {
+    memcached_result_st result;
+    memcached_result_st *result_ptr;
+    char buffer[SMALL_STRING_LEN];
+
+    /*
+     * We need to increase the timeout, because we might be waiting for
+     * data to be sent from the server (the commands was in the output buffer
+     * and just flushed
+   */
+    const int32_t timeo= ptr->root->poll_timeout;
+    root->poll_timeout= 2000;
+
+    result_ptr= memcached_result_create(root, &result);
+    WATCHPOINT_ASSERT(result_ptr);
+
+    for (x= 0; x < no_msg; x++)
+    {
+      memcached_result_reset(result_ptr);
+      memcached_return_t rc= memcached_read_one_response(ptr, buffer,
+                                                         sizeof (buffer),
+                                                         result_ptr);
+      /*
+       * Purge doesn't care for what kind of command results that is received.
+       * The only kind of errors I care about if is I'm out of sync with the
+       * protocol or have problems reading data from the network..
+     */
+      if (rc== MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_UNKNOWN_READ_FAILURE)
+      {
+        WATCHPOINT_ERROR(rc);
+        ret = rc;
+        memcached_io_reset(ptr);
+      }
+
+      if (ptr->root->callbacks != NULL)
+      {
+        memcached_callback_st cb = *ptr->root->callbacks;
+        if (rc == MEMCACHED_SUCCESS)
+        {
+          for (uint32_t y= 0; y < cb.number_of_callback; y++)
+          {
+            rc = (*cb.callback[y])(ptr->root, result_ptr, cb.context);
+            if (rc != MEMCACHED_SUCCESS)
+              break;
+          }
+        }
+      }
+    }
+
+    memcached_result_free(result_ptr);
+    root->poll_timeout= timeo;
+  }
+  memcached_set_purging(root, false);
+
+  return ret;
+}
diff --git a/libmemcached/quit.c b/libmemcached/quit.c
deleted file mode 100644 (file)
index 6d72906..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-#include "common.h"
-
-/*
-  This closes all connections (forces flush of input as well).
-
-  Maybe add a host specific, or key specific version?
-
-  The reason we send "quit" is that in case we have buffered IO, this
-  will force data to be completed.
-*/
-
-void memcached_quit_server(memcached_server_st *ptr, bool io_death)
-{
-  if (ptr->fd != INVALID_SOCKET)
-  {
-    if (io_death == false && ptr->type != MEMCACHED_CONNECTION_UDP && ptr->options.is_shutting_down == false)
-    {
-      memcached_return_t rc;
-      char buffer[MEMCACHED_MAX_BUFFER];
-
-      ptr->options.is_shutting_down= true;
-
-      if (ptr->root->flags.binary_protocol)
-      {
-        protocol_binary_request_quit request = {.bytes= {0}};
-        request.message.header.request.magic = PROTOCOL_BINARY_REQ;
-        request.message.header.request.opcode = PROTOCOL_BINARY_CMD_QUIT;
-        request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
-        rc= memcached_do(ptr, request.bytes, sizeof(request.bytes), true);
-      }
-      else
-      {
-        rc= memcached_do(ptr, "quit\r\n", sizeof("quit\r\n") -1, true);
-      }
-
-      WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_FETCH_NOTFINISHED);
-      (void)rc; // Shut up ICC
-
-      /* read until socket is closed, or there is an error
-       * closing the socket before all data is read
-       * results in server throwing away all data which is
-       * not read
-       *
-       * In .40 we began to only do this if we had been doing buffered
-       * requests of had replication enabled.
-       */
-      if (ptr->root->flags.buffer_requests || ptr->root->number_of_replicas)
-      {
-        ssize_t nread;
-        while (memcached_io_read(ptr, buffer, sizeof(buffer)/sizeof(*buffer),
-                                 &nread) == MEMCACHED_SUCCESS);
-      }
-
-
-      /*
-       * memcached_io_read may call memcached_quit_server with io_death if
-       * it encounters problems, but we don't care about those occurences.
-       * The intention of that loop is to drain the data sent from the
-       * server to ensure that the server processed all of the data we
-       * sent to the server.
-       */
-      ptr->server_failure_counter= 0;
-    }
-    memcached_io_close(ptr);
-  }
-
-  ptr->fd= INVALID_SOCKET;
-  ptr->io_bytes_sent= 0;
-  ptr->write_buffer_offset= (size_t) ((ptr->type == MEMCACHED_CONNECTION_UDP) ? UDP_DATAGRAM_HEADER_LENGTH : 0);
-  ptr->read_buffer_length= 0;
-  ptr->read_ptr= ptr->read_buffer;
-  ptr->options.is_shutting_down= false;
-  memcached_server_response_reset(ptr);
-
-  // We reset the version so that if we end up talking to a different server
-  // we don't have stale server version information.
-  ptr->major_version= ptr->minor_version= ptr->micro_version= UINT8_MAX;
-
-  if (io_death)
-  {
-    ptr->server_failure_counter++;
-    set_last_disconnected_host(ptr);
-  }
-}
-
-void send_quit(memcached_st *ptr)
-{
-  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
-  {
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(ptr, x);
-
-    memcached_quit_server(instance, false);
-  }
-}
-
-void memcached_quit(memcached_st *ptr)
-{
-  if (initialize_query(ptr) != MEMCACHED_SUCCESS)
-  {
-    return;
-  }
-
-  send_quit(ptr);
-}
diff --git a/libmemcached/quit.cc b/libmemcached/quit.cc
new file mode 100644 (file)
index 0000000..2efe909
--- /dev/null
@@ -0,0 +1,142 @@
+/*  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>
+
+/*
+  This closes all connections (forces flush of input as well).
+
+  Maybe add a host specific, or key specific version?
+
+  The reason we send "quit" is that in case we have buffered IO, this
+  will force data to be completed.
+*/
+
+void memcached_quit_server(memcached_server_st *ptr, bool io_death)
+{
+  if (ptr->fd != INVALID_SOCKET)
+  {
+    if (io_death == false && ptr->type != MEMCACHED_CONNECTION_UDP && ptr->options.is_shutting_down == false)
+    {
+      memcached_return_t rc;
+      char buffer[MEMCACHED_MAX_BUFFER];
+
+      ptr->options.is_shutting_down= true;
+
+      if (ptr->root->flags.binary_protocol)
+      {
+        protocol_binary_request_quit request= {}; // = {.bytes= {0}};
+        request.message.header.request.magic = PROTOCOL_BINARY_REQ;
+        request.message.header.request.opcode = PROTOCOL_BINARY_CMD_QUIT;
+        request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
+        rc= memcached_do(ptr, request.bytes, sizeof(request.bytes), true);
+      }
+      else
+      {
+        rc= memcached_do(ptr, "quit\r\n", sizeof("quit\r\n") -1, true);
+      }
+
+      WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_FETCH_NOTFINISHED);
+      (void)rc; // Shut up ICC
+
+      /* read until socket is closed, or there is an error
+       * closing the socket before all data is read
+       * results in server throwing away all data which is
+       * not read
+       *
+       * In .40 we began to only do this if we had been doing buffered
+       * requests of had replication enabled.
+       */
+      if (ptr->root->flags.buffer_requests || ptr->root->number_of_replicas)
+      {
+        ssize_t nread;
+        while (memcached_io_read(ptr, buffer, sizeof(buffer)/sizeof(*buffer),
+                                 &nread) == MEMCACHED_SUCCESS);
+      }
+
+
+      /*
+       * memcached_io_read may call memcached_quit_server with io_death if
+       * it encounters problems, but we don't care about those occurences.
+       * The intention of that loop is to drain the data sent from the
+       * server to ensure that the server processed all of the data we
+       * sent to the server.
+       */
+      ptr->server_failure_counter= 0;
+    }
+    memcached_io_close(ptr);
+  }
+
+  ptr->fd= INVALID_SOCKET;
+  ptr->io_bytes_sent= 0;
+  ptr->write_buffer_offset= (size_t) ((ptr->type == MEMCACHED_CONNECTION_UDP) ? UDP_DATAGRAM_HEADER_LENGTH : 0);
+  ptr->read_buffer_length= 0;
+  ptr->read_ptr= ptr->read_buffer;
+  ptr->options.is_shutting_down= false;
+  memcached_server_response_reset(ptr);
+
+  // We reset the version so that if we end up talking to a different server
+  // we don't have stale server version information.
+  ptr->major_version= ptr->minor_version= ptr->micro_version= UINT8_MAX;
+
+  if (io_death)
+  {
+    ptr->server_failure_counter++;
+    set_last_disconnected_host(ptr);
+  }
+}
+
+void send_quit(memcached_st *ptr)
+{
+  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    memcached_quit_server(instance, false);
+  }
+}
+
+void memcached_quit(memcached_st *ptr)
+{
+  if (initialize_query(ptr) != MEMCACHED_SUCCESS)
+  {
+    return;
+  }
+
+  send_quit(ptr);
+}
index e640020a3eb7a794490878db7acd84a10f002459..0338eaf03a200d610b9a59340fe6b1a9ff3e73f7 100644 (file)
@@ -1,16 +1,41 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
  *
- * Summary: returns a human readable string for the error message
+ *  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.
  *
  */
 
-#ifndef __LIBMEMCACHED_QUIT_H__
-#define __LIBMEMCACHED_QUIT_H__
+#pragma once
 
 #ifdef __cplusplus
 extern "C" {
@@ -28,5 +53,3 @@ void send_quit(memcached_st *ptr);
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __LIBMEMCACHED_QUIT_H__ */
diff --git a/libmemcached/response.c b/libmemcached/response.c
deleted file mode 100644 (file)
index 49825fb..0000000
+++ /dev/null
@@ -1,584 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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: memcached_response() is used to determine the return result from an issued command.
- *
-*/
-
-#include "common.h"
-
-static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr,
-                                                    char *buffer, size_t buffer_length,
-                                                    memcached_result_st *result);
-static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr,
-                                                   char *buffer, size_t buffer_length,
-                                                   memcached_result_st *result);
-
-memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr,
-                                               char *buffer, size_t buffer_length,
-                                               memcached_result_st *result)
-{
-  memcached_server_response_decrement(ptr);
-
-  if (result == NULL)
-  {
-    memcached_st *root= (memcached_st *)ptr->root;
-    result = &root->result;
-  }
-
-  memcached_return_t rc;
-  if (ptr->root->flags.binary_protocol)
-    rc= binary_read_one_response(ptr, buffer, buffer_length, result);
-  else
-    rc= textual_read_one_response(ptr, buffer, buffer_length, result);
-
-  unlikely(rc == MEMCACHED_UNKNOWN_READ_FAILURE ||
-           rc == MEMCACHED_PROTOCOL_ERROR ||
-           rc == MEMCACHED_CLIENT_ERROR ||
-           rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
-    memcached_io_reset(ptr);
-
-  return rc;
-}
-
-memcached_return_t memcached_response(memcached_server_write_instance_st ptr,
-                                      char *buffer, size_t buffer_length,
-                                      memcached_result_st *result)
-{
-  /* We may have old commands in the buffer not set, first purge */
-  if ((ptr->root->flags.no_block) && (memcached_is_processing_input(ptr->root) == false))
-  {
-    (void)memcached_io_write(ptr, NULL, 0, true);
-  }
-
-  /*
-   * The previous implementation purged all pending requests and just
-   * returned the last one. Purge all pending messages to ensure backwards
-   * compatibility.
- */
-  if (ptr->root->flags.binary_protocol == false)
-  {
-    while (memcached_server_response_count(ptr) > 1)
-    {
-      memcached_return_t rc= memcached_read_one_response(ptr, buffer, buffer_length, result);
-
-      unlikely (rc != MEMCACHED_END &&
-                rc != MEMCACHED_STORED &&
-                rc != MEMCACHED_SUCCESS &&
-                rc != MEMCACHED_STAT &&
-                rc != MEMCACHED_DELETED &&
-                rc != MEMCACHED_NOTFOUND &&
-                rc != MEMCACHED_NOTSTORED &&
-                rc != MEMCACHED_DATA_EXISTS)
-        return rc;
-    }
-  }
-
-  return memcached_read_one_response(ptr, buffer, buffer_length, result);
-}
-
-static memcached_return_t textual_value_fetch(memcached_server_write_instance_st ptr,
-                                              char *buffer,
-                                              memcached_result_st *result)
-{
-  memcached_return_t rc= MEMCACHED_SUCCESS;
-  char *string_ptr;
-  char *end_ptr;
-  char *next_ptr;
-  size_t value_length;
-  size_t to_read;
-  char *value_ptr;
-  ssize_t read_length= 0;
-  memcached_return_t rrc;
-
-  if (ptr->root->flags.use_udp)
-    return MEMCACHED_NOT_SUPPORTED;
-
-  WATCHPOINT_ASSERT(ptr->root);
-  end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
-
-  memcached_result_reset(result);
-
-  string_ptr= buffer;
-  string_ptr+= 6; /* "VALUE " */
-
-
-  /* We load the key */
-  {
-    char *key;
-    size_t prefix_length;
-
-    key= result->item_key;
-    result->key_length= 0;
-
-    for (prefix_length= memcached_array_size(ptr->root->prefix_key); !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
-    {
-      if (prefix_length == 0)
-      {
-        *key= *string_ptr;
-        key++;
-        result->key_length++;
-      }
-      else
-        prefix_length--;
-    }
-    result->item_key[result->key_length]= 0;
-  }
-
-  if (end_ptr == string_ptr)
-    goto read_error;
-
-  /* Flags fetch move past space */
-  string_ptr++;
-  if (end_ptr == string_ptr)
-    goto read_error;
-  for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
-  result->item_flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10);
-
-  if (end_ptr == string_ptr)
-    goto read_error;
-
-  /* Length fetch move past space*/
-  string_ptr++;
-  if (end_ptr == string_ptr)
-    goto read_error;
-
-  for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
-  value_length= (size_t)strtoull(next_ptr, &string_ptr, 10);
-
-  if (end_ptr == string_ptr)
-    goto read_error;
-
-  /* Skip spaces */
-  if (*string_ptr == '\r')
-  {
-    /* Skip past the \r\n */
-    string_ptr+= 2;
-  }
-  else
-  {
-    string_ptr++;
-    for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
-    result->item_cas= strtoull(next_ptr, &string_ptr, 10);
-  }
-
-  if (end_ptr < string_ptr)
-    goto read_error;
-
-  /* We add two bytes so that we can walk the \r\n */
-  rc= memcached_string_check(&result->value, value_length+2);
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    value_length= 0;
-    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-  }
-
-  value_ptr= memcached_string_value_mutable(&result->value);
-  /*
-    We read the \r\n into the string since not doing so is more
-    cycles then the waster of memory to do so.
-
-    We are null terminating through, which will most likely make
-    some people lazy about using the return length.
-  */
-  to_read= (value_length) + 2;
-  rrc= memcached_io_read(ptr, value_ptr, to_read, &read_length);
-  if (rrc != MEMCACHED_SUCCESS)
-    return rrc;
-
-  if (read_length != (ssize_t)(value_length + 2))
-  {
-    goto read_error;
-  }
-
-  /* This next bit blows the API, but this is internal....*/
-  {
-    char *char_ptr;
-    char_ptr= memcached_string_value_mutable(&result->value);;
-    char_ptr[value_length]= 0;
-    char_ptr[value_length + 1]= 0;
-    memcached_string_set_length(&result->value, value_length);
-  }
-
-  return MEMCACHED_SUCCESS;
-
-read_error:
-  memcached_io_reset(ptr);
-
-  return MEMCACHED_PARTIAL_READ;
-}
-
-static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr,
-                                                    char *buffer, size_t buffer_length,
-                                                    memcached_result_st *result)
-{
-  memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length);
-  if (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  switch(buffer[0])
-  {
-  case 'V': /* VALUE || VERSION */
-    if (buffer[1] == 'A') /* VALUE */
-    {
-      /* We add back in one because we will need to search for END */
-      memcached_server_response_increment(ptr);
-      return textual_value_fetch(ptr, buffer, result);
-    }
-    else if (buffer[1] == 'E') /* VERSION */
-    {
-      return MEMCACHED_SUCCESS;
-    }
-    else
-    {
-      WATCHPOINT_STRING(buffer);
-      return MEMCACHED_UNKNOWN_READ_FAILURE;
-    }
-  case 'O': /* OK */
-    return MEMCACHED_SUCCESS;
-  case 'S': /* STORED STATS SERVER_ERROR */
-    {
-      if (buffer[2] == 'A') /* STORED STATS */
-      {
-        memcached_server_response_increment(ptr);
-        return MEMCACHED_STAT;
-      }
-      else if (buffer[1] == 'E') /* SERVER_ERROR */
-      {
-        char *rel_ptr;
-        char *startptr= buffer + 13, *endptr= startptr;
-
-        while (*endptr != '\r' && *endptr != '\n') endptr++;
-
-        /*
-          Yes, we could make this "efficent" but to do that we would need
-          to maintain more state for the size of the buffer. Why waste
-          memory in the struct, which is important, for something that
-          rarely should happen?
-        */
-        rel_ptr= (char *)libmemcached_realloc(ptr->root,
-                                              ptr->cached_server_error,
-                                              (size_t) (endptr - startptr + 1));
-
-        if (rel_ptr == NULL)
-        {
-          /* If we happened to have some memory, we just null it since we don't know the size */
-          if (ptr->cached_server_error)
-            ptr->cached_server_error[0]= 0;
-          return MEMCACHED_SERVER_ERROR;
-        }
-        ptr->cached_server_error= rel_ptr;
-
-        memcpy(ptr->cached_server_error, startptr, (size_t) (endptr - startptr));
-        ptr->cached_server_error[endptr - startptr]= 0;
-        return MEMCACHED_SERVER_ERROR;
-      }
-      else if (buffer[1] == 'T')
-        return MEMCACHED_STORED;
-      else
-      {
-        WATCHPOINT_STRING(buffer);
-        return MEMCACHED_UNKNOWN_READ_FAILURE;
-      }
-    }
-  case 'D': /* DELETED */
-    return MEMCACHED_DELETED;
-  case 'N': /* NOT_FOUND */
-    {
-      if (buffer[4] == 'F')
-        return MEMCACHED_NOTFOUND;
-      else if (buffer[4] == 'S')
-        return MEMCACHED_NOTSTORED;
-      else
-      {
-        WATCHPOINT_STRING(buffer);
-        return MEMCACHED_UNKNOWN_READ_FAILURE;
-      }
-    }
-  case 'E': /* PROTOCOL ERROR or END */
-    {
-      if (buffer[1] == 'N')
-        return MEMCACHED_END;
-      else if (buffer[1] == 'R')
-        return MEMCACHED_PROTOCOL_ERROR;
-      else if (buffer[1] == 'X')
-        return MEMCACHED_DATA_EXISTS;
-      else
-      {
-        WATCHPOINT_STRING(buffer);
-        return MEMCACHED_UNKNOWN_READ_FAILURE;
-      }
-
-    }
-  case 'I': /* CLIENT ERROR */
-    /* We add back in one because we will need to search for END */
-    memcached_server_response_increment(ptr);
-    return MEMCACHED_ITEM;
-  case 'C': /* CLIENT ERROR */
-    return MEMCACHED_CLIENT_ERROR;
-  default:
-    {
-      unsigned long long auto_return_value;
-
-      if (sscanf(buffer, "%llu", &auto_return_value) == 1)
-        return MEMCACHED_SUCCESS;
-
-      WATCHPOINT_STRING(buffer);
-      return MEMCACHED_UNKNOWN_READ_FAILURE;
-    }
-  }
-
-  /* NOTREACHED */
-}
-
-static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr,
-                                                   char *buffer, size_t buffer_length,
-                                                   memcached_result_st *result)
-{
-  memcached_return_t rc;
-  protocol_binary_response_header header;
-
-  if ((rc= memcached_safe_read(ptr, &header.bytes, sizeof(header.bytes))) != MEMCACHED_SUCCESS)
-  {
-    WATCHPOINT_ERROR(rc);
-    return rc;
-  }
-
-  if (header.response.magic != PROTOCOL_BINARY_RES)
-  {
-    return MEMCACHED_PROTOCOL_ERROR;
-  }
-
-  /*
-   ** Convert the header to host local endian!
- */
-  header.response.keylen= ntohs(header.response.keylen);
-  header.response.status= ntohs(header.response.status);
-  header.response.bodylen= ntohl(header.response.bodylen);
-  header.response.cas= ntohll(header.response.cas);
-  uint32_t bodylen= header.response.bodylen;
-
-  if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS ||
-      header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE)
-  {
-    switch (header.response.opcode)
-    {
-    case PROTOCOL_BINARY_CMD_GETKQ:
-      /*
-       * We didn't increment the response counter for the GETKQ packet
-       * (only the final NOOP), so we need to increment the counter again.
-       */
-      memcached_server_response_increment(ptr);
-      /* FALLTHROUGH */
-    case PROTOCOL_BINARY_CMD_GETK:
-      {
-        uint16_t keylen= header.response.keylen;
-        memcached_result_reset(result);
-        result->item_cas= header.response.cas;
-
-        if ((rc= memcached_safe_read(ptr, &result->item_flags, sizeof (result->item_flags))) != MEMCACHED_SUCCESS)
-        {
-          WATCHPOINT_ERROR(rc);
-          return MEMCACHED_UNKNOWN_READ_FAILURE;
-        }
-
-        result->item_flags= ntohl(result->item_flags);
-        bodylen -= header.response.extlen;
-
-        result->key_length= keylen;
-        if ((rc= memcached_safe_read(ptr, result->item_key, keylen)) != MEMCACHED_SUCCESS)
-        {
-          WATCHPOINT_ERROR(rc);
-          return MEMCACHED_UNKNOWN_READ_FAILURE;
-        }
-
-        bodylen -= keylen;
-        if (memcached_string_check(&result->value,
-                                   bodylen) != MEMCACHED_SUCCESS)
-          return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-        char *vptr= memcached_string_value_mutable(&result->value);
-        if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS)
-        {
-          WATCHPOINT_ERROR(rc);
-          return MEMCACHED_UNKNOWN_READ_FAILURE;
-        }
-
-        memcached_string_set_length(&result->value, bodylen);
-      }
-      break;
-    case PROTOCOL_BINARY_CMD_INCREMENT:
-    case PROTOCOL_BINARY_CMD_DECREMENT:
-      {
-        if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t))
-          return MEMCACHED_PROTOCOL_ERROR;
-
-        WATCHPOINT_ASSERT(bodylen == buffer_length);
-        uint64_t val;
-        if ((rc= memcached_safe_read(ptr, &val, sizeof(val))) != MEMCACHED_SUCCESS)
-        {
-          WATCHPOINT_ERROR(rc);
-          return MEMCACHED_UNKNOWN_READ_FAILURE;
-        }
-
-        val= ntohll(val);
-        memcpy(buffer, &val, sizeof(val));
-      }
-      break;
-    case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
-    case PROTOCOL_BINARY_CMD_VERSION:
-      {
-        memset(buffer, 0, buffer_length);
-        if (bodylen >= buffer_length)
-        {
-          /* not enough space in buffer.. should not happen... */
-          return MEMCACHED_UNKNOWN_READ_FAILURE;
-        }
-        else if ((rc= memcached_safe_read(ptr, buffer, bodylen)) != MEMCACHED_SUCCESS)
-        {
-          WATCHPOINT_ERROR(rc);
-          return MEMCACHED_UNKNOWN_READ_FAILURE;
-        }
-      }
-      break;
-    case PROTOCOL_BINARY_CMD_FLUSH:
-    case PROTOCOL_BINARY_CMD_QUIT:
-    case PROTOCOL_BINARY_CMD_SET:
-    case PROTOCOL_BINARY_CMD_ADD:
-    case PROTOCOL_BINARY_CMD_REPLACE:
-    case PROTOCOL_BINARY_CMD_APPEND:
-    case PROTOCOL_BINARY_CMD_PREPEND:
-    case PROTOCOL_BINARY_CMD_DELETE:
-      {
-        WATCHPOINT_ASSERT(bodylen == 0);
-        return MEMCACHED_SUCCESS;
-      }
-    case PROTOCOL_BINARY_CMD_NOOP:
-      {
-        WATCHPOINT_ASSERT(bodylen == 0);
-        return MEMCACHED_END;
-      }
-    case PROTOCOL_BINARY_CMD_STAT:
-      {
-        if (bodylen == 0)
-        {
-          return MEMCACHED_END;
-        }
-        else if (bodylen + 1 > buffer_length)
-        {
-          /* not enough space in buffer.. should not happen... */
-          return MEMCACHED_UNKNOWN_READ_FAILURE;
-        }
-        else
-        {
-          size_t keylen= header.response.keylen;
-          memset(buffer, 0, buffer_length);
-          if ((rc= memcached_safe_read(ptr, buffer, keylen)) != MEMCACHED_SUCCESS ||
-              (rc= memcached_safe_read(ptr, buffer + keylen + 1, bodylen - keylen)) != MEMCACHED_SUCCESS)
-          {
-            WATCHPOINT_ERROR(rc);
-            return MEMCACHED_UNKNOWN_READ_FAILURE;
-          }
-        }
-      }
-      break;
-
-    case PROTOCOL_BINARY_CMD_SASL_AUTH:
-    case PROTOCOL_BINARY_CMD_SASL_STEP:
-      {
-        memcached_result_reset(result);
-        result->item_cas= header.response.cas;
-
-        if (memcached_string_check(&result->value,
-                                   bodylen) != MEMCACHED_SUCCESS)
-          return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-        char *vptr= memcached_string_value_mutable(&result->value);
-        if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS)
-        {
-          WATCHPOINT_ERROR(rc);
-          return MEMCACHED_UNKNOWN_READ_FAILURE;
-        }
-
-        memcached_string_set_length(&result->value, bodylen);
-      }
-      break;
-    default:
-      {
-        /* Command not implemented yet! */
-        WATCHPOINT_ASSERT(0);
-        return MEMCACHED_PROTOCOL_ERROR;
-      }
-    }
-  }
-  else if (header.response.bodylen)
-  {
-    /* What should I do with the error message??? just discard it for now */
-    char hole[SMALL_STRING_LEN];
-    while (bodylen > 0)
-    {
-      size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen;
-      if ((rc= memcached_safe_read(ptr, hole, nr)) != MEMCACHED_SUCCESS)
-      {
-        WATCHPOINT_ERROR(rc);
-        return MEMCACHED_UNKNOWN_READ_FAILURE;
-      }
-      bodylen-= (uint32_t) nr;
-    }
-
-    /* This might be an error from one of the quiet commands.. if
-     * so, just throw it away and get the next one. What about creating
-     * a callback to the user with the error information?
-   */
-    switch (header.response.opcode)
-    {
-    case PROTOCOL_BINARY_CMD_SETQ:
-    case PROTOCOL_BINARY_CMD_ADDQ:
-    case PROTOCOL_BINARY_CMD_REPLACEQ:
-    case PROTOCOL_BINARY_CMD_APPENDQ:
-    case PROTOCOL_BINARY_CMD_PREPENDQ:
-      return binary_read_one_response(ptr, buffer, buffer_length, result);
-    default:
-      break;
-    }
-  }
-
-  rc= MEMCACHED_SUCCESS;
-  unlikely(header.response.status != 0)
-    switch (header.response.status)
-    {
-    case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
-      rc= MEMCACHED_NOTFOUND;
-      break;
-    case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
-      rc= MEMCACHED_DATA_EXISTS;
-      break;
-    case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
-      rc= MEMCACHED_NOTSTORED;
-      break;
-    case PROTOCOL_BINARY_RESPONSE_E2BIG:
-      rc= MEMCACHED_E2BIG;
-      break;
-    case PROTOCOL_BINARY_RESPONSE_ENOMEM:
-      rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-      break;
-    case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE:
-      rc= MEMCACHED_AUTH_CONTINUE;
-      break;
-    case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR:
-      rc= MEMCACHED_AUTH_FAILURE;
-      break;
-    case PROTOCOL_BINARY_RESPONSE_EINVAL:
-    case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
-    default:
-      /* @todo fix the error mappings */
-      rc= MEMCACHED_PROTOCOL_ERROR;
-      break;
-    }
-
-  return rc;
-}
diff --git a/libmemcached/response.cc b/libmemcached/response.cc
new file mode 100644 (file)
index 0000000..572aef5
--- /dev/null
@@ -0,0 +1,610 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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>
+
+static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr,
+                                                    char *buffer, size_t buffer_length,
+                                                    memcached_result_st *result);
+static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr,
+                                                   char *buffer, size_t buffer_length,
+                                                   memcached_result_st *result);
+
+memcached_return_t memcached_read_one_response(memcached_server_write_instance_st ptr,
+                                               char *buffer, size_t buffer_length,
+                                               memcached_result_st *result)
+{
+  memcached_server_response_decrement(ptr);
+
+  if (result == NULL)
+  {
+    memcached_st *root= (memcached_st *)ptr->root;
+    result = &root->result;
+  }
+
+  memcached_return_t rc;
+  if (ptr->root->flags.binary_protocol)
+    rc= binary_read_one_response(ptr, buffer, buffer_length, result);
+  else
+    rc= textual_read_one_response(ptr, buffer, buffer_length, result);
+
+  unlikely(rc == MEMCACHED_UNKNOWN_READ_FAILURE ||
+           rc == MEMCACHED_PROTOCOL_ERROR ||
+           rc == MEMCACHED_CLIENT_ERROR ||
+           rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
+    memcached_io_reset(ptr);
+
+  return rc;
+}
+
+memcached_return_t memcached_response(memcached_server_write_instance_st ptr,
+                                      char *buffer, size_t buffer_length,
+                                      memcached_result_st *result)
+{
+  /* We may have old commands in the buffer not set, first purge */
+  if ((ptr->root->flags.no_block) && (memcached_is_processing_input(ptr->root) == false))
+  {
+    (void)memcached_io_write(ptr, NULL, 0, true);
+  }
+
+  /*
+   * The previous implementation purged all pending requests and just
+   * returned the last one. Purge all pending messages to ensure backwards
+   * compatibility.
+ */
+  if (ptr->root->flags.binary_protocol == false)
+  {
+    while (memcached_server_response_count(ptr) > 1)
+    {
+      memcached_return_t rc= memcached_read_one_response(ptr, buffer, buffer_length, result);
+
+      unlikely (rc != MEMCACHED_END &&
+                rc != MEMCACHED_STORED &&
+                rc != MEMCACHED_SUCCESS &&
+                rc != MEMCACHED_STAT &&
+                rc != MEMCACHED_DELETED &&
+                rc != MEMCACHED_NOTFOUND &&
+                rc != MEMCACHED_NOTSTORED &&
+                rc != MEMCACHED_DATA_EXISTS)
+        return rc;
+    }
+  }
+
+  return memcached_read_one_response(ptr, buffer, buffer_length, result);
+}
+
+static memcached_return_t textual_value_fetch(memcached_server_write_instance_st ptr,
+                                              char *buffer,
+                                              memcached_result_st *result)
+{
+  memcached_return_t rc= MEMCACHED_SUCCESS;
+  char *string_ptr;
+  char *end_ptr;
+  char *next_ptr;
+  size_t value_length;
+  size_t to_read;
+  char *value_ptr;
+  ssize_t read_length= 0;
+  memcached_return_t rrc;
+
+  if (ptr->root->flags.use_udp)
+    return MEMCACHED_NOT_SUPPORTED;
+
+  WATCHPOINT_ASSERT(ptr->root);
+  end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
+
+  memcached_result_reset(result);
+
+  string_ptr= buffer;
+  string_ptr+= 6; /* "VALUE " */
+
+
+  /* We load the key */
+  {
+    char *key;
+    size_t prefix_length;
+
+    key= result->item_key;
+    result->key_length= 0;
+
+    for (prefix_length= memcached_array_size(ptr->root->prefix_key); !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
+    {
+      if (prefix_length == 0)
+      {
+        *key= *string_ptr;
+        key++;
+        result->key_length++;
+      }
+      else
+        prefix_length--;
+    }
+    result->item_key[result->key_length]= 0;
+  }
+
+  if (end_ptr == string_ptr)
+    goto read_error;
+
+  /* Flags fetch move past space */
+  string_ptr++;
+  if (end_ptr == string_ptr)
+    goto read_error;
+  for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
+  result->item_flags= (uint32_t) strtoul(next_ptr, &string_ptr, 10);
+
+  if (end_ptr == string_ptr)
+    goto read_error;
+
+  /* Length fetch move past space*/
+  string_ptr++;
+  if (end_ptr == string_ptr)
+    goto read_error;
+
+  for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
+  value_length= (size_t)strtoull(next_ptr, &string_ptr, 10);
+
+  if (end_ptr == string_ptr)
+    goto read_error;
+
+  /* Skip spaces */
+  if (*string_ptr == '\r')
+  {
+    /* Skip past the \r\n */
+    string_ptr+= 2;
+  }
+  else
+  {
+    string_ptr++;
+    for (next_ptr= string_ptr; isdigit(*string_ptr); string_ptr++);
+    result->item_cas= strtoull(next_ptr, &string_ptr, 10);
+  }
+
+  if (end_ptr < string_ptr)
+    goto read_error;
+
+  /* We add two bytes so that we can walk the \r\n */
+  rc= memcached_string_check(&result->value, value_length+2);
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    value_length= 0;
+    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+  }
+
+  value_ptr= memcached_string_value_mutable(&result->value);
+  /*
+    We read the \r\n into the string since not doing so is more
+    cycles then the waster of memory to do so.
+
+    We are null terminating through, which will most likely make
+    some people lazy about using the return length.
+  */
+  to_read= (value_length) + 2;
+  rrc= memcached_io_read(ptr, value_ptr, to_read, &read_length);
+  if (rrc != MEMCACHED_SUCCESS)
+    return rrc;
+
+  if (read_length != (ssize_t)(value_length + 2))
+  {
+    goto read_error;
+  }
+
+  /* This next bit blows the API, but this is internal....*/
+  {
+    char *char_ptr;
+    char_ptr= memcached_string_value_mutable(&result->value);;
+    char_ptr[value_length]= 0;
+    char_ptr[value_length + 1]= 0;
+    memcached_string_set_length(&result->value, value_length);
+  }
+
+  return MEMCACHED_SUCCESS;
+
+read_error:
+  memcached_io_reset(ptr);
+
+  return MEMCACHED_PARTIAL_READ;
+}
+
+static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr,
+                                                    char *buffer, size_t buffer_length,
+                                                    memcached_result_st *result)
+{
+  memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length);
+  if (rc != MEMCACHED_SUCCESS)
+    return rc;
+
+  switch(buffer[0])
+  {
+  case 'V': /* VALUE || VERSION */
+    if (buffer[1] == 'A') /* VALUE */
+    {
+      /* We add back in one because we will need to search for END */
+      memcached_server_response_increment(ptr);
+      return textual_value_fetch(ptr, buffer, result);
+    }
+    else if (buffer[1] == 'E') /* VERSION */
+    {
+      return MEMCACHED_SUCCESS;
+    }
+    else
+    {
+      WATCHPOINT_STRING(buffer);
+      return MEMCACHED_UNKNOWN_READ_FAILURE;
+    }
+  case 'O': /* OK */
+    return MEMCACHED_SUCCESS;
+  case 'S': /* STORED STATS SERVER_ERROR */
+    {
+      if (buffer[2] == 'A') /* STORED STATS */
+      {
+        memcached_server_response_increment(ptr);
+        return MEMCACHED_STAT;
+      }
+      else if (buffer[1] == 'E') /* SERVER_ERROR */
+      {
+        char *rel_ptr;
+        char *startptr= buffer + 13, *endptr= startptr;
+
+        while (*endptr != '\r' && *endptr != '\n') endptr++;
+
+        /*
+          Yes, we could make this "efficent" but to do that we would need
+          to maintain more state for the size of the buffer. Why waste
+          memory in the struct, which is important, for something that
+          rarely should happen?
+        */
+        rel_ptr= (char *)libmemcached_realloc(ptr->root,
+                                              ptr->cached_server_error,
+                                              (size_t) (endptr - startptr + 1));
+
+        if (rel_ptr == NULL)
+        {
+          /* If we happened to have some memory, we just null it since we don't know the size */
+          if (ptr->cached_server_error)
+            ptr->cached_server_error[0]= 0;
+          return MEMCACHED_SERVER_ERROR;
+        }
+        ptr->cached_server_error= rel_ptr;
+
+        memcpy(ptr->cached_server_error, startptr, (size_t) (endptr - startptr));
+        ptr->cached_server_error[endptr - startptr]= 0;
+        return MEMCACHED_SERVER_ERROR;
+      }
+      else if (buffer[1] == 'T')
+        return MEMCACHED_STORED;
+      else
+      {
+        WATCHPOINT_STRING(buffer);
+        return MEMCACHED_UNKNOWN_READ_FAILURE;
+      }
+    }
+  case 'D': /* DELETED */
+    return MEMCACHED_DELETED;
+  case 'N': /* NOT_FOUND */
+    {
+      if (buffer[4] == 'F')
+        return MEMCACHED_NOTFOUND;
+      else if (buffer[4] == 'S')
+        return MEMCACHED_NOTSTORED;
+      else
+      {
+        WATCHPOINT_STRING(buffer);
+        return MEMCACHED_UNKNOWN_READ_FAILURE;
+      }
+    }
+  case 'E': /* PROTOCOL ERROR or END */
+    {
+      if (buffer[1] == 'N')
+        return MEMCACHED_END;
+      else if (buffer[1] == 'R')
+        return MEMCACHED_PROTOCOL_ERROR;
+      else if (buffer[1] == 'X')
+        return MEMCACHED_DATA_EXISTS;
+      else
+      {
+        WATCHPOINT_STRING(buffer);
+        return MEMCACHED_UNKNOWN_READ_FAILURE;
+      }
+
+    }
+  case 'I': /* CLIENT ERROR */
+    /* We add back in one because we will need to search for END */
+    memcached_server_response_increment(ptr);
+    return MEMCACHED_ITEM;
+  case 'C': /* CLIENT ERROR */
+    return MEMCACHED_CLIENT_ERROR;
+  default:
+    {
+      unsigned long long auto_return_value;
+
+      if (sscanf(buffer, "%llu", &auto_return_value) == 1)
+        return MEMCACHED_SUCCESS;
+
+      WATCHPOINT_STRING(buffer);
+      return MEMCACHED_UNKNOWN_READ_FAILURE;
+    }
+  }
+
+  /* NOTREACHED */
+}
+
+static memcached_return_t binary_read_one_response(memcached_server_write_instance_st ptr,
+                                                   char *buffer, size_t buffer_length,
+                                                   memcached_result_st *result)
+{
+  memcached_return_t rc;
+  protocol_binary_response_header header;
+
+  if ((rc= memcached_safe_read(ptr, &header.bytes, sizeof(header.bytes))) != MEMCACHED_SUCCESS)
+  {
+    WATCHPOINT_ERROR(rc);
+    return rc;
+  }
+
+  if (header.response.magic != PROTOCOL_BINARY_RES)
+  {
+    return MEMCACHED_PROTOCOL_ERROR;
+  }
+
+  /*
+   ** Convert the header to host local endian!
+ */
+  header.response.keylen= ntohs(header.response.keylen);
+  header.response.status= ntohs(header.response.status);
+  header.response.bodylen= ntohl(header.response.bodylen);
+  header.response.cas= ntohll(header.response.cas);
+  uint32_t bodylen= header.response.bodylen;
+
+  if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS ||
+      header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE)
+  {
+    switch (header.response.opcode)
+    {
+    case PROTOCOL_BINARY_CMD_GETKQ:
+      /*
+       * We didn't increment the response counter for the GETKQ packet
+       * (only the final NOOP), so we need to increment the counter again.
+       */
+      memcached_server_response_increment(ptr);
+      /* FALLTHROUGH */
+    case PROTOCOL_BINARY_CMD_GETK:
+      {
+        uint16_t keylen= header.response.keylen;
+        memcached_result_reset(result);
+        result->item_cas= header.response.cas;
+
+        if ((rc= memcached_safe_read(ptr, &result->item_flags, sizeof (result->item_flags))) != MEMCACHED_SUCCESS)
+        {
+          WATCHPOINT_ERROR(rc);
+          return MEMCACHED_UNKNOWN_READ_FAILURE;
+        }
+
+        result->item_flags= ntohl(result->item_flags);
+        bodylen -= header.response.extlen;
+
+        result->key_length= keylen;
+        if ((rc= memcached_safe_read(ptr, result->item_key, keylen)) != MEMCACHED_SUCCESS)
+        {
+          WATCHPOINT_ERROR(rc);
+          return MEMCACHED_UNKNOWN_READ_FAILURE;
+        }
+
+        bodylen -= keylen;
+        if (memcached_string_check(&result->value,
+                                   bodylen) != MEMCACHED_SUCCESS)
+          return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+        char *vptr= memcached_string_value_mutable(&result->value);
+        if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS)
+        {
+          WATCHPOINT_ERROR(rc);
+          return MEMCACHED_UNKNOWN_READ_FAILURE;
+        }
+
+        memcached_string_set_length(&result->value, bodylen);
+      }
+      break;
+    case PROTOCOL_BINARY_CMD_INCREMENT:
+    case PROTOCOL_BINARY_CMD_DECREMENT:
+      {
+        if (bodylen != sizeof(uint64_t) || buffer_length != sizeof(uint64_t))
+          return MEMCACHED_PROTOCOL_ERROR;
+
+        WATCHPOINT_ASSERT(bodylen == buffer_length);
+        uint64_t val;
+        if ((rc= memcached_safe_read(ptr, &val, sizeof(val))) != MEMCACHED_SUCCESS)
+        {
+          WATCHPOINT_ERROR(rc);
+          return MEMCACHED_UNKNOWN_READ_FAILURE;
+        }
+
+        val= ntohll(val);
+        memcpy(buffer, &val, sizeof(val));
+      }
+      break;
+    case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
+    case PROTOCOL_BINARY_CMD_VERSION:
+      {
+        memset(buffer, 0, buffer_length);
+        if (bodylen >= buffer_length)
+        {
+          /* not enough space in buffer.. should not happen... */
+          return MEMCACHED_UNKNOWN_READ_FAILURE;
+        }
+        else if ((rc= memcached_safe_read(ptr, buffer, bodylen)) != MEMCACHED_SUCCESS)
+        {
+          WATCHPOINT_ERROR(rc);
+          return MEMCACHED_UNKNOWN_READ_FAILURE;
+        }
+      }
+      break;
+    case PROTOCOL_BINARY_CMD_FLUSH:
+    case PROTOCOL_BINARY_CMD_QUIT:
+    case PROTOCOL_BINARY_CMD_SET:
+    case PROTOCOL_BINARY_CMD_ADD:
+    case PROTOCOL_BINARY_CMD_REPLACE:
+    case PROTOCOL_BINARY_CMD_APPEND:
+    case PROTOCOL_BINARY_CMD_PREPEND:
+    case PROTOCOL_BINARY_CMD_DELETE:
+      {
+        WATCHPOINT_ASSERT(bodylen == 0);
+        return MEMCACHED_SUCCESS;
+      }
+    case PROTOCOL_BINARY_CMD_NOOP:
+      {
+        WATCHPOINT_ASSERT(bodylen == 0);
+        return MEMCACHED_END;
+      }
+    case PROTOCOL_BINARY_CMD_STAT:
+      {
+        if (bodylen == 0)
+        {
+          return MEMCACHED_END;
+        }
+        else if (bodylen + 1 > buffer_length)
+        {
+          /* not enough space in buffer.. should not happen... */
+          return MEMCACHED_UNKNOWN_READ_FAILURE;
+        }
+        else
+        {
+          size_t keylen= header.response.keylen;
+          memset(buffer, 0, buffer_length);
+          if ((rc= memcached_safe_read(ptr, buffer, keylen)) != MEMCACHED_SUCCESS ||
+              (rc= memcached_safe_read(ptr, buffer + keylen + 1, bodylen - keylen)) != MEMCACHED_SUCCESS)
+          {
+            WATCHPOINT_ERROR(rc);
+            return MEMCACHED_UNKNOWN_READ_FAILURE;
+          }
+        }
+      }
+      break;
+
+    case PROTOCOL_BINARY_CMD_SASL_AUTH:
+    case PROTOCOL_BINARY_CMD_SASL_STEP:
+      {
+        memcached_result_reset(result);
+        result->item_cas= header.response.cas;
+
+        if (memcached_string_check(&result->value,
+                                   bodylen) != MEMCACHED_SUCCESS)
+          return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+        char *vptr= memcached_string_value_mutable(&result->value);
+        if ((rc= memcached_safe_read(ptr, vptr, bodylen)) != MEMCACHED_SUCCESS)
+        {
+          WATCHPOINT_ERROR(rc);
+          return MEMCACHED_UNKNOWN_READ_FAILURE;
+        }
+
+        memcached_string_set_length(&result->value, bodylen);
+      }
+      break;
+    default:
+      {
+        /* Command not implemented yet! */
+        WATCHPOINT_ASSERT(0);
+        return MEMCACHED_PROTOCOL_ERROR;
+      }
+    }
+  }
+  else if (header.response.bodylen)
+  {
+    /* What should I do with the error message??? just discard it for now */
+    char hole[SMALL_STRING_LEN];
+    while (bodylen > 0)
+    {
+      size_t nr= (bodylen > SMALL_STRING_LEN) ? SMALL_STRING_LEN : bodylen;
+      if ((rc= memcached_safe_read(ptr, hole, nr)) != MEMCACHED_SUCCESS)
+      {
+        WATCHPOINT_ERROR(rc);
+        return MEMCACHED_UNKNOWN_READ_FAILURE;
+      }
+      bodylen-= (uint32_t) nr;
+    }
+
+    /* This might be an error from one of the quiet commands.. if
+     * so, just throw it away and get the next one. What about creating
+     * a callback to the user with the error information?
+   */
+    switch (header.response.opcode)
+    {
+    case PROTOCOL_BINARY_CMD_SETQ:
+    case PROTOCOL_BINARY_CMD_ADDQ:
+    case PROTOCOL_BINARY_CMD_REPLACEQ:
+    case PROTOCOL_BINARY_CMD_APPENDQ:
+    case PROTOCOL_BINARY_CMD_PREPENDQ:
+      return binary_read_one_response(ptr, buffer, buffer_length, result);
+    default:
+      break;
+    }
+  }
+
+  rc= MEMCACHED_SUCCESS;
+  unlikely(header.response.status != 0)
+    switch (header.response.status)
+    {
+    case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
+      rc= MEMCACHED_NOTFOUND;
+      break;
+    case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
+      rc= MEMCACHED_DATA_EXISTS;
+      break;
+    case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
+      rc= MEMCACHED_NOTSTORED;
+      break;
+    case PROTOCOL_BINARY_RESPONSE_E2BIG:
+      rc= MEMCACHED_E2BIG;
+      break;
+    case PROTOCOL_BINARY_RESPONSE_ENOMEM:
+      rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+      break;
+    case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE:
+      rc= MEMCACHED_AUTH_CONTINUE;
+      break;
+    case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR:
+      rc= MEMCACHED_AUTH_FAILURE;
+      break;
+    case PROTOCOL_BINARY_RESPONSE_EINVAL:
+    case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
+    default:
+      /* @todo fix the error mappings */
+      rc= MEMCACHED_PROTOCOL_ERROR;
+      break;
+    }
+
+  return rc;
+}
index da6f2b4274cc345757c132ea510ce0185dfe7879..51f09998deba41e3f905e8b791fefa6a9cf28772 100644 (file)
@@ -1,16 +1,41 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
  *
- * Summary: Change the behavior of the memcached connection.
+ *  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.
  *
  */
 
-#ifndef __LIBMEMCACHED_RESPONSE_H__
-#define __LIBMEMCACHED_RESPONSE_H__
+#pragma once
 
 #ifdef __cplusplus
 extern "C" {
@@ -30,5 +55,3 @@ memcached_return_t memcached_response(memcached_server_write_instance_st ptr,
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __LIBMEMCACHED_RESPONSE_H__ */
diff --git a/libmemcached/result.c b/libmemcached/result.c
deleted file mode 100644 (file)
index 6e58eeb..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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: Functions to manipulate the result structure.
- *
- */
-
-/*
-  memcached_result_st are used to internally represent the return values from
-  memcached. We use a structure so that long term as identifiers are added
-  to memcached we will be able to absorb new attributes without having
-  to addjust the entire API.
-*/
-#include "common.h"
-
-static inline void _result_init(memcached_result_st *self,
-                                memcached_st *memc)
-{
-  self->item_flags= 0;
-  self->item_expiration= 0;
-  self->key_length= 0;
-  self->item_cas= 0;
-  self->root= memc;
-  self->item_key[0]= 0;
-}
-
-memcached_result_st *memcached_result_create(const memcached_st *memc,
-                                             memcached_result_st *ptr)
-{
-  WATCHPOINT_ASSERT(memc);
-
-  /* Saving malloc calls :) */
-  if (ptr)
-  {
-    ptr->options.is_allocated= false;
-  }
-  else
-  {
-    ptr= libmemcached_malloc(memc, sizeof(memcached_result_st));
-
-    if (ptr == NULL)
-      return NULL;
-
-    ptr->options.is_allocated= true;
-  }
-
-  ptr->options.is_initialized= true;
-
-  _result_init(ptr, (memcached_st *)memc);
-
-  WATCHPOINT_SET(ptr->value.options.is_initialized= false);
-  memcached_string_create(memc, &ptr->value, 0);
-  WATCHPOINT_ASSERT_INITIALIZED(&ptr->value);
-  WATCHPOINT_ASSERT(ptr->value.string == NULL);
-
-  return ptr;
-}
-
-void memcached_result_reset(memcached_result_st *ptr)
-{
-  ptr->key_length= 0;
-  memcached_string_reset(&ptr->value);
-  ptr->item_flags= 0;
-  ptr->item_cas= 0;
-  ptr->item_expiration= 0;
-}
-
-void memcached_result_free(memcached_result_st *ptr)
-{
-  if (ptr == NULL)
-    return;
-
-  memcached_string_free(&ptr->value);
-
-  if (memcached_is_allocated(ptr))
-  {
-    WATCHPOINT_ASSERT(ptr->root); // Without a root, that means that result was not properly initialized.
-    libmemcached_free(ptr->root, ptr);
-  }
-  else
-  {
-    ptr->options.is_initialized= false;
-  }
-}
-
-memcached_return_t memcached_result_set_value(memcached_result_st *ptr,
-                                              const char *value,
-                                              size_t length)
-{
-  memcached_return_t rc= memcached_string_append(&ptr->value, value, length);
-
-  if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
-  {
-    memcached_set_errno(ptr->root, errno, NULL);
-  }
-
-      return rc;
-}
-
-const char *memcached_result_key_value(const memcached_result_st *self)
-{
-  return self->key_length ? self->item_key : NULL;
-}
-
-size_t memcached_result_key_length(const memcached_result_st *self)
-{
-  return self->key_length;
-}
-
-const char *memcached_result_value(const memcached_result_st *self)
-{
-  const memcached_string_st *sptr= &self->value;
-  return memcached_string_value(sptr);
-}
-
-size_t memcached_result_length(const memcached_result_st *self)
-{
-  const memcached_string_st *sptr= &self->value;
-  return memcached_string_length(sptr);
-}
-
-uint32_t memcached_result_flags(const memcached_result_st *self)
-{
-  return self->item_flags;
-}
-
-uint64_t memcached_result_cas(const memcached_result_st *self)
-{
-  return self->item_cas;
-}
-
-void memcached_result_set_flags(memcached_result_st *self, uint32_t flags)
-{
-  self->item_flags= flags;
-}
-
-void memcached_result_set_expiration(memcached_result_st *self, time_t expiration)
-{
-  self->item_expiration= expiration;
-}
diff --git a/libmemcached/result.cc b/libmemcached/result.cc
new file mode 100644 (file)
index 0000000..1d0b763
--- /dev/null
@@ -0,0 +1,171 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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.
+ *
+ */
+
+
+/*
+  memcached_result_st are used to internally represent the return values from
+  memcached. We use a structure so that long term as identifiers are added
+  to memcached we will be able to absorb new attributes without having
+  to addjust the entire API.
+*/
+#include <libmemcached/common.h>
+
+static inline void _result_init(memcached_result_st *self,
+                                memcached_st *memc)
+{
+  self->item_flags= 0;
+  self->item_expiration= 0;
+  self->key_length= 0;
+  self->item_cas= 0;
+  self->root= memc;
+  self->item_key[0]= 0;
+}
+
+memcached_result_st *memcached_result_create(const memcached_st *memc,
+                                             memcached_result_st *ptr)
+{
+  WATCHPOINT_ASSERT(memc);
+
+  /* Saving malloc calls :) */
+  if (ptr)
+  {
+    ptr->options.is_allocated= false;
+  }
+  else
+  {
+    ptr= static_cast<memcached_result_st *>(libmemcached_malloc(memc, sizeof(memcached_result_st)));
+
+    if (ptr == NULL)
+      return NULL;
+
+    ptr->options.is_allocated= true;
+  }
+
+  ptr->options.is_initialized= true;
+
+  _result_init(ptr, (memcached_st *)memc);
+
+  WATCHPOINT_SET(ptr->value.options.is_initialized= false);
+  memcached_string_create(memc, &ptr->value, 0);
+  WATCHPOINT_ASSERT_INITIALIZED(&ptr->value);
+  WATCHPOINT_ASSERT(ptr->value.string == NULL);
+
+  return ptr;
+}
+
+void memcached_result_reset(memcached_result_st *ptr)
+{
+  ptr->key_length= 0;
+  memcached_string_reset(&ptr->value);
+  ptr->item_flags= 0;
+  ptr->item_cas= 0;
+  ptr->item_expiration= 0;
+}
+
+void memcached_result_free(memcached_result_st *ptr)
+{
+  if (ptr == NULL)
+    return;
+
+  memcached_string_free(&ptr->value);
+
+  if (memcached_is_allocated(ptr))
+  {
+    WATCHPOINT_ASSERT(ptr->root); // Without a root, that means that result was not properly initialized.
+    libmemcached_free(ptr->root, ptr);
+  }
+  else
+  {
+    ptr->options.is_initialized= false;
+  }
+}
+
+memcached_return_t memcached_result_set_value(memcached_result_st *ptr,
+                                              const char *value,
+                                              size_t length)
+{
+  memcached_return_t rc= memcached_string_append(&ptr->value, value, length);
+
+  if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
+  {
+    memcached_set_errno(ptr->root, errno, NULL);
+  }
+
+      return rc;
+}
+
+const char *memcached_result_key_value(const memcached_result_st *self)
+{
+  return self->key_length ? self->item_key : NULL;
+}
+
+size_t memcached_result_key_length(const memcached_result_st *self)
+{
+  return self->key_length;
+}
+
+const char *memcached_result_value(const memcached_result_st *self)
+{
+  const memcached_string_st *sptr= &self->value;
+  return memcached_string_value(sptr);
+}
+
+size_t memcached_result_length(const memcached_result_st *self)
+{
+  const memcached_string_st *sptr= &self->value;
+  return memcached_string_length(sptr);
+}
+
+uint32_t memcached_result_flags(const memcached_result_st *self)
+{
+  return self->item_flags;
+}
+
+uint64_t memcached_result_cas(const memcached_result_st *self)
+{
+  return self->item_cas;
+}
+
+void memcached_result_set_flags(memcached_result_st *self, uint32_t flags)
+{
+  self->item_flags= flags;
+}
+
+void memcached_result_set_expiration(memcached_result_st *self, time_t expiration)
+{
+  self->item_expiration= expiration;
+}
index c7aa60034b5b8bc3a2ed2e50c61b9b3e6891c4b4..048c06708e1c864b062758b5c0e63f0f1228ceb1 100644 (file)
@@ -90,4 +90,5 @@ enum memcached_return_t {
 typedef enum memcached_return_t memcached_return_t;
 #endif
 
+#define  memcached_failed(A) (A) != MEMCACHED_SUCCESS ? true : false
 
diff --git a/libmemcached/server.c b/libmemcached/server.c
deleted file mode 100644 (file)
index 4fe676b..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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: String structure used for libmemcached.
- *
- */
-
-/*
-  This is a partial implementation for fetching/creating memcached_server_st objects.
-*/
-#include <libmemcached/common.h>
-
-static inline void _server_init(memcached_server_st *self, const memcached_st *root,
-                                const char *hostname, in_port_t port,
-                                uint32_t weight, memcached_connection_t type)
-{
-  self->options.is_shutting_down= false;
-  self->options.is_dead= false;
-  self->number_of_hosts= 0;
-  self->cursor_active= 0;
-  self->port= port;
-  self->cached_errno= 0;
-  self->fd= -1;
-  self->io_bytes_sent= 0;
-  self->server_failure_counter= 0;
-  self->weight= weight ? weight : 1; // 1 is the default weight value
-  WATCHPOINT_SET(self->io_wait_count.read= 0);
-  WATCHPOINT_SET(self->io_wait_count.write= 0);
-  self->major_version= UINT8_MAX;
-  self->micro_version= UINT8_MAX;
-  self->minor_version= UINT8_MAX;
-  self->type= type;
-  self->read_ptr= self->read_buffer;
-  self->cached_server_error= NULL;
-  self->read_buffer_length= 0;
-  self->read_data_length= 0;
-  self->write_buffer_offset= 0;
-  self->address_info= NULL;
-  self->address_info_next= NULL;
-
-  if (root)
-  {
-    self->next_retry= root->retry_timeout;
-  }
-  else
-  {
-    self->next_retry= 0;
-  }
-
-  if (self->weight > 1 && root)
-  {
-    ((memcached_st *)root)->ketama.weighted= true;
-  }
-
-  self->root= root;
-  self->limit_maxbytes= 0;
-  if (hostname == NULL)
-  {
-    self->hostname[0]= 0;
-  }
-  else
-  {
-    strncpy(self->hostname, hostname, NI_MAXHOST - 1);
-  }
-}
-
-static memcached_server_st *_server_create(memcached_server_st *self, const memcached_st *memc)
-{
-  if (self == NULL)
-  {
-   self= (memcached_server_st *)libmemcached_malloc(memc, sizeof(memcached_server_st));
-
-    if (! self)
-      return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
-
-    self->options.is_allocated= true;
-  }
-  else
-  {
-    self->options.is_allocated= false;
-  }
-
-  self->options.is_initialized= true;
-
-  return self;
-}
-
-memcached_server_st *memcached_server_create_with(const memcached_st *memc,
-                                                  memcached_server_write_instance_st self,
-                                                  const char *hostname, in_port_t port,
-                                                  uint32_t weight, memcached_connection_t type)
-{
-  self= _server_create(self, memc);
-
-  if (self == NULL)
-    return NULL;
-
-  _server_init(self, memc, hostname, port, weight, type);
-
-
-  if (type == MEMCACHED_CONNECTION_UDP)
-  {
-    self->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
-    memcached_io_init_udp_header(self, 0);
-  }
-
-  return self;
-}
-
-void memcached_server_free(memcached_server_st *self)
-{
-  memcached_quit_server(self, false);
-
-  if (self->cached_server_error)
-    free(self->cached_server_error);
-
-  if (self->address_info)
-    freeaddrinfo(self->address_info);
-
-  if (memcached_is_allocated(self))
-  {
-    if (self->root)
-    {
-      libmemcached_free(self->root, self);
-    }
-    else
-    {
-      free(self);
-    }
-  }
-  else
-  {
-    self->options.is_initialized= false;
-  }
-}
-
-/*
-  If we do not have a valid object to clone from, we toss an error.
-*/
-memcached_server_st *memcached_server_clone(memcached_server_st *destination,
-                                            const memcached_server_st *source)
-{
-  /* We just do a normal create if source is missing */
-  if (source == NULL)
-    return NULL;
-
-  destination= memcached_server_create_with(source->root, destination,
-                                            source->hostname, source->port, source->weight,
-                                            source->type);
-  if (destination != NULL)
-  {
-    destination->cached_errno= source->cached_errno;
-
-    if (source->cached_server_error)
-      destination->cached_server_error= strdup(source->cached_server_error);
-  }
-
-  return destination;
-
-}
-
-memcached_return_t memcached_server_cursor(const memcached_st *ptr,
-                                           const memcached_server_fn *callback,
-                                           void *context,
-                                           uint32_t number_of_callbacks)
-{
-  memcached_return_t rc;
-  if ((rc= initialize_const_query(ptr)) != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
-  {
-    memcached_server_instance_st instance=
-      memcached_server_instance_by_position(ptr, x);
-
-    for (uint32_t y= 0; y < number_of_callbacks; y++)
-    {
-      unsigned int iferror;
-
-      iferror= (*callback[y])(ptr, instance, context);
-
-      if (iferror)
-        continue;
-    }
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_server_execute(memcached_st *ptr,
-                                            memcached_server_execute_fn callback,
-                                            void *context)
-{
-  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
-  {
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(ptr, x);
-
-    unsigned int iferror;
-
-    iferror= (*callback)(ptr, instance, context);
-
-    if (iferror)
-      continue;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-memcached_server_instance_st memcached_server_by_key(const memcached_st *ptr,
-                                                     const char *key,
-                                                     size_t key_length,
-                                                     memcached_return_t *error)
-{
-  uint32_t server_key;
-  memcached_server_instance_st instance;
-
-  memcached_return_t rc;
-  if ((rc= initialize_const_query(ptr)) != MEMCACHED_SUCCESS)
-  {
-    if (error)
-      *error= rc;
-
-    return NULL;
-  }
-
-  if ((rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)) != MEMCACHED_SUCCESS)
-  {
-    if (error)
-      *error= rc;
-
-    return NULL;
-  }
-
-  if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
-  {
-    *error= MEMCACHED_BAD_KEY_PROVIDED;
-    return NULL;
-  }
-
-  server_key= memcached_generate_hash(ptr, key, key_length);
-  instance= memcached_server_instance_by_position(ptr, server_key);
-
-  return instance;
-
-}
-
-void memcached_server_error_reset(memcached_server_st *self)
-{
-  WATCHPOINT_ASSERT(self);
-  if (! self)
-    return;
-
-  self->cached_server_error[0]= 0;
-}
-
-memcached_server_instance_st memcached_server_get_last_disconnect(const memcached_st *self)
-{
-  WATCHPOINT_ASSERT(self);
-  if (! self)
-    return 0;
-
-  return self->last_disconnected_server;
-}
-
-void memcached_server_list_free(memcached_server_list_st self)
-{
-  if (self == NULL)
-    return;
-
-  for (uint32_t x= 0; x < memcached_server_list_count(self); x++)
-  {
-    if (self[x].address_info)
-    {
-      freeaddrinfo(self[x].address_info);
-      self[x].address_info= NULL;
-    }
-  }
-
-  const memcached_st *root= self->root;
-  if (root)
-  {
-    libmemcached_free(root, self);
-  }
-  else
-  {
-    free(self);
-  }
-}
-
-uint32_t memcached_servers_set_count(memcached_server_st *servers, uint32_t count)
-{
-  WATCHPOINT_ASSERT(servers);
-  if (! servers)
-    return 0;
-
-  return servers->number_of_hosts= count;
-}
-
-uint32_t memcached_server_count(const memcached_st *self)
-{
-  WATCHPOINT_ASSERT(self);
-  if (! self)
-    return 0;
-
-  return self->number_of_hosts;
-}
-
-const char *memcached_server_name(memcached_server_instance_st self)
-{
-  WATCHPOINT_ASSERT(self);
-  if (! self)
-    return NULL;
-
-  return self->hostname;
-}
-
-in_port_t memcached_server_port(memcached_server_instance_st self)
-{
-  WATCHPOINT_ASSERT(self);
-  if (! self)
-    return 0;
-
-  return self->port;
-}
-
-uint32_t memcached_server_response_count(memcached_server_instance_st self)
-{
-  WATCHPOINT_ASSERT(self);
-  if (! self)
-    return 0;
-
-  return self->cursor_active;
-}
-
-const char *memcached_server_error(memcached_server_instance_st ptr)
-{
-  return ptr
-    ?  ptr->cached_server_error
-    : NULL;
-}
-
diff --git a/libmemcached/server.cc b/libmemcached/server.cc
new file mode 100644 (file)
index 0000000..1eb50ee
--- /dev/null
@@ -0,0 +1,342 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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: String structure used for libmemcached.
+ *
+ */
+
+/*
+  This is a partial implementation for fetching/creating memcached_server_st objects.
+*/
+#include <libmemcached/common.h>
+
+static inline void _server_init(memcached_server_st *self, const memcached_st *root,
+                                const char *hostname, in_port_t port,
+                                uint32_t weight, memcached_connection_t type)
+{
+  self->options.is_shutting_down= false;
+  self->options.is_dead= false;
+  self->number_of_hosts= 0;
+  self->cursor_active= 0;
+  self->port= port;
+  self->cached_errno= 0;
+  self->fd= -1;
+  self->io_bytes_sent= 0;
+  self->server_failure_counter= 0;
+  self->weight= weight ? weight : 1; // 1 is the default weight value
+  WATCHPOINT_SET(self->io_wait_count.read= 0);
+  WATCHPOINT_SET(self->io_wait_count.write= 0);
+  self->major_version= UINT8_MAX;
+  self->micro_version= UINT8_MAX;
+  self->minor_version= UINT8_MAX;
+  self->type= type;
+  self->read_ptr= self->read_buffer;
+  self->cached_server_error= NULL;
+  self->read_buffer_length= 0;
+  self->read_data_length= 0;
+  self->write_buffer_offset= 0;
+  self->address_info= NULL;
+  self->address_info_next= NULL;
+
+  if (root)
+  {
+    self->next_retry= root->retry_timeout;
+  }
+  else
+  {
+    self->next_retry= 0;
+  }
+
+  if (self->weight > 1 && root)
+  {
+    ((memcached_st *)root)->ketama.weighted= true;
+  }
+
+  self->root= root;
+  self->limit_maxbytes= 0;
+  if (hostname == NULL)
+  {
+    self->hostname[0]= 0;
+  }
+  else
+  {
+    strncpy(self->hostname, hostname, NI_MAXHOST - 1);
+  }
+}
+
+static memcached_server_st *_server_create(memcached_server_st *self, const memcached_st *memc)
+{
+  if (self == NULL)
+  {
+   self= (memcached_server_st *)libmemcached_malloc(memc, sizeof(memcached_server_st));
+
+    if (! self)
+      return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
+
+    self->options.is_allocated= true;
+  }
+  else
+  {
+    self->options.is_allocated= false;
+  }
+
+  self->options.is_initialized= true;
+
+  return self;
+}
+
+memcached_server_st *memcached_server_create_with(const memcached_st *memc,
+                                                  memcached_server_write_instance_st self,
+                                                  const char *hostname, in_port_t port,
+                                                  uint32_t weight, memcached_connection_t type)
+{
+  self= _server_create(self, memc);
+
+  if (self == NULL)
+    return NULL;
+
+  _server_init(self, memc, hostname, port, weight, type);
+
+
+  if (type == MEMCACHED_CONNECTION_UDP)
+  {
+    self->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
+    memcached_io_init_udp_header(self, 0);
+  }
+
+  return self;
+}
+
+void memcached_server_free(memcached_server_st *self)
+{
+  memcached_quit_server(self, false);
+
+  if (self->cached_server_error)
+    free(self->cached_server_error);
+
+  if (self->address_info)
+    freeaddrinfo(self->address_info);
+
+  if (memcached_is_allocated(self))
+  {
+    if (self->root)
+    {
+      libmemcached_free(self->root, self);
+    }
+    else
+    {
+      free(self);
+    }
+  }
+  else
+  {
+    self->options.is_initialized= false;
+  }
+}
+
+/*
+  If we do not have a valid object to clone from, we toss an error.
+*/
+memcached_server_st *memcached_server_clone(memcached_server_st *destination,
+                                            const memcached_server_st *source)
+{
+  /* We just do a normal create if source is missing */
+  if (source == NULL)
+    return NULL;
+
+  destination= memcached_server_create_with(source->root, destination,
+                                            source->hostname, source->port, source->weight,
+                                            source->type);
+  if (destination != NULL)
+  {
+    destination->cached_errno= source->cached_errno;
+
+    if (source->cached_server_error)
+      destination->cached_server_error= strdup(source->cached_server_error);
+  }
+
+  return destination;
+
+}
+
+memcached_return_t memcached_server_cursor(const memcached_st *ptr,
+                                           const memcached_server_fn *callback,
+                                           void *context,
+                                           uint32_t number_of_callbacks)
+{
+  memcached_return_t rc;
+  if ((rc= initialize_const_query(ptr)) != MEMCACHED_SUCCESS)
+  {
+    return rc;
+  }
+
+  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_server_instance_st instance=
+      memcached_server_instance_by_position(ptr, x);
+
+    for (uint32_t y= 0; y < number_of_callbacks; y++)
+    {
+      unsigned int iferror;
+
+      iferror= (*callback[y])(ptr, instance, context);
+
+      if (iferror)
+        continue;
+    }
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_server_execute(memcached_st *ptr,
+                                            memcached_server_execute_fn callback,
+                                            void *context)
+{
+  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    unsigned int iferror;
+
+    iferror= (*callback)(ptr, instance, context);
+
+    if (iferror)
+      continue;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+memcached_server_instance_st memcached_server_by_key(const memcached_st *ptr,
+                                                     const char *key,
+                                                     size_t key_length,
+                                                     memcached_return_t *error)
+{
+  memcached_return_t rc;
+  if (memcached_failed(rc= initialize_const_query(ptr)))
+  {
+    if (error)
+      *error= rc;
+
+    return NULL;
+  }
+
+  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
+  {
+    if (error)
+      *error= rc;
+
+    return NULL;
+  }
+
+  if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+  {
+    if (error)
+      *error= MEMCACHED_BAD_KEY_PROVIDED;
+    return NULL;
+  }
+
+  uint32_t server_key= memcached_generate_hash(ptr, key, key_length);
+  return memcached_server_instance_by_position(ptr, server_key);
+
+}
+
+void memcached_server_error_reset(memcached_server_st *self)
+{
+  WATCHPOINT_ASSERT(self);
+  if (not self)
+    return;
+
+  self->cached_server_error[0]= 0;
+}
+
+memcached_server_instance_st memcached_server_get_last_disconnect(const memcached_st *self)
+{
+  WATCHPOINT_ASSERT(self);
+  if (not self)
+    return 0;
+
+  return self->last_disconnected_server;
+}
+
+void memcached_server_list_free(memcached_server_list_st self)
+{
+  if (not self)
+    return;
+
+  for (uint32_t x= 0; x < memcached_server_list_count(self); x++)
+  {
+    if (self[x].address_info)
+    {
+      freeaddrinfo(self[x].address_info);
+      self[x].address_info= NULL;
+    }
+  }
+
+  const memcached_st *root= self->root;
+  if (root)
+  {
+    libmemcached_free(root, self);
+  }
+  else
+  {
+    free(self);
+  }
+}
+
+uint32_t memcached_servers_set_count(memcached_server_st *servers, uint32_t count)
+{
+  WATCHPOINT_ASSERT(servers);
+  if (not servers)
+    return 0;
+
+  return servers->number_of_hosts= count;
+}
+
+uint32_t memcached_server_count(const memcached_st *self)
+{
+  WATCHPOINT_ASSERT(self);
+  if (not self)
+    return 0;
+
+  return self->number_of_hosts;
+}
+
+const char *memcached_server_name(memcached_server_instance_st self)
+{
+  WATCHPOINT_ASSERT(self);
+  if (not self)
+    return NULL;
+
+  return self->hostname;
+}
+
+in_port_t memcached_server_port(memcached_server_instance_st self)
+{
+  WATCHPOINT_ASSERT(self);
+  if (not self)
+    return 0;
+
+  return self->port;
+}
+
+uint32_t memcached_server_response_count(memcached_server_instance_st self)
+{
+  WATCHPOINT_ASSERT(self);
+  if (not self)
+    return 0;
+
+  return self->cursor_active;
+}
+
+const char *memcached_server_error(memcached_server_instance_st ptr)
+{
+  return ptr ?  ptr->cached_server_error : NULL;
+}
+
diff --git a/libmemcached/server_list.c b/libmemcached/server_list.c
deleted file mode 100644 (file)
index ca37f7f..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-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: 
- *
- */
-
-
-#include "common.h"
-
-memcached_server_list_st 
-memcached_server_list_append_with_weight(memcached_server_list_st ptr,
-                                         const char *hostname, in_port_t port,
-                                         uint32_t weight,
-                                         memcached_return_t *error)
-{
-  uint32_t count;
-  memcached_server_list_st new_host_list;
-
-  if (hostname == NULL || error == NULL)
-    return NULL;
-
-  if (hostname[0] == '/')
-    port = 0;
-  else if (! port)
-    port= MEMCACHED_DEFAULT_PORT;
-
-  /* Increment count for hosts */
-  count= 1;
-  if (ptr != NULL)
-  {
-    count+= memcached_server_list_count(ptr);
-  }
-
-  new_host_list= (memcached_server_write_instance_st)realloc(ptr, sizeof(memcached_server_st) * count);
-  if (!new_host_list)
-  {
-    ptr->cached_errno= errno;
-    *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-    return NULL;
-  }
-
-  /* @todo Check return type */
-  memcached_server_create_with(NULL, &new_host_list[count-1], hostname, port, weight, port ? MEMCACHED_CONNECTION_TCP : MEMCACHED_CONNECTION_UNIX_SOCKET);
-
-  // Handset allocated since 
-  new_host_list->options.is_allocated= true;
-
-  /* Backwards compatibility hack */
-  memcached_servers_set_count(new_host_list, count);
-
-  *error= MEMCACHED_SUCCESS;
-  return new_host_list;
-}
-
-memcached_server_list_st
-memcached_server_list_append(memcached_server_list_st ptr,
-                             const char *hostname, in_port_t port,
-                             memcached_return_t *error)
-{
-  return memcached_server_list_append_with_weight(ptr, hostname, port, 0, error);
-}
-
-uint32_t memcached_server_list_count(const memcached_server_list_st self)
-{
-  return (self == NULL)
-    ? 0
-    : self->number_of_hosts;
-}
-
-memcached_server_st *memcached_server_list(const memcached_st *self)
-{
-  return self->servers;
-}
-
-void memcached_server_list_set(memcached_st *self, memcached_server_st *list)
-{
-  self->servers= list;
-}
diff --git a/libmemcached/server_list.cc b/libmemcached/server_list.cc
new file mode 100644 (file)
index 0000000..ca37f7f
--- /dev/null
@@ -0,0 +1,83 @@
+/* LibMemcached
+ * Copyright (C) 2006-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: 
+ *
+ */
+
+
+#include "common.h"
+
+memcached_server_list_st 
+memcached_server_list_append_with_weight(memcached_server_list_st ptr,
+                                         const char *hostname, in_port_t port,
+                                         uint32_t weight,
+                                         memcached_return_t *error)
+{
+  uint32_t count;
+  memcached_server_list_st new_host_list;
+
+  if (hostname == NULL || error == NULL)
+    return NULL;
+
+  if (hostname[0] == '/')
+    port = 0;
+  else if (! port)
+    port= MEMCACHED_DEFAULT_PORT;
+
+  /* Increment count for hosts */
+  count= 1;
+  if (ptr != NULL)
+  {
+    count+= memcached_server_list_count(ptr);
+  }
+
+  new_host_list= (memcached_server_write_instance_st)realloc(ptr, sizeof(memcached_server_st) * count);
+  if (!new_host_list)
+  {
+    ptr->cached_errno= errno;
+    *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+    return NULL;
+  }
+
+  /* @todo Check return type */
+  memcached_server_create_with(NULL, &new_host_list[count-1], hostname, port, weight, port ? MEMCACHED_CONNECTION_TCP : MEMCACHED_CONNECTION_UNIX_SOCKET);
+
+  // Handset allocated since 
+  new_host_list->options.is_allocated= true;
+
+  /* Backwards compatibility hack */
+  memcached_servers_set_count(new_host_list, count);
+
+  *error= MEMCACHED_SUCCESS;
+  return new_host_list;
+}
+
+memcached_server_list_st
+memcached_server_list_append(memcached_server_list_st ptr,
+                             const char *hostname, in_port_t port,
+                             memcached_return_t *error)
+{
+  return memcached_server_list_append_with_weight(ptr, hostname, port, 0, error);
+}
+
+uint32_t memcached_server_list_count(const memcached_server_list_st self)
+{
+  return (self == NULL)
+    ? 0
+    : self->number_of_hosts;
+}
+
+memcached_server_st *memcached_server_list(const memcached_st *self)
+{
+  return self->servers;
+}
+
+void memcached_server_list_set(memcached_st *self, memcached_server_st *list)
+{
+  self->servers= list;
+}
diff --git a/libmemcached/stats.c b/libmemcached/stats.c
deleted file mode 100644 (file)
index 45b530e..0000000
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
-*/
-
-#include "common.h"
-
-static const char *memcached_stat_keys[] = {
-  "pid",
-  "uptime",
-  "time",
-  "version",
-  "pointer_size",
-  "rusage_user",
-  "rusage_system",
-  "curr_items",
-  "total_items",
-  "bytes",
-  "curr_connections",
-  "total_connections",
-  "connection_structures",
-  "cmd_get",
-  "cmd_set",
-  "get_hits",
-  "get_misses",
-  "evictions",
-  "bytes_read",
-  "bytes_written",
-  "limit_maxbytes",
-  "threads",
-  NULL
-};
-
-struct local_context
-{
-  memcached_stat_fn func;
-  void *context;
-  const char *args;
-};
-
-
-static memcached_return_t set_data(memcached_stat_st *memc_stat, char *key, char *value)
-{
-
-  if (strlen(key) < 1)
-  {
-    WATCHPOINT_STRING(key);
-    return MEMCACHED_UNKNOWN_STAT_KEY;
-  }
-  else if (!strcmp("pid", key))
-  {
-    memc_stat->pid= (uint32_t) strtol(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("uptime", key))
-  {
-    memc_stat->uptime= (uint32_t) strtol(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("time", key))
-  {
-    memc_stat->time= (uint32_t) strtol(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("version", key))
-  {
-    memcpy(memc_stat->version, value, strlen(value));
-    memc_stat->version[strlen(value)]= 0;
-  }
-  else if (!strcmp("pointer_size", key))
-  {
-    memc_stat->pointer_size= (uint32_t) strtol(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("rusage_user", key))
-  {
-    char *walk_ptr;
-    for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++);
-    *walk_ptr= 0;
-    walk_ptr++;
-    memc_stat->rusage_user_seconds= (uint32_t) strtol(value, (char **)NULL, 10);
-    memc_stat->rusage_user_microseconds= (uint32_t) strtol(walk_ptr, (char **)NULL, 10);
-  }
-  else if (!strcmp("rusage_system", key))
-  {
-    char *walk_ptr;
-    for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++);
-    *walk_ptr= 0;
-    walk_ptr++;
-    memc_stat->rusage_system_seconds= (uint32_t) strtol(value, (char **)NULL, 10);
-    memc_stat->rusage_system_microseconds= (uint32_t) strtol(walk_ptr, (char **)NULL, 10);
-  }
-  else if (!strcmp("curr_items", key))
-  {
-    memc_stat->curr_items= (uint32_t) strtol(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("total_items", key))
-  {
-    memc_stat->total_items= (uint32_t) strtol(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("bytes_read", key))
-  {
-    memc_stat->bytes_read= (uint32_t) strtoll(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("bytes_written", key))
-  {
-    memc_stat->bytes_written= (uint32_t) strtoll(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("bytes", key))
-  {
-    memc_stat->bytes= (uint32_t) strtoll(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("curr_connections", key))
-  {
-    memc_stat->curr_connections= (uint32_t) strtoll(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("total_connections", key))
-  {
-    memc_stat->total_connections= (uint32_t) strtoll(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("connection_structures", key))
-  {
-    memc_stat->connection_structures= (uint32_t) strtol(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("cmd_get", key))
-  {
-    memc_stat->cmd_get= (uint64_t) strtoll(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("cmd_set", key))
-  {
-    memc_stat->cmd_set= (uint64_t) strtoll(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("get_hits", key))
-  {
-    memc_stat->get_hits= (uint64_t) strtoll(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("get_misses", key))
-  {
-    memc_stat->get_misses= (uint64_t)strtoll(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("evictions", key))
-  {
-    memc_stat->evictions= (uint64_t)strtoll(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("limit_maxbytes", key))
-  {
-    memc_stat->limit_maxbytes= (uint64_t) strtoll(value, (char **)NULL, 10);
-  }
-  else if (!strcmp("threads", key))
-  {
-    memc_stat->threads= (uint32_t) strtol(value, (char **)NULL, 10);
-  }
-  else if (!(strcmp("delete_misses", key) == 0 ||/* New stats in the 1.3 beta */
-             strcmp("delete_hits", key) == 0 ||/* Just swallow them for now.. */
-             strcmp("incr_misses", key) == 0 ||
-             strcmp("incr_hits", key) == 0 ||
-             strcmp("decr_misses", key) == 0 ||
-             strcmp("decr_hits", key) == 0 ||
-             strcmp("cas_misses", key) == 0 ||
-             strcmp("cas_hits", key) == 0 ||
-             strcmp("cas_badval", key) == 0 ||
-             strcmp("cmd_flush", key) == 0 ||
-             strcmp("accepting_conns", key) == 0 ||
-             strcmp("listen_disabled_num", key) == 0 ||
-             strcmp("conn_yields", key) == 0 ||
-             strcmp("auth_cmds", key) == 0 ||
-             strcmp("auth_errors", key) == 0 ||
-             strcmp("reclaimed", key) == 0))
-  {
-    WATCHPOINT_STRING(key);
-    /* return MEMCACHED_UNKNOWN_STAT_KEY; */
-    return MEMCACHED_SUCCESS;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-char *memcached_stat_get_value(const memcached_st *ptr, memcached_stat_st *memc_stat,
-                               const char *key, memcached_return_t *error)
-{
-  char buffer[SMALL_STRING_LEN];
-  int length;
-  char *ret;
-
-  *error= MEMCACHED_SUCCESS;
-
-  if (!memcmp("pid", key, sizeof("pid") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pid);
-  else if (!memcmp("uptime", key, sizeof("uptime") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->uptime);
-  else if (!memcmp("time", key, sizeof("time") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time);
-  else if (!memcmp("version", key, sizeof("version") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version);
-  else if (!memcmp("pointer_size", key, sizeof("pointer_size") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pointer_size);
-  else if (!memcmp("rusage_user", key, sizeof("rusage_user") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds);
-  else if (!memcmp("rusage_system", key, sizeof("rusage_system") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds);
-  else if (!memcmp("curr_items", key, sizeof("curr_items") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_items);
-  else if (!memcmp("total_items", key, sizeof("total_items") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_items);
-  else if (!memcmp("curr_connections", key, sizeof("curr_connections") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_connections);
-  else if (!memcmp("total_connections", key, sizeof("total_connections") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_connections);
-  else if (!memcmp("connection_structures", key, sizeof("connection_structures") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->connection_structures);
-  else if (!memcmp("cmd_get", key, sizeof("cmd_get") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get);
-  else if (!memcmp("cmd_set", key, sizeof("cmd_set") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set);
-  else if (!memcmp("get_hits", key, sizeof("get_hits") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits);
-  else if (!memcmp("get_misses", key, sizeof("get_misses") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses);
-  else if (!memcmp("evictions", key, sizeof("evictions") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions);
-  else if (!memcmp("bytes_read", key, sizeof("bytes_read") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read);
-  else if (!memcmp("bytes_written", key, sizeof("bytes_written") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written);
-  else if (!memcmp("bytes", key, sizeof("bytes") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes);
-  else if (!memcmp("limit_maxbytes", key, sizeof("limit_maxbytes") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes);
-  else if (! memcmp("threads", key, sizeof("threads") -1))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->threads);
-  else
-  {
-    *error= MEMCACHED_NOTFOUND;
-    return NULL;
-  }
-
-  if (length >= SMALL_STRING_LEN || length < 0)
-  {
-    *error= MEMCACHED_FAILURE;
-    return NULL;
-  }
-
-  ret= libmemcached_malloc(ptr, (size_t) (length + 1));
-  memcpy(ret, buffer, (size_t) length);
-  ret[length]= '\0';
-
-  return ret;
-}
-
-static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat,
-                                             const char *args,
-                                             memcached_server_write_instance_st instance,
-                                             struct local_context *check)
-{
-  memcached_return_t rc;
-
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  protocol_binary_request_stats request= {.bytes= {0}};
-  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
-  request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT;
-  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-
-  if (args != NULL)
-  {
-    size_t len= strlen(args);
-
-    rc= memcached_validate_key_length(len, true);
-    unlikely (rc != MEMCACHED_SUCCESS)
-      return rc;
-
-    request.message.header.request.keylen= htons((uint16_t)len);
-    request.message.header.request.bodylen= htonl((uint32_t) len);
-
-    struct libmemcached_io_vector_st vector[]=
-    {
-      { .length= sizeof(request.bytes), .buffer= request.bytes },
-      { .length= len, .buffer= args }
-    };
-
-    if (memcached_vdo(instance, vector, 2, true) != MEMCACHED_SUCCESS)
-    {
-      memcached_io_reset(instance);
-      return MEMCACHED_WRITE_FAILURE;
-    }
-  }
-  else
-  {
-    if (memcached_do(instance, request.bytes,
-                     sizeof(request.bytes), true) != MEMCACHED_SUCCESS)
-    {
-      memcached_io_reset(instance);
-      return MEMCACHED_WRITE_FAILURE;
-    }
-  }
-
-  memcached_server_response_decrement(instance);
-  do
-  {
-    rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
-
-    if (rc == MEMCACHED_END)
-      break;
-
-    unlikely (rc != MEMCACHED_SUCCESS)
-    {
-      memcached_io_reset(instance);
-      return rc;
-    }
-
-    if (memc_stat)
-    {
-      unlikely((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY)
-      {
-        WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
-        WATCHPOINT_ASSERT(0);
-      }
-    }
-
-    if (check && check->func)
-    {
-      size_t key_length= strlen(buffer);
-
-      check->func(instance,
-                  buffer, key_length,
-                  buffer+key_length+1, strlen(buffer+key_length+1),
-                  check->context);
-    }
-  } while (1);
-
-  /* shit... memcached_response will decrement the counter, so I need to
-   ** reset it.. todo: look at this and try to find a better solution.
- */
-  instance->cursor_active= 0;
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat,
-                                            const char *args,
-                                            memcached_server_write_instance_st instance,
-                                            struct local_context *check)
-{
-  memcached_return_t rc;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  int send_length;
-
-  if (args)
-    send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                                   "stats %s\r\n", args);
-  else
-    send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                                   "stats\r\n");
-
-  if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
-    return MEMCACHED_WRITE_FAILURE;
-
-  rc= memcached_do(instance, buffer, (size_t)send_length, true);
-  if (rc != MEMCACHED_SUCCESS)
-    goto error;
-
-  while (1)
-  {
-    rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-
-    if (rc == MEMCACHED_STAT)
-    {
-      char *string_ptr, *end_ptr;
-      char *key, *value;
-
-      string_ptr= buffer;
-      string_ptr+= 5; /* Move past STAT */
-      for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++);
-      key= string_ptr;
-      key[(size_t)(end_ptr-string_ptr)]= 0;
-
-      string_ptr= end_ptr + 1;
-      for (end_ptr= string_ptr; !(isspace(*end_ptr)); end_ptr++);
-      value= string_ptr;
-      value[(size_t)(end_ptr-string_ptr)]= 0;
-      string_ptr= end_ptr + 2;
-      if (memc_stat)
-      {
-        unlikely((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY)
-        {
-          WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
-          WATCHPOINT_ASSERT(0);
-        }
-      }
-
-      if (check && check->func)
-      {
-        check->func(instance,
-                    key, strlen(key),
-                    value, strlen(value),
-                    check->context);
-      }
-    }
-    else
-      break;
-  }
-
-error:
-  if (rc == MEMCACHED_END)
-    return MEMCACHED_SUCCESS;
-  else
-    return rc;
-}
-
-memcached_stat_st *memcached_stat(memcached_st *self, char *args, memcached_return_t *error)
-{
-  memcached_return_t rc;
-  memcached_stat_st *stats;
-
-  if ((rc= initialize_query(self)) != MEMCACHED_SUCCESS)
-  {
-    if (error)
-      *error= rc;
-
-    return NULL;
-  }
-
-  WATCHPOINT_ASSERT(error);
-
-  unlikely (self->flags.use_udp)
-  {
-    if (error)
-      *error= MEMCACHED_NOT_SUPPORTED;
-
-    return NULL;
-  }
-
-  stats= libmemcached_calloc(self, memcached_server_count(self), sizeof(memcached_stat_st));
-
-  if (! stats)
-  {
-    if (error)
-      *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-    return NULL;
-  }
-
-  WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
-  rc= MEMCACHED_SUCCESS;
-  for (uint32_t x= 0; x < memcached_server_count(self); x++)
-  {
-    memcached_return_t temp_return;
-    memcached_server_write_instance_st instance;
-    memcached_stat_st *stat_instance;
-
-    stat_instance= stats + x;
-
-    stat_instance->root= self;
-
-    instance= memcached_server_instance_fetch(self, x);
-
-    if (self->flags.binary_protocol)
-    {
-      temp_return= binary_stats_fetch(stat_instance, args, instance, NULL);
-    }
-    else
-    {
-      temp_return= ascii_stats_fetch(stat_instance, args, instance, NULL);
-    }
-
-    if (temp_return != MEMCACHED_SUCCESS)
-      rc= MEMCACHED_SOME_ERRORS;
-  }
-
-  if (error)
-    *error= rc;
-
-  return stats;
-}
-
-memcached_return_t memcached_stat_servername(memcached_stat_st *memc_stat, char *args,
-                                             const char *hostname, in_port_t port)
-{
-  memcached_st memc;
-  memcached_st *memc_ptr;
-  memcached_server_write_instance_st instance;
-
-  memset(memc_stat, 0, sizeof(memcached_stat_st));
-
-  memc_ptr= memcached_create(&memc);
-  if (! memc_ptr)
-    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-  memcached_server_add(&memc, hostname, port);
-
-  memcached_return_t rc;
-  if ((rc= initialize_query(memc_ptr)) != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  instance= memcached_server_instance_fetch(memc_ptr, 0);
-
-  if (memc.flags.binary_protocol)
-  {
-    rc= binary_stats_fetch(memc_stat, args, instance, NULL);
-  }
-  else
-  {
-    rc= ascii_stats_fetch(memc_stat, args, instance, NULL);
-  }
-
-  memcached_free(&memc);
-
-  return rc;
-}
-
-/*
-  We make a copy of the keys since at some point in the not so distant future
-  we will add support for "found" keys.
-*/
-char ** memcached_stat_get_keys(const memcached_st *ptr,
-                                memcached_stat_st *memc_stat,
-                                memcached_return_t *error)
-{
-  char **list;
-  size_t length= sizeof(memcached_stat_keys);
-
-  (void)memc_stat;
-
-  list= libmemcached_malloc(ptr, length);
-
-  if (! list)
-  {
-    *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-    return NULL;
-  }
-
-  memcpy(list, memcached_stat_keys, sizeof(memcached_stat_keys));
-
-  *error= MEMCACHED_SUCCESS;
-
-  return list;
-}
-
-void memcached_stat_free(const memcached_st *ptr, memcached_stat_st *memc_stat)
-{
-  if (memc_stat == NULL)
-  {
-    WATCHPOINT_ASSERT(0); /* Be polite, but when debugging catch this as an error */
-    return;
-  }
-
-  if (memc_stat->root)
-  {
-    libmemcached_free(memc_stat->root, memc_stat);
-  }
-  else if (ptr)
-  {
-    libmemcached_free(ptr, memc_stat);
-  }
-  else
-  {
-    free(memc_stat);
-  }
-}
-
-static memcached_return_t call_stat_fn(memcached_st *ptr,
-                                       memcached_server_write_instance_st instance,
-                                       void *context)
-{
-  memcached_return_t rc;
-  struct local_context *check= (struct local_context *)context;
-
-  if (ptr->flags.binary_protocol)
-  {
-    rc= binary_stats_fetch(NULL, check->args, instance, check);
-  }
-  else
-  {
-    rc= ascii_stats_fetch(NULL, check->args, instance, check);
-  }
-
-  return rc;
-}
-
-memcached_return_t memcached_stat_execute(memcached_st *memc, const char *args,  memcached_stat_fn func, void *context)
-{
-  memcached_version(memc);
-
- struct local_context check= { .func= func, .context= context, .args= args };
-
- return memcached_server_execute(memc, call_stat_fn, (void *)&check);
-}
diff --git a/libmemcached/stats.cc b/libmemcached/stats.cc
new file mode 100644 (file)
index 0000000..08934ba
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+*/
+
+#include "common.h"
+
+static const char *memcached_stat_keys[] = {
+  "pid",
+  "uptime",
+  "time",
+  "version",
+  "pointer_size",
+  "rusage_user",
+  "rusage_system",
+  "curr_items",
+  "total_items",
+  "bytes",
+  "curr_connections",
+  "total_connections",
+  "connection_structures",
+  "cmd_get",
+  "cmd_set",
+  "get_hits",
+  "get_misses",
+  "evictions",
+  "bytes_read",
+  "bytes_written",
+  "limit_maxbytes",
+  "threads",
+  NULL
+};
+
+struct local_context
+{
+  memcached_stat_fn func;
+  void *context;
+  const char *args;
+
+  local_context(memcached_stat_fn func_arg,
+               void *context_arg,
+               const char *args_arg) :
+    func(func_arg),
+    context(context_arg),
+    args(args_arg)
+  { }
+};
+
+
+static memcached_return_t set_data(memcached_stat_st *memc_stat, char *key, char *value)
+{
+
+  if (strlen(key) < 1)
+  {
+    WATCHPOINT_STRING(key);
+    return MEMCACHED_UNKNOWN_STAT_KEY;
+  }
+  else if (!strcmp("pid", key))
+  {
+    memc_stat->pid= (uint32_t) strtol(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("uptime", key))
+  {
+    memc_stat->uptime= (uint32_t) strtol(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("time", key))
+  {
+    memc_stat->time= (uint32_t) strtol(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("version", key))
+  {
+    memcpy(memc_stat->version, value, strlen(value));
+    memc_stat->version[strlen(value)]= 0;
+  }
+  else if (!strcmp("pointer_size", key))
+  {
+    memc_stat->pointer_size= (uint32_t) strtol(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("rusage_user", key))
+  {
+    char *walk_ptr;
+    for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++);
+    *walk_ptr= 0;
+    walk_ptr++;
+    memc_stat->rusage_user_seconds= (uint32_t) strtol(value, (char **)NULL, 10);
+    memc_stat->rusage_user_microseconds= (uint32_t) strtol(walk_ptr, (char **)NULL, 10);
+  }
+  else if (!strcmp("rusage_system", key))
+  {
+    char *walk_ptr;
+    for (walk_ptr= value; (!ispunct(*walk_ptr)); walk_ptr++);
+    *walk_ptr= 0;
+    walk_ptr++;
+    memc_stat->rusage_system_seconds= (uint32_t) strtol(value, (char **)NULL, 10);
+    memc_stat->rusage_system_microseconds= (uint32_t) strtol(walk_ptr, (char **)NULL, 10);
+  }
+  else if (!strcmp("curr_items", key))
+  {
+    memc_stat->curr_items= (uint32_t) strtol(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("total_items", key))
+  {
+    memc_stat->total_items= (uint32_t) strtol(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("bytes_read", key))
+  {
+    memc_stat->bytes_read= (uint32_t) strtoll(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("bytes_written", key))
+  {
+    memc_stat->bytes_written= (uint32_t) strtoll(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("bytes", key))
+  {
+    memc_stat->bytes= (uint32_t) strtoll(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("curr_connections", key))
+  {
+    memc_stat->curr_connections= (uint32_t) strtoll(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("total_connections", key))
+  {
+    memc_stat->total_connections= (uint32_t) strtoll(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("connection_structures", key))
+  {
+    memc_stat->connection_structures= (uint32_t) strtol(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("cmd_get", key))
+  {
+    memc_stat->cmd_get= (uint64_t) strtoll(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("cmd_set", key))
+  {
+    memc_stat->cmd_set= (uint64_t) strtoll(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("get_hits", key))
+  {
+    memc_stat->get_hits= (uint64_t) strtoll(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("get_misses", key))
+  {
+    memc_stat->get_misses= (uint64_t)strtoll(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("evictions", key))
+  {
+    memc_stat->evictions= (uint64_t)strtoll(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("limit_maxbytes", key))
+  {
+    memc_stat->limit_maxbytes= (uint64_t) strtoll(value, (char **)NULL, 10);
+  }
+  else if (!strcmp("threads", key))
+  {
+    memc_stat->threads= (uint32_t) strtol(value, (char **)NULL, 10);
+  }
+  else if (!(strcmp("delete_misses", key) == 0 ||/* New stats in the 1.3 beta */
+             strcmp("delete_hits", key) == 0 ||/* Just swallow them for now.. */
+             strcmp("incr_misses", key) == 0 ||
+             strcmp("incr_hits", key) == 0 ||
+             strcmp("decr_misses", key) == 0 ||
+             strcmp("decr_hits", key) == 0 ||
+             strcmp("cas_misses", key) == 0 ||
+             strcmp("cas_hits", key) == 0 ||
+             strcmp("cas_badval", key) == 0 ||
+             strcmp("cmd_flush", key) == 0 ||
+             strcmp("accepting_conns", key) == 0 ||
+             strcmp("listen_disabled_num", key) == 0 ||
+             strcmp("conn_yields", key) == 0 ||
+             strcmp("auth_cmds", key) == 0 ||
+             strcmp("auth_errors", key) == 0 ||
+             strcmp("reclaimed", key) == 0))
+  {
+    WATCHPOINT_STRING(key);
+    /* return MEMCACHED_UNKNOWN_STAT_KEY; */
+    return MEMCACHED_SUCCESS;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+char *memcached_stat_get_value(const memcached_st *ptr, memcached_stat_st *memc_stat,
+                               const char *key, memcached_return_t *error)
+{
+  char buffer[SMALL_STRING_LEN];
+  int length;
+  char *ret;
+
+  *error= MEMCACHED_SUCCESS;
+
+  if (!memcmp("pid", key, sizeof("pid") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pid);
+  else if (!memcmp("uptime", key, sizeof("uptime") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->uptime);
+  else if (!memcmp("time", key, sizeof("time") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time);
+  else if (!memcmp("version", key, sizeof("version") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version);
+  else if (!memcmp("pointer_size", key, sizeof("pointer_size") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pointer_size);
+  else if (!memcmp("rusage_user", key, sizeof("rusage_user") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds);
+  else if (!memcmp("rusage_system", key, sizeof("rusage_system") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds);
+  else if (!memcmp("curr_items", key, sizeof("curr_items") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_items);
+  else if (!memcmp("total_items", key, sizeof("total_items") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_items);
+  else if (!memcmp("curr_connections", key, sizeof("curr_connections") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_connections);
+  else if (!memcmp("total_connections", key, sizeof("total_connections") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_connections);
+  else if (!memcmp("connection_structures", key, sizeof("connection_structures") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->connection_structures);
+  else if (!memcmp("cmd_get", key, sizeof("cmd_get") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get);
+  else if (!memcmp("cmd_set", key, sizeof("cmd_set") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set);
+  else if (!memcmp("get_hits", key, sizeof("get_hits") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits);
+  else if (!memcmp("get_misses", key, sizeof("get_misses") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses);
+  else if (!memcmp("evictions", key, sizeof("evictions") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions);
+  else if (!memcmp("bytes_read", key, sizeof("bytes_read") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read);
+  else if (!memcmp("bytes_written", key, sizeof("bytes_written") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written);
+  else if (!memcmp("bytes", key, sizeof("bytes") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes);
+  else if (!memcmp("limit_maxbytes", key, sizeof("limit_maxbytes") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes);
+  else if (! memcmp("threads", key, sizeof("threads") -1))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->threads);
+  else
+  {
+    *error= MEMCACHED_NOTFOUND;
+    return NULL;
+  }
+
+  if (length >= SMALL_STRING_LEN || length < 0)
+  {
+    *error= MEMCACHED_FAILURE;
+    return NULL;
+  }
+
+  ret= static_cast<char *>(libmemcached_malloc(ptr, (size_t) (length + 1)));
+  memcpy(ret, buffer, (size_t) length);
+  ret[length]= '\0';
+
+  return ret;
+}
+
+static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat,
+                                             const char *args,
+                                             memcached_server_write_instance_st instance,
+                                             struct local_context *check)
+{
+  memcached_return_t rc;
+
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+  protocol_binary_request_stats request= {}; // = {.bytes= {0}};
+  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+  request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT;
+  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+  if (args != NULL)
+  {
+    size_t len= strlen(args);
+
+    rc= memcached_validate_key_length(len, true);
+    unlikely (rc != MEMCACHED_SUCCESS)
+      return rc;
+
+    request.message.header.request.keylen= htons((uint16_t)len);
+    request.message.header.request.bodylen= htonl((uint32_t) len);
+
+    struct libmemcached_io_vector_st vector[]=
+    {
+      { sizeof(request.bytes), request.bytes },
+      { len, args }
+    };
+
+    if (memcached_vdo(instance, vector, 2, true) != MEMCACHED_SUCCESS)
+    {
+      memcached_io_reset(instance);
+      return MEMCACHED_WRITE_FAILURE;
+    }
+  }
+  else
+  {
+    if (memcached_do(instance, request.bytes,
+                     sizeof(request.bytes), true) != MEMCACHED_SUCCESS)
+    {
+      memcached_io_reset(instance);
+      return MEMCACHED_WRITE_FAILURE;
+    }
+  }
+
+  memcached_server_response_decrement(instance);
+  do
+  {
+    rc= memcached_response(instance, buffer, sizeof(buffer), NULL);
+
+    if (rc == MEMCACHED_END)
+      break;
+
+    unlikely (rc != MEMCACHED_SUCCESS)
+    {
+      memcached_io_reset(instance);
+      return rc;
+    }
+
+    if (memc_stat)
+    {
+      unlikely((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY)
+      {
+        WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
+        WATCHPOINT_ASSERT(0);
+      }
+    }
+
+    if (check && check->func)
+    {
+      size_t key_length= strlen(buffer);
+
+      check->func(instance,
+                  buffer, key_length,
+                  buffer+key_length+1, strlen(buffer+key_length+1),
+                  check->context);
+    }
+  } while (1);
+
+  /* shit... memcached_response will decrement the counter, so I need to
+   ** reset it.. todo: look at this and try to find a better solution.
+ */
+  instance->cursor_active= 0;
+
+  return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat,
+                                            const char *args,
+                                            memcached_server_write_instance_st instance,
+                                            struct local_context *check)
+{
+  memcached_return_t rc;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+  int send_length;
+
+  if (args)
+    send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                                   "stats %s\r\n", args);
+  else
+    send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                                   "stats\r\n");
+
+  if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
+    return MEMCACHED_WRITE_FAILURE;
+
+  rc= memcached_do(instance, buffer, (size_t)send_length, true);
+  if (rc != MEMCACHED_SUCCESS)
+    goto error;
+
+  while (1)
+  {
+    rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+    if (rc == MEMCACHED_STAT)
+    {
+      char *string_ptr, *end_ptr;
+      char *key, *value;
+
+      string_ptr= buffer;
+      string_ptr+= 5; /* Move past STAT */
+      for (end_ptr= string_ptr; isgraph(*end_ptr); end_ptr++);
+      key= string_ptr;
+      key[(size_t)(end_ptr-string_ptr)]= 0;
+
+      string_ptr= end_ptr + 1;
+      for (end_ptr= string_ptr; !(isspace(*end_ptr)); end_ptr++);
+      value= string_ptr;
+      value[(size_t)(end_ptr-string_ptr)]= 0;
+      string_ptr= end_ptr + 2;
+      if (memc_stat)
+      {
+        unlikely((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY)
+        {
+          WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
+          WATCHPOINT_ASSERT(0);
+        }
+      }
+
+      if (check && check->func)
+      {
+        check->func(instance,
+                    key, strlen(key),
+                    value, strlen(value),
+                    check->context);
+      }
+    }
+    else
+      break;
+  }
+
+error:
+  if (rc == MEMCACHED_END)
+    return MEMCACHED_SUCCESS;
+  else
+    return rc;
+}
+
+memcached_stat_st *memcached_stat(memcached_st *self, char *args, memcached_return_t *error)
+{
+  memcached_return_t rc;
+  memcached_stat_st *stats;
+
+  if ((rc= initialize_query(self)) != MEMCACHED_SUCCESS)
+  {
+    if (error)
+      *error= rc;
+
+    return NULL;
+  }
+
+  WATCHPOINT_ASSERT(error);
+
+  unlikely (self->flags.use_udp)
+  {
+    if (error)
+      *error= MEMCACHED_NOT_SUPPORTED;
+
+    return NULL;
+  }
+
+  stats= static_cast<memcached_stat_st *>(libmemcached_calloc(self, memcached_server_count(self), sizeof(memcached_stat_st)));
+
+  if (! stats)
+  {
+    if (error)
+      *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+    return NULL;
+  }
+
+  WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
+  rc= MEMCACHED_SUCCESS;
+  for (uint32_t x= 0; x < memcached_server_count(self); x++)
+  {
+    memcached_return_t temp_return;
+    memcached_server_write_instance_st instance;
+    memcached_stat_st *stat_instance;
+
+    stat_instance= stats + x;
+
+    stat_instance->root= self;
+
+    instance= memcached_server_instance_fetch(self, x);
+
+    if (self->flags.binary_protocol)
+    {
+      temp_return= binary_stats_fetch(stat_instance, args, instance, NULL);
+    }
+    else
+    {
+      temp_return= ascii_stats_fetch(stat_instance, args, instance, NULL);
+    }
+
+    if (temp_return != MEMCACHED_SUCCESS)
+      rc= MEMCACHED_SOME_ERRORS;
+  }
+
+  if (error)
+    *error= rc;
+
+  return stats;
+}
+
+memcached_return_t memcached_stat_servername(memcached_stat_st *memc_stat, char *args,
+                                             const char *hostname, in_port_t port)
+{
+  memcached_st memc;
+  memcached_st *memc_ptr;
+  memcached_server_write_instance_st instance;
+
+  memset(memc_stat, 0, sizeof(memcached_stat_st));
+
+  memc_ptr= memcached_create(&memc);
+  if (! memc_ptr)
+    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+  memcached_server_add(&memc, hostname, port);
+
+  memcached_return_t rc;
+  if ((rc= initialize_query(memc_ptr)) != MEMCACHED_SUCCESS)
+  {
+    return rc;
+  }
+
+  instance= memcached_server_instance_fetch(memc_ptr, 0);
+
+  if (memc.flags.binary_protocol)
+  {
+    rc= binary_stats_fetch(memc_stat, args, instance, NULL);
+  }
+  else
+  {
+    rc= ascii_stats_fetch(memc_stat, args, instance, NULL);
+  }
+
+  memcached_free(&memc);
+
+  return rc;
+}
+
+/*
+  We make a copy of the keys since at some point in the not so distant future
+  we will add support for "found" keys.
+*/
+char ** memcached_stat_get_keys(const memcached_st *ptr,
+                                memcached_stat_st *memc_stat,
+                                memcached_return_t *error)
+{
+  char **list;
+  size_t length= sizeof(memcached_stat_keys);
+
+  (void)memc_stat;
+
+  list= static_cast<char **>(libmemcached_malloc(ptr, length));
+
+  if (not list)
+  {
+    *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+    return NULL;
+  }
+
+  memcpy(list, memcached_stat_keys, sizeof(memcached_stat_keys));
+
+  *error= MEMCACHED_SUCCESS;
+
+  return list;
+}
+
+void memcached_stat_free(const memcached_st *ptr, memcached_stat_st *memc_stat)
+{
+  if (memc_stat == NULL)
+  {
+    WATCHPOINT_ASSERT(0); /* Be polite, but when debugging catch this as an error */
+    return;
+  }
+
+  if (memc_stat->root)
+  {
+    libmemcached_free(memc_stat->root, memc_stat);
+  }
+  else if (ptr)
+  {
+    libmemcached_free(ptr, memc_stat);
+  }
+  else
+  {
+    free(memc_stat);
+  }
+}
+
+static memcached_return_t call_stat_fn(memcached_st *ptr,
+                                       memcached_server_write_instance_st instance,
+                                       void *context)
+{
+  memcached_return_t rc;
+  struct local_context *check= (struct local_context *)context;
+
+  if (ptr->flags.binary_protocol)
+  {
+    rc= binary_stats_fetch(NULL, check->args, instance, check);
+  }
+  else
+  {
+    rc= ascii_stats_fetch(NULL, check->args, instance, check);
+  }
+
+  return rc;
+}
+
+memcached_return_t memcached_stat_execute(memcached_st *memc, const char *args,  memcached_stat_fn func, void *context)
+{
+  memcached_version(memc);
+
+ struct local_context check(func, context, args);
+
+ return memcached_server_execute(memc, call_stat_fn, (void *)&check);
+}
diff --git a/libmemcached/storage.c b/libmemcached/storage.c
deleted file mode 100644 (file)
index 135def3..0000000
+++ /dev/null
@@ -1,570 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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: Storage related functions, aka set, replace,..
- *
- */
-
-#include "common.h"
-
-typedef enum {
-  SET_OP,
-  REPLACE_OP,
-  ADD_OP,
-  PREPEND_OP,
-  APPEND_OP,
-  CAS_OP,
-} memcached_storage_action_t;
-
-/* Inline this */
-static inline const char *storage_op_string(memcached_storage_action_t verb)
-{
-  switch (verb)
-  {
-  case SET_OP:
-    return "set ";
-  case REPLACE_OP:
-    return "replace ";
-  case ADD_OP:
-    return "add ";
-  case PREPEND_OP:
-    return "prepend ";
-  case APPEND_OP:
-    return "append ";
-  case CAS_OP:
-    return "cas ";
-  default:
-    return "tosserror"; /* This is impossible, fixes issue for compiler warning in VisualStudio */
-  }
-
-  /* NOTREACHED */
-}
-
-static memcached_return_t memcached_send_binary(memcached_st *ptr,
-                                                memcached_server_write_instance_st server,
-                                                uint32_t server_key,
-                                                const char *key,
-                                                size_t key_length,
-                                                const char *value,
-                                                size_t value_length,
-                                                time_t expiration,
-                                                uint32_t flags,
-                                                uint64_t cas,
-                                                memcached_storage_action_t verb);
-
-static inline memcached_return_t memcached_send(memcached_st *ptr,
-                                                const char *group_key, size_t group_key_length,
-                                                const char *key, size_t key_length,
-                                                const char *value, size_t value_length,
-                                                time_t expiration,
-                                                uint32_t flags,
-                                                uint64_t cas,
-                                                memcached_storage_action_t verb)
-{
-  bool to_write;
-  size_t write_length;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  uint32_t server_key;
-  memcached_server_write_instance_st instance;
-
-  WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));
-
-  memcached_return_t rc;
-  if ((rc= initialize_query(ptr)) != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
-    return MEMCACHED_BAD_KEY_PROVIDED;
-
-  server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
-  instance= memcached_server_instance_fetch(ptr, server_key);
-
-  WATCHPOINT_SET(instance->io_wait_count.read= 0);
-  WATCHPOINT_SET(instance->io_wait_count.write= 0);
-
-  if (ptr->flags.binary_protocol)
-  {
-    rc= memcached_send_binary(ptr, instance, server_key,
-                              key, key_length,
-                              value, value_length, expiration,
-                              flags, cas, verb);
-    WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read);
-    WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write);
-  }
-  else
-  {
-
-    if (cas)
-    {
-      int check_length;
-      check_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                                    "%s %.*s%.*s %u %llu %lu %llu%s\r\n",
-                                    storage_op_string(verb),
-                                    memcached_print_array(ptr->prefix_key),
-                                    (int)key_length, key, flags,
-                                    (unsigned long long)expiration, (unsigned long)value_length,
-                                    (unsigned long long)cas,
-                                    (ptr->flags.no_reply) ? " noreply" : "");
-      if (check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || check_length < 0)
-      {
-        rc= MEMCACHED_WRITE_FAILURE;
-        memcached_io_reset(instance);
-
-        return rc;
-      }
-      write_length= check_length;
-    }
-    else
-    {
-      char *buffer_ptr= buffer;
-      const char *command= storage_op_string(verb);
-
-      /* Copy in the command, no space needed, we handle that in the command function*/
-      memcpy(buffer_ptr, command, strlen(command));
-
-      /* Copy in the key prefix, switch to the buffer_ptr */
-      buffer_ptr= memcpy((buffer_ptr + strlen(command)), memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key));
-
-      /* Copy in the key, adjust point if a key prefix was used. */
-      buffer_ptr= memcpy(buffer_ptr + memcached_array_size(ptr->prefix_key),
-                         key, key_length);
-      buffer_ptr+= key_length;
-      buffer_ptr[0]=  ' ';
-      buffer_ptr++;
-
-      write_length= (size_t)(buffer_ptr - buffer);
-      int check_length;
-      check_length= snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer),
-                                    "%u %llu %lu%s\r\n",
-                                    flags,
-                                    (unsigned long long)expiration, (unsigned long)value_length,
-                                    ptr->flags.no_reply ? " noreply" : "");
-      if ((size_t)check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer) || check_length < 0)
-      {
-        rc= MEMCACHED_WRITE_FAILURE;
-        memcached_io_reset(instance);
-
-        return rc;
-      }
-
-      write_length+= (size_t)check_length;
-      WATCHPOINT_ASSERT(write_length < MEMCACHED_DEFAULT_COMMAND_SIZE);
-    }
-
-    if (ptr->flags.use_udp && ptr->flags.buffer_requests)
-    {
-      size_t cmd_size= write_length + value_length + 2;
-      if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
-        return MEMCACHED_WRITE_FAILURE;
-      if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
-        memcached_io_write(instance, NULL, 0, true);
-    }
-
-    if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
-    {
-      rc= MEMCACHED_WRITE_FAILURE;
-    }
-    else
-    {
-      struct libmemcached_io_vector_st vector[]=
-      {
-        { .length= write_length, .buffer= buffer },
-        { .length= value_length, .buffer= value },
-        { .length= 2, .buffer= "\r\n" }
-      };
-
-      if (ptr->flags.buffer_requests && verb == SET_OP)
-      {
-        to_write= false;
-      }
-      else
-      {
-        to_write= true;
-      }
-
-      /* Send command header */
-      rc=  memcached_vdo(instance, vector, 3, to_write);
-      if (rc == MEMCACHED_SUCCESS)
-      {
-
-        if (ptr->flags.no_reply)
-        {
-          rc= (to_write == false) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS;
-        }
-        else if (to_write == false)
-        {
-          rc= MEMCACHED_BUFFERED;
-        }
-        else
-        {
-          rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-
-          if (rc == MEMCACHED_STORED)
-            rc= MEMCACHED_SUCCESS;
-        }
-      }
-    }
-
-    if (rc == MEMCACHED_WRITE_FAILURE)
-      memcached_io_reset(instance);
-  }
-
-  WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read);
-  WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write);
-
-  return rc;
-}
-
-
-memcached_return_t memcached_set(memcached_st *ptr, const char *key, size_t key_length,
-                                 const char *value, size_t value_length,
-                                 time_t expiration,
-                                 uint32_t flags)
-{
-  memcached_return_t rc;
-  LIBMEMCACHED_MEMCACHED_SET_START();
-  rc= memcached_send(ptr, key, key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, SET_OP);
-  LIBMEMCACHED_MEMCACHED_SET_END();
-  return rc;
-}
-
-memcached_return_t memcached_add(memcached_st *ptr,
-                                 const char *key, size_t key_length,
-                                 const char *value, size_t value_length,
-                                 time_t expiration,
-                                 uint32_t flags)
-{
-  memcached_return_t rc;
-  LIBMEMCACHED_MEMCACHED_ADD_START();
-  rc= memcached_send(ptr, key, key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, ADD_OP);
-  LIBMEMCACHED_MEMCACHED_ADD_END();
-  return rc;
-}
-
-memcached_return_t memcached_replace(memcached_st *ptr,
-                                     const char *key, size_t key_length,
-                                     const char *value, size_t value_length,
-                                     time_t expiration,
-                                     uint32_t flags)
-{
-  memcached_return_t rc;
-  LIBMEMCACHED_MEMCACHED_REPLACE_START();
-  rc= memcached_send(ptr, key, key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, REPLACE_OP);
-  LIBMEMCACHED_MEMCACHED_REPLACE_END();
-  return rc;
-}
-
-memcached_return_t memcached_prepend(memcached_st *ptr,
-                                     const char *key, size_t key_length,
-                                     const char *value, size_t value_length,
-                                     time_t expiration,
-                                     uint32_t flags)
-{
-  memcached_return_t rc;
-  rc= memcached_send(ptr, key, key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, PREPEND_OP);
-  return rc;
-}
-
-memcached_return_t memcached_append(memcached_st *ptr,
-                                    const char *key, size_t key_length,
-                                    const char *value, size_t value_length,
-                                    time_t expiration,
-                                    uint32_t flags)
-{
-  memcached_return_t rc;
-  rc= memcached_send(ptr, key, key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, APPEND_OP);
-  return rc;
-}
-
-memcached_return_t memcached_cas(memcached_st *ptr,
-                                 const char *key, size_t key_length,
-                                 const char *value, size_t value_length,
-                                 time_t expiration,
-                                 uint32_t flags,
-                                 uint64_t cas)
-{
-  memcached_return_t rc;
-  rc= memcached_send(ptr, key, key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, cas, CAS_OP);
-  return rc;
-}
-
-memcached_return_t memcached_set_by_key(memcached_st *ptr,
-                                        const char *group_key,
-                                        size_t group_key_length,
-                                        const char *key, size_t key_length,
-                                        const char *value, size_t value_length,
-                                        time_t expiration,
-                                        uint32_t flags)
-{
-  memcached_return_t rc;
-  LIBMEMCACHED_MEMCACHED_SET_START();
-  rc= memcached_send(ptr, group_key, group_key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, SET_OP);
-  LIBMEMCACHED_MEMCACHED_SET_END();
-  return rc;
-}
-
-memcached_return_t memcached_add_by_key(memcached_st *ptr,
-                                        const char *group_key, size_t group_key_length,
-                                        const char *key, size_t key_length,
-                                        const char *value, size_t value_length,
-                                        time_t expiration,
-                                        uint32_t flags)
-{
-  memcached_return_t rc;
-  LIBMEMCACHED_MEMCACHED_ADD_START();
-  rc= memcached_send(ptr, group_key, group_key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, ADD_OP);
-  LIBMEMCACHED_MEMCACHED_ADD_END();
-  return rc;
-}
-
-memcached_return_t memcached_replace_by_key(memcached_st *ptr,
-                                            const char *group_key, size_t group_key_length,
-                                            const char *key, size_t key_length,
-                                            const char *value, size_t value_length,
-                                            time_t expiration,
-                                            uint32_t flags)
-{
-  memcached_return_t rc;
-  LIBMEMCACHED_MEMCACHED_REPLACE_START();
-  rc= memcached_send(ptr, group_key, group_key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, REPLACE_OP);
-  LIBMEMCACHED_MEMCACHED_REPLACE_END();
-  return rc;
-}
-
-memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
-                                            const char *group_key, size_t group_key_length,
-                                            const char *key, size_t key_length,
-                                            const char *value, size_t value_length,
-                                            time_t expiration,
-                                            uint32_t flags)
-{
-  memcached_return_t rc;
-  rc= memcached_send(ptr, group_key, group_key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, PREPEND_OP);
-  return rc;
-}
-
-memcached_return_t memcached_append_by_key(memcached_st *ptr,
-                                           const char *group_key, size_t group_key_length,
-                                           const char *key, size_t key_length,
-                                           const char *value, size_t value_length,
-                                           time_t expiration,
-                                           uint32_t flags)
-{
-  memcached_return_t rc;
-  rc= memcached_send(ptr, group_key, group_key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, APPEND_OP);
-  return rc;
-}
-
-memcached_return_t memcached_cas_by_key(memcached_st *ptr,
-                                        const char *group_key, size_t group_key_length,
-                                        const char *key, size_t key_length,
-                                        const char *value, size_t value_length,
-                                        time_t expiration,
-                                        uint32_t flags,
-                                        uint64_t cas)
-{
-  memcached_return_t rc;
-  rc= memcached_send(ptr, group_key, group_key_length,
-                     key, key_length, value, value_length,
-                     expiration, flags, cas, CAS_OP);
-  return rc;
-}
-
-static inline uint8_t get_com_code(memcached_storage_action_t verb, bool noreply)
-{
-  /* 0 isn't a value we want, but GCC 4.2 seems to think ret can otherwise
-   * be used uninitialized in this function. FAIL */
-  uint8_t ret= 0;
-
-  if (noreply)
-    switch (verb)
-    {
-    case SET_OP:
-      ret=PROTOCOL_BINARY_CMD_SETQ;
-      break;
-    case ADD_OP:
-      ret=PROTOCOL_BINARY_CMD_ADDQ;
-      break;
-    case CAS_OP: /* FALLTHROUGH */
-    case REPLACE_OP:
-      ret=PROTOCOL_BINARY_CMD_REPLACEQ;
-      break;
-    case APPEND_OP:
-      ret=PROTOCOL_BINARY_CMD_APPENDQ;
-      break;
-    case PREPEND_OP:
-      ret=PROTOCOL_BINARY_CMD_PREPENDQ;
-      break;
-    default:
-      WATCHPOINT_ASSERT(verb);
-      break;
-    }
-  else
-    switch (verb)
-    {
-    case SET_OP:
-      ret=PROTOCOL_BINARY_CMD_SET;
-      break;
-    case ADD_OP:
-      ret=PROTOCOL_BINARY_CMD_ADD;
-      break;
-    case CAS_OP: /* FALLTHROUGH */
-    case REPLACE_OP:
-      ret=PROTOCOL_BINARY_CMD_REPLACE;
-      break;
-    case APPEND_OP:
-      ret=PROTOCOL_BINARY_CMD_APPEND;
-      break;
-    case PREPEND_OP:
-      ret=PROTOCOL_BINARY_CMD_PREPEND;
-      break;
-    default:
-      WATCHPOINT_ASSERT(verb);
-      break;
-    }
-
-  return ret;
-}
-
-
-
-static memcached_return_t memcached_send_binary(memcached_st *ptr,
-                                                memcached_server_write_instance_st server,
-                                                uint32_t server_key,
-                                                const char *key,
-                                                size_t key_length,
-                                                const char *value,
-                                                size_t value_length,
-                                                time_t expiration,
-                                                uint32_t flags,
-                                                uint64_t cas,
-                                                memcached_storage_action_t verb)
-{
-  bool flush;
-  protocol_binary_request_set request= {.bytes= {0}};
-  size_t send_length= sizeof(request.bytes);
-
-  bool noreply= server->root->flags.no_reply;
-
-  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
-  request.message.header.request.opcode= get_com_code(verb, noreply);
-  request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
-  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-  if (verb == APPEND_OP || verb == PREPEND_OP)
-    send_length -= 8; /* append & prepend does not contain extras! */
-  else
-  {
-    request.message.header.request.extlen= 8;
-    request.message.body.flags= htonl(flags);
-    request.message.body.expiration= htonl((uint32_t)expiration);
-  }
-
-  request.message.header.request.bodylen= htonl((uint32_t) (key_length + memcached_array_size(ptr->prefix_key) + value_length +
-                                                            request.message.header.request.extlen));
-
-  if (cas)
-    request.message.header.request.cas= htonll(cas);
-
-  flush= (bool) ((server->root->flags.buffer_requests && verb == SET_OP) ? 0 : 1);
-
-  if (server->root->flags.use_udp && ! flush)
-  {
-    size_t cmd_size= send_length + key_length + value_length;
-
-    if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
-    {
-      return MEMCACHED_WRITE_FAILURE;
-    }
-    if (cmd_size + server->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
-    {
-      memcached_io_write(server, NULL, 0, true);
-    }
-  }
-
-  struct libmemcached_io_vector_st vector[]=
-  {
-    { .length= send_length, .buffer= request.bytes },
-    { .length= memcached_array_size(ptr->prefix_key), .buffer= memcached_array_string(ptr->prefix_key) },
-    { .length= key_length, .buffer= key },
-    { .length= value_length, .buffer= value }
-  };
-
-  /* write the header */
-  memcached_return_t rc;
-  if ((rc= memcached_vdo(server, vector, 4, flush)) != MEMCACHED_SUCCESS)
-  {
-    memcached_io_reset(server);
-    return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
-  }
-
-  if (verb == SET_OP && ptr->number_of_replicas > 0)
-  {
-    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
-    WATCHPOINT_STRING("replicating");
-
-    for (uint32_t x= 0; x < ptr->number_of_replicas; x++)
-    {
-      memcached_server_write_instance_st instance;
-
-      ++server_key;
-      if (server_key == memcached_server_count(ptr))
-        server_key= 0;
-
-      instance= memcached_server_instance_fetch(ptr, server_key);
-
-      if (memcached_vdo(instance, vector, 4, false) != MEMCACHED_SUCCESS)
-      {
-        memcached_io_reset(instance);
-      }
-      else
-      {
-        memcached_server_response_decrement(instance);
-      }
-    }
-  }
-
-  if (flush == false)
-  {
-    return MEMCACHED_BUFFERED;
-  }
-
-  if (noreply)
-  {
-    return MEMCACHED_SUCCESS;
-  }
-
-  return memcached_response(server, NULL, 0, NULL);
-}
-
diff --git a/libmemcached/storage.cc b/libmemcached/storage.cc
new file mode 100644 (file)
index 0000000..006393c
--- /dev/null
@@ -0,0 +1,569 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 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: Storage related functions, aka set, replace,..
+ *
+ */
+
+#include <libmemcached/common.h>
+
+enum memcached_storage_action_t {
+  SET_OP,
+  REPLACE_OP,
+  ADD_OP,
+  PREPEND_OP,
+  APPEND_OP,
+  CAS_OP
+};
+
+/* Inline this */
+static inline const char *storage_op_string(memcached_storage_action_t verb)
+{
+  switch (verb)
+  {
+  case SET_OP:
+    return "set ";
+  case REPLACE_OP:
+    return "replace ";
+  case ADD_OP:
+    return "add ";
+  case PREPEND_OP:
+    return "prepend ";
+  case APPEND_OP:
+    return "append ";
+  case CAS_OP:
+    return "cas ";
+  default:
+    return "tosserror"; /* This is impossible, fixes issue for compiler warning in VisualStudio */
+  }
+
+  /* NOTREACHED */
+}
+
+static memcached_return_t memcached_send_binary(memcached_st *ptr,
+                                                memcached_server_write_instance_st server,
+                                                uint32_t server_key,
+                                                const char *key,
+                                                size_t key_length,
+                                                const char *value,
+                                                size_t value_length,
+                                                time_t expiration,
+                                                uint32_t flags,
+                                                uint64_t cas,
+                                                memcached_storage_action_t verb);
+
+static inline memcached_return_t memcached_send(memcached_st *ptr,
+                                                const char *group_key, size_t group_key_length,
+                                                const char *key, size_t key_length,
+                                                const char *value, size_t value_length,
+                                                time_t expiration,
+                                                uint32_t flags,
+                                                uint64_t cas,
+                                                memcached_storage_action_t verb)
+{
+  bool to_write;
+  size_t write_length;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+  uint32_t server_key;
+  memcached_server_write_instance_st instance;
+
+  WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));
+
+  memcached_return_t rc;
+  if (memcached_failed(rc= initialize_query(ptr)))
+  {
+    return rc;
+  }
+
+  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
+    return rc;
+
+  if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+    return MEMCACHED_BAD_KEY_PROVIDED;
+
+  server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
+  instance= memcached_server_instance_fetch(ptr, server_key);
+
+  WATCHPOINT_SET(instance->io_wait_count.read= 0);
+  WATCHPOINT_SET(instance->io_wait_count.write= 0);
+
+  if (ptr->flags.binary_protocol)
+  {
+    rc= memcached_send_binary(ptr, instance, server_key,
+                              key, key_length,
+                              value, value_length, expiration,
+                              flags, cas, verb);
+    WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read);
+    WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write);
+  }
+  else
+  {
+
+    if (cas)
+    {
+      int check_length;
+      check_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                                    "%s %.*s%.*s %u %llu %lu %llu%s\r\n",
+                                    storage_op_string(verb),
+                                    memcached_print_array(ptr->prefix_key),
+                                    (int)key_length, key, flags,
+                                    (unsigned long long)expiration, (unsigned long)value_length,
+                                    (unsigned long long)cas,
+                                    (ptr->flags.no_reply) ? " noreply" : "");
+      if (check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || check_length < 0)
+      {
+        rc= MEMCACHED_WRITE_FAILURE;
+        memcached_io_reset(instance);
+
+        return rc;
+      }
+      write_length= check_length;
+    }
+    else
+    {
+      char *buffer_ptr= buffer;
+      const char *command= storage_op_string(verb);
+
+      /* Copy in the command, no space needed, we handle that in the command function*/
+      memcpy(buffer_ptr, command, strlen(command));
+
+      /* Copy in the key prefix, switch to the buffer_ptr */
+      buffer_ptr= (char *)memcpy((char *)(buffer_ptr + strlen(command)), (char *)memcached_array_string(ptr->prefix_key), memcached_array_size(ptr->prefix_key));
+
+      /* Copy in the key, adjust point if a key prefix was used. */
+      buffer_ptr= (char *)memcpy(buffer_ptr + memcached_array_size(ptr->prefix_key),
+                         key, key_length);
+      buffer_ptr+= key_length;
+      buffer_ptr[0]=  ' ';
+      buffer_ptr++;
+
+      write_length= (size_t)(buffer_ptr - buffer);
+      int check_length;
+      check_length= snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer),
+                                    "%u %llu %lu%s\r\n",
+                                    flags,
+                                    (unsigned long long)expiration, (unsigned long)value_length,
+                                    ptr->flags.no_reply ? " noreply" : "");
+      if ((size_t)check_length >= MEMCACHED_DEFAULT_COMMAND_SIZE -(size_t)(buffer_ptr - buffer) || check_length < 0)
+      {
+        rc= MEMCACHED_WRITE_FAILURE;
+        memcached_io_reset(instance);
+
+        return rc;
+      }
+
+      write_length+= (size_t)check_length;
+      WATCHPOINT_ASSERT(write_length < MEMCACHED_DEFAULT_COMMAND_SIZE);
+    }
+
+    if (ptr->flags.use_udp && ptr->flags.buffer_requests)
+    {
+      size_t cmd_size= write_length + value_length + 2;
+      if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+        return MEMCACHED_WRITE_FAILURE;
+      if (cmd_size + instance->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+        memcached_io_write(instance, NULL, 0, true);
+    }
+
+    if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
+    {
+      rc= MEMCACHED_WRITE_FAILURE;
+    }
+    else
+    {
+      struct libmemcached_io_vector_st vector[]=
+      {
+        { write_length, buffer },
+        { value_length, value },
+        { 2, "\r\n" }
+      };
+
+      if (ptr->flags.buffer_requests && verb == SET_OP)
+      {
+        to_write= false;
+      }
+      else
+      {
+        to_write= true;
+      }
+
+      /* Send command header */
+      rc=  memcached_vdo(instance, vector, 3, to_write);
+      if (rc == MEMCACHED_SUCCESS)
+      {
+
+        if (ptr->flags.no_reply)
+        {
+          rc= (to_write == false) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS;
+        }
+        else if (to_write == false)
+        {
+          rc= MEMCACHED_BUFFERED;
+        }
+        else
+        {
+          rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+          if (rc == MEMCACHED_STORED)
+            rc= MEMCACHED_SUCCESS;
+        }
+      }
+    }
+
+    if (rc == MEMCACHED_WRITE_FAILURE)
+      memcached_io_reset(instance);
+  }
+
+  WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.read > 2, "read IO_WAIT", instance->io_wait_count.read);
+  WATCHPOINT_IF_LABELED_NUMBER(instance->io_wait_count.write > 2, "write_IO_WAIT", instance->io_wait_count.write);
+
+  return rc;
+}
+
+
+memcached_return_t memcached_set(memcached_st *ptr, const char *key, size_t key_length,
+                                 const char *value, size_t value_length,
+                                 time_t expiration,
+                                 uint32_t flags)
+{
+  memcached_return_t rc;
+  LIBMEMCACHED_MEMCACHED_SET_START();
+  rc= memcached_send(ptr, key, key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, 0, SET_OP);
+  LIBMEMCACHED_MEMCACHED_SET_END();
+  return rc;
+}
+
+memcached_return_t memcached_add(memcached_st *ptr,
+                                 const char *key, size_t key_length,
+                                 const char *value, size_t value_length,
+                                 time_t expiration,
+                                 uint32_t flags)
+{
+  memcached_return_t rc;
+  LIBMEMCACHED_MEMCACHED_ADD_START();
+  rc= memcached_send(ptr, key, key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, 0, ADD_OP);
+  LIBMEMCACHED_MEMCACHED_ADD_END();
+  return rc;
+}
+
+memcached_return_t memcached_replace(memcached_st *ptr,
+                                     const char *key, size_t key_length,
+                                     const char *value, size_t value_length,
+                                     time_t expiration,
+                                     uint32_t flags)
+{
+  memcached_return_t rc;
+  LIBMEMCACHED_MEMCACHED_REPLACE_START();
+  rc= memcached_send(ptr, key, key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, 0, REPLACE_OP);
+  LIBMEMCACHED_MEMCACHED_REPLACE_END();
+  return rc;
+}
+
+memcached_return_t memcached_prepend(memcached_st *ptr,
+                                     const char *key, size_t key_length,
+                                     const char *value, size_t value_length,
+                                     time_t expiration,
+                                     uint32_t flags)
+{
+  memcached_return_t rc;
+  rc= memcached_send(ptr, key, key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, 0, PREPEND_OP);
+  return rc;
+}
+
+memcached_return_t memcached_append(memcached_st *ptr,
+                                    const char *key, size_t key_length,
+                                    const char *value, size_t value_length,
+                                    time_t expiration,
+                                    uint32_t flags)
+{
+  memcached_return_t rc;
+  rc= memcached_send(ptr, key, key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, 0, APPEND_OP);
+  return rc;
+}
+
+memcached_return_t memcached_cas(memcached_st *ptr,
+                                 const char *key, size_t key_length,
+                                 const char *value, size_t value_length,
+                                 time_t expiration,
+                                 uint32_t flags,
+                                 uint64_t cas)
+{
+  memcached_return_t rc;
+  rc= memcached_send(ptr, key, key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, cas, CAS_OP);
+  return rc;
+}
+
+memcached_return_t memcached_set_by_key(memcached_st *ptr,
+                                        const char *group_key,
+                                        size_t group_key_length,
+                                        const char *key, size_t key_length,
+                                        const char *value, size_t value_length,
+                                        time_t expiration,
+                                        uint32_t flags)
+{
+  memcached_return_t rc;
+  LIBMEMCACHED_MEMCACHED_SET_START();
+  rc= memcached_send(ptr, group_key, group_key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, 0, SET_OP);
+  LIBMEMCACHED_MEMCACHED_SET_END();
+  return rc;
+}
+
+memcached_return_t memcached_add_by_key(memcached_st *ptr,
+                                        const char *group_key, size_t group_key_length,
+                                        const char *key, size_t key_length,
+                                        const char *value, size_t value_length,
+                                        time_t expiration,
+                                        uint32_t flags)
+{
+  memcached_return_t rc;
+  LIBMEMCACHED_MEMCACHED_ADD_START();
+  rc= memcached_send(ptr, group_key, group_key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, 0, ADD_OP);
+  LIBMEMCACHED_MEMCACHED_ADD_END();
+  return rc;
+}
+
+memcached_return_t memcached_replace_by_key(memcached_st *ptr,
+                                            const char *group_key, size_t group_key_length,
+                                            const char *key, size_t key_length,
+                                            const char *value, size_t value_length,
+                                            time_t expiration,
+                                            uint32_t flags)
+{
+  memcached_return_t rc;
+  LIBMEMCACHED_MEMCACHED_REPLACE_START();
+  rc= memcached_send(ptr, group_key, group_key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, 0, REPLACE_OP);
+  LIBMEMCACHED_MEMCACHED_REPLACE_END();
+  return rc;
+}
+
+memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
+                                            const char *group_key, size_t group_key_length,
+                                            const char *key, size_t key_length,
+                                            const char *value, size_t value_length,
+                                            time_t expiration,
+                                            uint32_t flags)
+{
+  memcached_return_t rc;
+  rc= memcached_send(ptr, group_key, group_key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, 0, PREPEND_OP);
+  return rc;
+}
+
+memcached_return_t memcached_append_by_key(memcached_st *ptr,
+                                           const char *group_key, size_t group_key_length,
+                                           const char *key, size_t key_length,
+                                           const char *value, size_t value_length,
+                                           time_t expiration,
+                                           uint32_t flags)
+{
+  memcached_return_t rc;
+  rc= memcached_send(ptr, group_key, group_key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, 0, APPEND_OP);
+  return rc;
+}
+
+memcached_return_t memcached_cas_by_key(memcached_st *ptr,
+                                        const char *group_key, size_t group_key_length,
+                                        const char *key, size_t key_length,
+                                        const char *value, size_t value_length,
+                                        time_t expiration,
+                                        uint32_t flags,
+                                        uint64_t cas)
+{
+  memcached_return_t rc;
+  rc= memcached_send(ptr, group_key, group_key_length,
+                     key, key_length, value, value_length,
+                     expiration, flags, cas, CAS_OP);
+  return rc;
+}
+
+static inline uint8_t get_com_code(memcached_storage_action_t verb, bool noreply)
+{
+  /* 0 isn't a value we want, but GCC 4.2 seems to think ret can otherwise
+   * be used uninitialized in this function. FAIL */
+  uint8_t ret= 0;
+
+  if (noreply)
+    switch (verb)
+    {
+    case SET_OP:
+      ret=PROTOCOL_BINARY_CMD_SETQ;
+      break;
+    case ADD_OP:
+      ret=PROTOCOL_BINARY_CMD_ADDQ;
+      break;
+    case CAS_OP: /* FALLTHROUGH */
+    case REPLACE_OP:
+      ret=PROTOCOL_BINARY_CMD_REPLACEQ;
+      break;
+    case APPEND_OP:
+      ret=PROTOCOL_BINARY_CMD_APPENDQ;
+      break;
+    case PREPEND_OP:
+      ret=PROTOCOL_BINARY_CMD_PREPENDQ;
+      break;
+    default:
+      WATCHPOINT_ASSERT(verb);
+      break;
+    }
+  else
+    switch (verb)
+    {
+    case SET_OP:
+      ret=PROTOCOL_BINARY_CMD_SET;
+      break;
+    case ADD_OP:
+      ret=PROTOCOL_BINARY_CMD_ADD;
+      break;
+    case CAS_OP: /* FALLTHROUGH */
+    case REPLACE_OP:
+      ret=PROTOCOL_BINARY_CMD_REPLACE;
+      break;
+    case APPEND_OP:
+      ret=PROTOCOL_BINARY_CMD_APPEND;
+      break;
+    case PREPEND_OP:
+      ret=PROTOCOL_BINARY_CMD_PREPEND;
+      break;
+    default:
+      WATCHPOINT_ASSERT(verb);
+      break;
+    }
+
+  return ret;
+}
+
+
+
+static memcached_return_t memcached_send_binary(memcached_st *ptr,
+                                                memcached_server_write_instance_st server,
+                                                uint32_t server_key,
+                                                const char *key,
+                                                size_t key_length,
+                                                const char *value,
+                                                size_t value_length,
+                                                time_t expiration,
+                                                uint32_t flags,
+                                                uint64_t cas,
+                                                memcached_storage_action_t verb)
+{
+  bool flush;
+  protocol_binary_request_set request= {};
+  size_t send_length= sizeof(request.bytes);
+
+  bool noreply= server->root->flags.no_reply;
+
+  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+  request.message.header.request.opcode= get_com_code(verb, noreply);
+  request.message.header.request.keylen= htons((uint16_t)(key_length + memcached_array_size(ptr->prefix_key)));
+  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+  if (verb == APPEND_OP || verb == PREPEND_OP)
+    send_length -= 8; /* append & prepend does not contain extras! */
+  else
+  {
+    request.message.header.request.extlen= 8;
+    request.message.body.flags= htonl(flags);
+    request.message.body.expiration= htonl((uint32_t)expiration);
+  }
+
+  request.message.header.request.bodylen= htonl((uint32_t) (key_length + memcached_array_size(ptr->prefix_key) + value_length +
+                                                            request.message.header.request.extlen));
+
+  if (cas)
+    request.message.header.request.cas= htonll(cas);
+
+  flush= (bool) ((server->root->flags.buffer_requests && verb == SET_OP) ? 0 : 1);
+
+  if (server->root->flags.use_udp && ! flush)
+  {
+    size_t cmd_size= send_length + key_length + value_length;
+
+    if (cmd_size > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
+    {
+      return MEMCACHED_WRITE_FAILURE;
+    }
+    if (cmd_size + server->write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
+    {
+      memcached_io_write(server, NULL, 0, true);
+    }
+  }
+
+  struct libmemcached_io_vector_st vector[]=
+  {
+    { send_length, request.bytes },
+    { memcached_array_size(ptr->prefix_key), memcached_array_string(ptr->prefix_key) },
+    { key_length, key },
+    { value_length, value }
+  };
+
+  /* write the header */
+  memcached_return_t rc;
+  if ((rc= memcached_vdo(server, vector, 4, flush)) != MEMCACHED_SUCCESS)
+  {
+    memcached_io_reset(server);
+    return (rc == MEMCACHED_SUCCESS) ? MEMCACHED_WRITE_FAILURE : rc;
+  }
+
+  if (verb == SET_OP && ptr->number_of_replicas > 0)
+  {
+    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
+    WATCHPOINT_STRING("replicating");
+
+    for (uint32_t x= 0; x < ptr->number_of_replicas; x++)
+    {
+      memcached_server_write_instance_st instance;
+
+      ++server_key;
+      if (server_key == memcached_server_count(ptr))
+        server_key= 0;
+
+      instance= memcached_server_instance_fetch(ptr, server_key);
+
+      if (memcached_vdo(instance, vector, 4, false) != MEMCACHED_SUCCESS)
+      {
+        memcached_io_reset(instance);
+      }
+      else
+      {
+        memcached_server_response_decrement(instance);
+      }
+    }
+  }
+
+  if (flush == false)
+  {
+    return MEMCACHED_BUFFERED;
+  }
+
+  if (noreply)
+  {
+    return MEMCACHED_SUCCESS;
+  }
+
+  return memcached_response(server, NULL, 0, NULL);
+}
+
diff --git a/libmemcached/strerror.c b/libmemcached/strerror.c
deleted file mode 100644 (file)
index b3ac2b7..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-#include "common.h"
-
-const char *memcached_strerror(memcached_st *ptr, memcached_return_t rc)
-{
-  (void)ptr;
-  switch (rc)
-  {
-  case MEMCACHED_SUCCESS:
-    return "SUCCESS";
-  case MEMCACHED_FAILURE:
-    return "FAILURE";
-  case MEMCACHED_HOST_LOOKUP_FAILURE:
-    return "HOSTNAME LOOKUP FAILURE";
-  case MEMCACHED_CONNECTION_FAILURE:
-    return "CONNECTION FAILURE";
-  case MEMCACHED_CONNECTION_BIND_FAILURE:
-    return "CONNECTION BIND FAILURE";
-  case MEMCACHED_READ_FAILURE:
-    return "READ FAILURE";
-  case MEMCACHED_UNKNOWN_READ_FAILURE:
-    return "UNKNOWN READ FAILURE";
-  case MEMCACHED_PROTOCOL_ERROR:
-    return "PROTOCOL ERROR";
-  case MEMCACHED_CLIENT_ERROR:
-    return "CLIENT ERROR";
-  case MEMCACHED_SERVER_ERROR:
-    return "SERVER ERROR";
-  case MEMCACHED_WRITE_FAILURE:
-    return "WRITE FAILURE";
-  case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE:
-    return "CONNECTION SOCKET CREATE FAILURE";
-  case MEMCACHED_DATA_EXISTS:
-    return "CONNECTION DATA EXISTS";
-  case MEMCACHED_DATA_DOES_NOT_EXIST:
-    return "CONNECTION DATA DOES NOT EXIST";
-  case MEMCACHED_NOTSTORED:
-    return "NOT STORED";
-  case MEMCACHED_STORED:
-    return "STORED";
-  case MEMCACHED_NOTFOUND:
-    return "NOT FOUND";
-  case MEMCACHED_MEMORY_ALLOCATION_FAILURE:
-    return "MEMORY ALLOCATION FAILURE";
-  case MEMCACHED_PARTIAL_READ:
-    return "PARTIAL READ";
-  case MEMCACHED_SOME_ERRORS:
-    return "SOME ERRORS WERE REPORTED";
-  case MEMCACHED_NO_SERVERS:
-    return "NO SERVERS DEFINED";
-  case MEMCACHED_END:
-    return "SERVER END";
-  case MEMCACHED_DELETED:
-    return "SERVER DELETE";
-  case MEMCACHED_VALUE:
-    return "SERVER VALUE";
-  case MEMCACHED_STAT:
-    return "STAT VALUE";
-  case MEMCACHED_ITEM:
-    return "ITEM VALUE";
-  case MEMCACHED_ERRNO:
-    return "SYSTEM ERROR";
-  case MEMCACHED_FAIL_UNIX_SOCKET:
-    return "COULD NOT OPEN UNIX SOCKET";
-  case MEMCACHED_NOT_SUPPORTED:
-    return "ACTION NOT SUPPORTED";
-  case MEMCACHED_FETCH_NOTFINISHED:
-    return "FETCH WAS NOT COMPLETED";
-  case MEMCACHED_NO_KEY_PROVIDED:
-    return "A KEY LENGTH OF ZERO WAS PROVIDED";
-  case MEMCACHED_BUFFERED:
-    return "ACTION QUEUED";
-  case MEMCACHED_TIMEOUT:
-    return "A TIMEOUT OCCURRED";
-  case MEMCACHED_BAD_KEY_PROVIDED:
-    return "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE";
-  case MEMCACHED_INVALID_HOST_PROTOCOL:
-    return "THE HOST TRANSPORT PROTOCOL DOES NOT MATCH THAT OF THE CLIENT";
-  case MEMCACHED_SERVER_MARKED_DEAD:
-    return "SERVER IS MARKED DEAD";
-  case MEMCACHED_UNKNOWN_STAT_KEY:
-    return "ENCOUNTERED AN UNKNOWN STAT KEY";
-  case MEMCACHED_E2BIG:
-    return "ITEM TOO BIG";
-  case MEMCACHED_INVALID_ARGUMENTS:
-     return "INVALID ARGUMENTS";
-  case MEMCACHED_KEY_TOO_BIG:
-     return "KEY RETURNED FROM SERVER WAS TOO LARGE";
-  case MEMCACHED_AUTH_PROBLEM:
-    return "FAILED TO SEND AUTHENTICATION TO SERVER";
-  case MEMCACHED_AUTH_FAILURE:
-    return "AUTHENTICATION FAILURE";
-  case MEMCACHED_AUTH_CONTINUE:
-    return "CONTINUE AUTHENTICATION";
-  case MEMCACHED_PARSE_ERROR:
-    return "ERROR OCCURED WHILE PARSING";
-  case MEMCACHED_PARSE_USER_ERROR:
-    return "USER INITIATED ERROR OCCURED WHILE PARSING";
-  case MEMCACHED_DEPRECATED:
-    return "DEPRECATED";
-  case MEMCACHED_MAXIMUM_RETURN:
-    return "Gibberish returned!";
-  default:
-    return "Gibberish returned!";
-  }
-}
diff --git a/libmemcached/strerror.cc b/libmemcached/strerror.cc
new file mode 100644 (file)
index 0000000..b3ac2b7
--- /dev/null
@@ -0,0 +1,105 @@
+#include "common.h"
+
+const char *memcached_strerror(memcached_st *ptr, memcached_return_t rc)
+{
+  (void)ptr;
+  switch (rc)
+  {
+  case MEMCACHED_SUCCESS:
+    return "SUCCESS";
+  case MEMCACHED_FAILURE:
+    return "FAILURE";
+  case MEMCACHED_HOST_LOOKUP_FAILURE:
+    return "HOSTNAME LOOKUP FAILURE";
+  case MEMCACHED_CONNECTION_FAILURE:
+    return "CONNECTION FAILURE";
+  case MEMCACHED_CONNECTION_BIND_FAILURE:
+    return "CONNECTION BIND FAILURE";
+  case MEMCACHED_READ_FAILURE:
+    return "READ FAILURE";
+  case MEMCACHED_UNKNOWN_READ_FAILURE:
+    return "UNKNOWN READ FAILURE";
+  case MEMCACHED_PROTOCOL_ERROR:
+    return "PROTOCOL ERROR";
+  case MEMCACHED_CLIENT_ERROR:
+    return "CLIENT ERROR";
+  case MEMCACHED_SERVER_ERROR:
+    return "SERVER ERROR";
+  case MEMCACHED_WRITE_FAILURE:
+    return "WRITE FAILURE";
+  case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE:
+    return "CONNECTION SOCKET CREATE FAILURE";
+  case MEMCACHED_DATA_EXISTS:
+    return "CONNECTION DATA EXISTS";
+  case MEMCACHED_DATA_DOES_NOT_EXIST:
+    return "CONNECTION DATA DOES NOT EXIST";
+  case MEMCACHED_NOTSTORED:
+    return "NOT STORED";
+  case MEMCACHED_STORED:
+    return "STORED";
+  case MEMCACHED_NOTFOUND:
+    return "NOT FOUND";
+  case MEMCACHED_MEMORY_ALLOCATION_FAILURE:
+    return "MEMORY ALLOCATION FAILURE";
+  case MEMCACHED_PARTIAL_READ:
+    return "PARTIAL READ";
+  case MEMCACHED_SOME_ERRORS:
+    return "SOME ERRORS WERE REPORTED";
+  case MEMCACHED_NO_SERVERS:
+    return "NO SERVERS DEFINED";
+  case MEMCACHED_END:
+    return "SERVER END";
+  case MEMCACHED_DELETED:
+    return "SERVER DELETE";
+  case MEMCACHED_VALUE:
+    return "SERVER VALUE";
+  case MEMCACHED_STAT:
+    return "STAT VALUE";
+  case MEMCACHED_ITEM:
+    return "ITEM VALUE";
+  case MEMCACHED_ERRNO:
+    return "SYSTEM ERROR";
+  case MEMCACHED_FAIL_UNIX_SOCKET:
+    return "COULD NOT OPEN UNIX SOCKET";
+  case MEMCACHED_NOT_SUPPORTED:
+    return "ACTION NOT SUPPORTED";
+  case MEMCACHED_FETCH_NOTFINISHED:
+    return "FETCH WAS NOT COMPLETED";
+  case MEMCACHED_NO_KEY_PROVIDED:
+    return "A KEY LENGTH OF ZERO WAS PROVIDED";
+  case MEMCACHED_BUFFERED:
+    return "ACTION QUEUED";
+  case MEMCACHED_TIMEOUT:
+    return "A TIMEOUT OCCURRED";
+  case MEMCACHED_BAD_KEY_PROVIDED:
+    return "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE";
+  case MEMCACHED_INVALID_HOST_PROTOCOL:
+    return "THE HOST TRANSPORT PROTOCOL DOES NOT MATCH THAT OF THE CLIENT";
+  case MEMCACHED_SERVER_MARKED_DEAD:
+    return "SERVER IS MARKED DEAD";
+  case MEMCACHED_UNKNOWN_STAT_KEY:
+    return "ENCOUNTERED AN UNKNOWN STAT KEY";
+  case MEMCACHED_E2BIG:
+    return "ITEM TOO BIG";
+  case MEMCACHED_INVALID_ARGUMENTS:
+     return "INVALID ARGUMENTS";
+  case MEMCACHED_KEY_TOO_BIG:
+     return "KEY RETURNED FROM SERVER WAS TOO LARGE";
+  case MEMCACHED_AUTH_PROBLEM:
+    return "FAILED TO SEND AUTHENTICATION TO SERVER";
+  case MEMCACHED_AUTH_FAILURE:
+    return "AUTHENTICATION FAILURE";
+  case MEMCACHED_AUTH_CONTINUE:
+    return "CONTINUE AUTHENTICATION";
+  case MEMCACHED_PARSE_ERROR:
+    return "ERROR OCCURED WHILE PARSING";
+  case MEMCACHED_PARSE_USER_ERROR:
+    return "USER INITIATED ERROR OCCURED WHILE PARSING";
+  case MEMCACHED_DEPRECATED:
+    return "DEPRECATED";
+  case MEMCACHED_MAXIMUM_RETURN:
+    return "Gibberish returned!";
+  default:
+    return "Gibberish returned!";
+  }
+}
diff --git a/libmemcached/string.c b/libmemcached/string.c
deleted file mode 100644 (file)
index b5badc5..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 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: String structure used for libmemcached.
- *
- */
-
-#include "common.h"
-
-inline static memcached_return_t _string_check(memcached_string_st *string, size_t need)
-{
-  if (need && need > (size_t)(string->current_size - (size_t)(string->end - string->string)))
-  {
-    size_t current_offset= (size_t) (string->end - string->string);
-    char *new_value;
-    size_t adjust;
-    size_t new_size;
-
-    /* This is the block multiplier. To keep it larger and surive division errors we must round it up */
-    adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / MEMCACHED_BLOCK_SIZE;
-    adjust++;
-
-    new_size= sizeof(char) * (size_t)((adjust * MEMCACHED_BLOCK_SIZE) + string->current_size);
-    /* Test for overflow */
-    if (new_size < need)
-      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-    new_value= libmemcached_realloc(string->root, string->string, new_size);
-
-    if (new_value == NULL)
-    {
-      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-    }
-
-    string->string= new_value;
-    string->end= string->string + current_offset;
-
-    string->current_size+= (MEMCACHED_BLOCK_SIZE * adjust);
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-static inline void _init_string(memcached_string_st *self)
-{
-  self->current_size= 0;
-  self->end= self->string= NULL;
-}
-
-memcached_string_st *memcached_string_create(const memcached_st *memc, memcached_string_st *self, size_t initial_size)
-{
-  memcached_return_t rc;
-
-  WATCHPOINT_ASSERT(memc);
-
-  /* Saving malloc calls :) */
-  if (self)
-  {
-    WATCHPOINT_ASSERT(self->options.is_initialized == false);
-
-    self->options.is_allocated= false;
-  }
-  else
-  {
-    self= libmemcached_malloc(memc, sizeof(memcached_string_st));
-
-    if (self == NULL)
-    {
-      return NULL;
-    }
-
-    self->options.is_allocated= true;
-  }
-  self->root= (memcached_st *)memc;
-
-  _init_string(self);
-
-  rc=  _string_check(self, initial_size);
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
-    {
-      memcached_set_errno(self->root, errno, NULL);
-    }
-    libmemcached_free(memc, self);
-
-    return NULL;
-  }
-
-  self->options.is_initialized= true;
-
-  WATCHPOINT_ASSERT(self->string == self->end);
-
-  return self;
-}
-
-memcached_return_t memcached_string_append_character(memcached_string_st *string,
-                                                     char character)
-{
-  memcached_return_t rc;
-
-  rc=  _string_check(string, 1);
-
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  *string->end= character;
-  string->end++;
-
-  return MEMCACHED_SUCCESS;
-}
-
-memcached_return_t memcached_string_append(memcached_string_st *string,
-                                           const char *value, size_t length)
-{
-  memcached_return_t rc;
-
-  rc= _string_check(string, length);
-
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  WATCHPOINT_ASSERT(length <= string->current_size);
-  WATCHPOINT_ASSERT(string->string);
-  WATCHPOINT_ASSERT(string->end >= string->string);
-
-  memcpy(string->end, value, length);
-  string->end+= length;
-
-  return MEMCACHED_SUCCESS;
-}
-
-char *memcached_string_c_copy(memcached_string_st *string)
-{
-  char *c_ptr;
-
-  if (memcached_string_length(string) == 0)
-    return NULL;
-
-  c_ptr= libmemcached_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char));
-
-  if (c_ptr == NULL)
-    return NULL;
-
-  memcpy(c_ptr, memcached_string_value(string), memcached_string_length(string));
-  c_ptr[memcached_string_length(string)]= 0;
-
-  return c_ptr;
-}
-
-memcached_return_t memcached_string_reset(memcached_string_st *string)
-{
-  string->end= string->string;
-
-  return MEMCACHED_SUCCESS;
-}
-
-void memcached_string_free(memcached_string_st *ptr)
-{
-  if (ptr == NULL)
-    return;
-
-  if (ptr->string)
-  {
-    libmemcached_free(ptr->root, ptr->string);
-  }
-
-  if (memcached_is_allocated(ptr))
-  {
-    libmemcached_free(ptr->root, ptr);
-  }
-  else
-  {
-    ptr->options.is_initialized= false;
-  }
-}
-
-memcached_return_t memcached_string_check(memcached_string_st *string, size_t need)
-{
-  return _string_check(string, need);
-}
-
-size_t memcached_string_length(const memcached_string_st *self)
-{
-  return (size_t)(self->end - self->string);
-}
-
-size_t memcached_string_size(const memcached_string_st *self)
-{
-  return self->current_size;
-}
-
-const char *memcached_string_value(const memcached_string_st *self)
-{
-  return self->string;
-}
-
-char *memcached_string_value_mutable(const memcached_string_st *self)
-{
-  return self->string;
-}
-
-void memcached_string_set_length(memcached_string_st *self, size_t length)
-{
-  self->end= self->string + length;
-}
diff --git a/libmemcached/string.cc b/libmemcached/string.cc
new file mode 100644 (file)
index 0000000..4f01279
--- /dev/null
@@ -0,0 +1,241 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 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>
+
+inline static memcached_return_t _string_check(memcached_string_st *string, size_t need)
+{
+  if (need && need > (size_t)(string->current_size - (size_t)(string->end - string->string)))
+  {
+    size_t current_offset= (size_t) (string->end - string->string);
+    char *new_value;
+    size_t adjust;
+    size_t new_size;
+
+    /* This is the block multiplier. To keep it larger and surive division errors we must round it up */
+    adjust= (need - (size_t)(string->current_size - (size_t)(string->end - string->string))) / MEMCACHED_BLOCK_SIZE;
+    adjust++;
+
+    new_size= sizeof(char) * (size_t)((adjust * MEMCACHED_BLOCK_SIZE) + string->current_size);
+    /* Test for overflow */
+    if (new_size < need)
+      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+    new_value= static_cast<char *>(libmemcached_realloc(string->root, string->string, new_size));
+
+    if (new_value == NULL)
+    {
+      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+    }
+
+    string->string= new_value;
+    string->end= string->string + current_offset;
+
+    string->current_size+= (MEMCACHED_BLOCK_SIZE * adjust);
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+static inline void _init_string(memcached_string_st *self)
+{
+  self->current_size= 0;
+  self->end= self->string= NULL;
+}
+
+memcached_string_st *memcached_string_create(const memcached_st *memc, memcached_string_st *self, size_t initial_size)
+{
+  memcached_return_t rc;
+
+  WATCHPOINT_ASSERT(memc);
+
+  /* Saving malloc calls :) */
+  if (self)
+  {
+    WATCHPOINT_ASSERT(self->options.is_initialized == false);
+
+    self->options.is_allocated= false;
+  }
+  else
+  {
+    self= static_cast<memcached_string_st *>(libmemcached_malloc(memc, sizeof(memcached_string_st)));
+
+    if (self == NULL)
+    {
+      return NULL;
+    }
+
+    self->options.is_allocated= true;
+  }
+  self->root= const_cast<memcached_st *>(memc);
+
+  _init_string(self);
+
+  rc=  _string_check(self, initial_size);
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    if (rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
+    {
+      memcached_set_errno(self->root, errno, NULL);
+    }
+    libmemcached_free(memc, self);
+
+    return NULL;
+  }
+
+  self->options.is_initialized= true;
+
+  WATCHPOINT_ASSERT(self->string == self->end);
+
+  return self;
+}
+
+memcached_return_t memcached_string_append_character(memcached_string_st *string,
+                                                     char character)
+{
+  memcached_return_t rc;
+
+  rc=  _string_check(string, 1);
+
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    return rc;
+  }
+
+  *string->end= character;
+  string->end++;
+
+  return MEMCACHED_SUCCESS;
+}
+
+memcached_return_t memcached_string_append(memcached_string_st *string,
+                                           const char *value, size_t length)
+{
+  memcached_return_t rc;
+
+  rc= _string_check(string, length);
+
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    return rc;
+  }
+
+  WATCHPOINT_ASSERT(length <= string->current_size);
+  WATCHPOINT_ASSERT(string->string);
+  WATCHPOINT_ASSERT(string->end >= string->string);
+
+  memcpy(string->end, value, length);
+  string->end+= length;
+
+  return MEMCACHED_SUCCESS;
+}
+
+char *memcached_string_c_copy(memcached_string_st *string)
+{
+  char *c_ptr;
+
+  if (memcached_string_length(string) == 0)
+    return NULL;
+
+  c_ptr= static_cast<char *>(libmemcached_malloc(string->root, (memcached_string_length(string)+1) * sizeof(char)));
+
+  if (c_ptr == NULL)
+    return NULL;
+
+  memcpy(c_ptr, memcached_string_value(string), memcached_string_length(string));
+  c_ptr[memcached_string_length(string)]= 0;
+
+  return c_ptr;
+}
+
+memcached_return_t memcached_string_reset(memcached_string_st *string)
+{
+  string->end= string->string;
+
+  return MEMCACHED_SUCCESS;
+}
+
+void memcached_string_free(memcached_string_st *ptr)
+{
+  if (ptr == NULL)
+    return;
+
+  if (ptr->string)
+  {
+    libmemcached_free(ptr->root, ptr->string);
+  }
+
+  if (memcached_is_allocated(ptr))
+  {
+    libmemcached_free(ptr->root, ptr);
+  }
+  else
+  {
+    ptr->options.is_initialized= false;
+  }
+}
+
+memcached_return_t memcached_string_check(memcached_string_st *string, size_t need)
+{
+  return _string_check(string, need);
+}
+
+size_t memcached_string_length(const memcached_string_st *self)
+{
+  return (size_t)(self->end - self->string);
+}
+
+size_t memcached_string_size(const memcached_string_st *self)
+{
+  return self->current_size;
+}
+
+const char *memcached_string_value(const memcached_string_st *self)
+{
+  return self->string;
+}
+
+char *memcached_string_value_mutable(const memcached_string_st *self)
+{
+  return self->string;
+}
+
+void memcached_string_set_length(memcached_string_st *self, size_t length)
+{
+  self->end= self->string + length;
+}
index ca3dad14faa64e2601c652b1f98b624a26df69b6..8c57c8b0d2c9c7399862ed7acced698b41d1bf30 100644 (file)
@@ -1,17 +1,41 @@
-/* LibMemcached
- * Copyright (C) 2006-2009 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 Brian Aker All rights reserved.
  *
- * Summary: String structure used for libmemcached.
+ *  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.
  *
  */
 
 #pragma once
-#ifndef __LIBMEMCACHED_STRING_H__
-#define __LIBMEMCACHED_STRING_H__
 
 /**
   Strings are always under our control so we make some assumptions
@@ -97,5 +121,3 @@ void memcached_string_set_length(memcached_string_st *self, size_t length);
 #define memcached_string_make_from_cstr(X) (X), ((X) ? strlen(X) : 0)
 
 #endif
-
-#endif /* __LIBMEMCACHED_STRING_H__ */
index 2ebb8c00eb707d57b0e3e0faefa74f2fe030d6af..b3d8f4791f9c2a54a21a937cc3422208ebafc5ee 100644 (file)
@@ -9,6 +9,7 @@
  *
  */
 
+#pragma once
 #ifndef __LIBMEMCACHED_TYPES_H__
 #define __LIBMEMCACHED_TYPES_H__
 
diff --git a/libmemcached/util/include.am b/libmemcached/util/include.am
new file mode 100644 (file)
index 0000000..2c452f5
--- /dev/null
@@ -0,0 +1,32 @@
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+
+if BUILD_LIBMEMCACHEDUTIL
+nobase_include_HEADERS+= \
+                        libmemcached/memcached_util.h \
+                        libmemcached/util.h \
+                        libmemcached/util/ping.h \
+                        libmemcached/util/pool.h \
+                        libmemcached/util/version.h
+lib_LTLIBRARIES+= libmemcached/libmemcachedutil.la
+endif
+
+libmemcached_libmemcachedutil_la_SOURCES= \
+                                         libmemcached/util/ping.cc \
+                                         libmemcached/util/pool.cc \
+                                         libmemcached/util/version.cc
+libmemcached_libmemcachedutil_la_CFLAGS= \
+                                        ${AM_CFLAGS} \
+                                        ${NO_CONVERSION} \
+                                        ${PTHREAD_CFLAGS} \
+                                        -DBUILDING_LIBMEMCACHED
+libmemcached_libmemcachedutil_la_CXXFLAGS= \
+                                          ${AM_CXXFLAGS} \
+                                          ${NO_CONVERSION} \
+                                          ${PTHREAD_CFLAGS} \
+                                          -DBUILDING_LIBMEMCACHED
+libmemcached_libmemcachedutil_la_LIBADD= libmemcached/libmemcached.la
+libmemcached_libmemcachedutil_la_LDFLAGS= ${AM_LDFLAGS} ${PTHREAD_LIBS} -version-info ${MEMCACHED_UTIL_LIBRARY_VERSION}
+libmemcached_libmemcachedutil_la_DEPENDENCIES= libmemcached/libmemcached.la
+
index 761cbbf576fddd82c6767f44fd83fd814eb0a39e..a82082986fa1decd70cc8cdd598980feadd21fd0 100644 (file)
@@ -1,17 +1,43 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
  *
- * Summary: connect to all hosts, and make sure they meet a minimum version
+ *  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.
  *
  */
 
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/common.h"
-#include "libmemcached/memcached_util.h"
+
+#include <libmemcached/common.h>
+#include <libmemcached/memcached_util.h>
 
 struct local_context
 {
@@ -48,14 +74,12 @@ bool libmemcached_util_version_check(memcached_st *memc,
                                      uint8_t minor_version,
                                      uint8_t micro_version)
 {
-  memcached_server_fn callbacks[1];
-  memcached_return_t rc= memcached_version(memc);
-
-  if (rc != MEMCACHED_SUCCESS)
+  if (memcached_version(memc) != MEMCACHED_SUCCESS)
     return false;
 
   struct local_context check= { major_version, minor_version, micro_version, true };
 
+  memcached_server_fn callbacks[1];
   callbacks[0]= check_server_version;
   memcached_server_cursor(memc, callbacks, (void *)&check,  1);
 
diff --git a/libmemcached/verbosity.c b/libmemcached/verbosity.c
deleted file mode 100644 (file)
index d71fced..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#include "common.h"
-
-struct context_st
-{
-  size_t length;
-  const char *buffer;
-};
-
-static memcached_return_t _set_verbosity(const memcached_st *ptr,
-                                         const memcached_server_st *server,
-                                         void *context)
-{
-  memcached_return_t rc;
-  memcached_st local_memc;
-  memcached_st *memc_ptr;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
-  struct context_st *execute= (struct context_st *)context;
-  (void)ptr;
-
-  memc_ptr= memcached_create(&local_memc);
-
-  rc= memcached_server_add(memc_ptr, memcached_server_name(server), memcached_server_port(server));
-
-  if (rc == MEMCACHED_SUCCESS)
-  {
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(memc_ptr, 0);
-
-    rc= memcached_do(instance, execute->buffer, execute->length, true);
-
-    if (rc == MEMCACHED_SUCCESS)
-    {
-      rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-    }
-  }
-
-  memcached_free(memc_ptr);
-
-  return rc;
-}
-
-memcached_return_t memcached_verbosity(memcached_st *ptr, uint32_t verbosity)
-{
-  int send_length;
-  memcached_server_fn callbacks[1];
-
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
-  send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                                 "verbosity %u\r\n", verbosity);
-  if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
-    return MEMCACHED_WRITE_FAILURE;
-
-  struct context_st context = { .length= (size_t)send_length, .buffer= buffer };
-
-  callbacks[0]= _set_verbosity;
-
-  return memcached_server_cursor(ptr, callbacks, &context, 1);
-}
diff --git a/libmemcached/verbosity.cc b/libmemcached/verbosity.cc
new file mode 100644 (file)
index 0000000..ec00b8d
--- /dev/null
@@ -0,0 +1,97 @@
+/*  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>
+
+struct context_st
+{
+  size_t length;
+  const char *buffer;
+};
+
+static memcached_return_t _set_verbosity(const memcached_st *ptr,
+                                         const memcached_server_st *server,
+                                         void *context)
+{
+  memcached_return_t rc;
+  memcached_st local_memc;
+  memcached_st *memc_ptr;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+  struct context_st *execute= (struct context_st *)context;
+  (void)ptr;
+
+  memc_ptr= memcached_create(&local_memc);
+
+  rc= memcached_server_add(memc_ptr, memcached_server_name(server), memcached_server_port(server));
+
+  if (rc == MEMCACHED_SUCCESS)
+  {
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(memc_ptr, 0);
+
+    rc= memcached_do(instance, execute->buffer, execute->length, true);
+
+    if (rc == MEMCACHED_SUCCESS)
+    {
+      rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+    }
+  }
+
+  memcached_free(memc_ptr);
+
+  return rc;
+}
+
+memcached_return_t memcached_verbosity(memcached_st *ptr, uint32_t verbosity)
+{
+  int send_length;
+  memcached_server_fn callbacks[1];
+
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+  send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                                 "verbosity %u\r\n", verbosity);
+  if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE || send_length < 0)
+    return MEMCACHED_WRITE_FAILURE;
+
+  struct context_st context = { (size_t)send_length, buffer };
+
+  callbacks[0]= _set_verbosity;
+
+  return memcached_server_cursor(ptr, callbacks, &context, 1);
+}
index b28458e43bb3416c458202998610be6909ff01bd..29946486ff23ce8ef096520cfde6235c62714219 100644 (file)
@@ -1,16 +1,41 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
  *
- * Summary: Change the verbository level of the memcached server
+ *  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.
  *
  */
 
-#ifndef __LIBMEMCACHED_VERBOSITY_H__
-#define __LIBMEMCACHED_VERBOSITY_H__
+#pragma once
 
 #ifdef __cplusplus
 extern "C" {
@@ -23,5 +48,3 @@ memcached_return_t memcached_verbosity(memcached_st *ptr, uint32_t verbosity);
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __LIBMEMCACHED_VERBOSITY_H__ */
diff --git a/libmemcached/version.c b/libmemcached/version.c
deleted file mode 100644 (file)
index 82de87d..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-#include "common.h"
-
-const char * memcached_lib_version(void) 
-{
-  return LIBMEMCACHED_VERSION_STRING;
-}
-
-static inline memcached_return_t memcached_version_binary(memcached_st *ptr);
-static inline memcached_return_t memcached_version_textual(memcached_st *ptr);
-
-memcached_return_t memcached_version(memcached_st *ptr)
-{
-  if (ptr->flags.use_udp)
-    return MEMCACHED_NOT_SUPPORTED;
-
-  memcached_return_t rc;
-
-  if (ptr->flags.binary_protocol)
-    rc= memcached_version_binary(ptr);
-  else
-    rc= memcached_version_textual(ptr);      
-
-  return rc;
-}
-
-static inline memcached_return_t memcached_version_textual(memcached_st *ptr)
-{
-  size_t send_length;
-  memcached_return_t rc;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  char *response_ptr;
-  const char *command= "version\r\n";
-
-  send_length= sizeof("version\r\n") -1;
-
-  rc= MEMCACHED_SUCCESS;
-  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
-  {
-    memcached_return_t rrc;
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(ptr, x);
-
-    // Optimization, we only fetch version once.
-    if (instance->major_version != UINT8_MAX)
-      continue;
-
-    rrc= memcached_do(instance, command, send_length, true);
-    if (rrc != MEMCACHED_SUCCESS)
-    {
-      instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-
-    rrc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-    if (rrc != MEMCACHED_SUCCESS)
-    {
-      instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-
-    /* Find the space, and then move one past it to copy version */
-    response_ptr= index(buffer, ' ');
-    response_ptr++;
-
-    instance->major_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
-    if (errno == ERANGE)
-    {
-      instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-
-    response_ptr= index(response_ptr, '.');
-    response_ptr++;
-
-    instance->minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
-    if (errno == ERANGE)
-    {
-      instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-
-    response_ptr= index(response_ptr, '.');
-    response_ptr++;
-    instance->micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
-    if (errno == ERANGE)
-    {
-      instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-  }
-
-  return rc;
-}
-
-static inline memcached_return_t memcached_version_binary(memcached_st *ptr)
-{
-  memcached_return_t rc;
-  protocol_binary_request_version request= { .bytes= {0}};
-  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
-  request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION;
-  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-
-  rc= MEMCACHED_SUCCESS;
-  for (uint32_t x= 0; x < memcached_server_count(ptr); x++) 
-  {
-    memcached_return_t rrc;
-
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(ptr, x);
-
-    if (instance->major_version != UINT8_MAX)
-      continue;
-
-    rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true);
-    if (rrc != MEMCACHED_SUCCESS) 
-    {
-      memcached_io_reset(instance);
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-  }
-
-  for (uint32_t x= 0; x < memcached_server_count(ptr); x++) 
-  {
-    memcached_server_write_instance_st instance=
-      memcached_server_instance_fetch(ptr, x);
-
-    if (instance->major_version != UINT8_MAX)
-      continue;
-
-    if (memcached_server_response_count(instance) > 0) 
-    {
-      memcached_return_t rrc;
-      char buffer[32];
-      char *p;
-
-      rrc= memcached_response(instance, buffer, sizeof(buffer), NULL);
-      if (rrc != MEMCACHED_SUCCESS) 
-      {
-        memcached_io_reset(instance);
-        rc= MEMCACHED_SOME_ERRORS;
-        continue;
-      }
-
-      instance->major_version= (uint8_t)strtol(buffer, &p, 10);
-      if (errno == ERANGE)
-      {
-        instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
-        rc= MEMCACHED_SOME_ERRORS;
-        continue;
-      }
-
-      instance->minor_version= (uint8_t)strtol(p + 1, &p, 10);
-      if (errno == ERANGE)
-      {
-        instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
-        rc= MEMCACHED_SOME_ERRORS;
-        continue;
-      }
-
-      instance->micro_version= (uint8_t)strtol(p + 1, NULL, 10);
-      if (errno == ERANGE)
-      {
-        instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
-        rc= MEMCACHED_SOME_ERRORS;
-        continue;
-      }
-
-    }
-  }
-
-  return rc;
-}
diff --git a/libmemcached/version.cc b/libmemcached/version.cc
new file mode 100644 (file)
index 0000000..abb7200
--- /dev/null
@@ -0,0 +1,214 @@
+/*  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>
+
+const char * memcached_lib_version(void) 
+{
+  return LIBMEMCACHED_VERSION_STRING;
+}
+
+static inline memcached_return_t memcached_version_binary(memcached_st *ptr);
+static inline memcached_return_t memcached_version_textual(memcached_st *ptr);
+
+memcached_return_t memcached_version(memcached_st *ptr)
+{
+  if (ptr->flags.use_udp)
+    return MEMCACHED_NOT_SUPPORTED;
+
+  memcached_return_t rc;
+
+  if (ptr->flags.binary_protocol)
+    rc= memcached_version_binary(ptr);
+  else
+    rc= memcached_version_textual(ptr);      
+
+  return rc;
+}
+
+static inline memcached_return_t memcached_version_textual(memcached_st *ptr)
+{
+  size_t send_length;
+  memcached_return_t rc;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+  char *response_ptr;
+  const char *command= "version\r\n";
+
+  send_length= sizeof("version\r\n") -1;
+
+  rc= MEMCACHED_SUCCESS;
+  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_return_t rrc;
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    // Optimization, we only fetch version once.
+    if (instance->major_version != UINT8_MAX)
+      continue;
+
+    rrc= memcached_do(instance, command, send_length, true);
+    if (rrc != MEMCACHED_SUCCESS)
+    {
+      instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+
+    rrc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+    if (rrc != MEMCACHED_SUCCESS)
+    {
+      instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+
+    /* Find the space, and then move one past it to copy version */
+    response_ptr= index(buffer, ' ');
+    response_ptr++;
+
+    instance->major_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
+    if (errno == ERANGE)
+    {
+      instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+
+    response_ptr= index(response_ptr, '.');
+    response_ptr++;
+
+    instance->minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
+    if (errno == ERANGE)
+    {
+      instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+
+    response_ptr= index(response_ptr, '.');
+    response_ptr++;
+    instance->micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
+    if (errno == ERANGE)
+    {
+      instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+  }
+
+  return rc;
+}
+
+static inline memcached_return_t memcached_version_binary(memcached_st *ptr)
+{
+  memcached_return_t rc;
+  protocol_binary_request_version request= {};
+  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+  request.message.header.request.opcode= PROTOCOL_BINARY_CMD_VERSION;
+  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+
+  rc= MEMCACHED_SUCCESS;
+  for (uint32_t x= 0; x < memcached_server_count(ptr); x++) 
+  {
+    memcached_return_t rrc;
+
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    if (instance->major_version != UINT8_MAX)
+      continue;
+
+    rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true);
+    if (rrc != MEMCACHED_SUCCESS) 
+    {
+      memcached_io_reset(instance);
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+  }
+
+  for (uint32_t x= 0; x < memcached_server_count(ptr); x++) 
+  {
+    memcached_server_write_instance_st instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    if (instance->major_version != UINT8_MAX)
+      continue;
+
+    if (memcached_server_response_count(instance) > 0) 
+    {
+      memcached_return_t rrc;
+      char buffer[32];
+      char *p;
+
+      rrc= memcached_response(instance, buffer, sizeof(buffer), NULL);
+      if (rrc != MEMCACHED_SUCCESS) 
+      {
+        memcached_io_reset(instance);
+        rc= MEMCACHED_SOME_ERRORS;
+        continue;
+      }
+
+      instance->major_version= (uint8_t)strtol(buffer, &p, 10);
+      if (errno == ERANGE)
+      {
+        instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+        rc= MEMCACHED_SOME_ERRORS;
+        continue;
+      }
+
+      instance->minor_version= (uint8_t)strtol(p + 1, &p, 10);
+      if (errno == ERANGE)
+      {
+        instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+        rc= MEMCACHED_SOME_ERRORS;
+        continue;
+      }
+
+      instance->micro_version= (uint8_t)strtol(p + 1, NULL, 10);
+      if (errno == ERANGE)
+      {
+        instance->major_version= instance->minor_version= instance->micro_version= UINT8_MAX;
+        rc= MEMCACHED_SOME_ERRORS;
+        continue;
+      }
+
+    }
+  }
+
+  return rc;
+}
index 7e6f607aa48591dc43c69bc595a603ffffe70cfb..c443accb54c12bc6fa644dac85d8303e04d0cccd 100644 (file)
@@ -1,16 +1,41 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
  *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
  *
- * Summary: Find version information
+ *  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.
  *
  */
 
-#ifndef __LIBMEMCACHED_VERSION_H__
-#define __LIBMEMCACHED_VERSION_H__
+#pragma once
 
 #ifdef __cplusplus
 extern "C" {
@@ -25,5 +50,3 @@ const char * memcached_lib_version(void);
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __LIBMEMCACHED_VERSION_H__ */
index 7d9af058f5fc2efebe376cbb971aa8fed095943b..646806ac94d8bf588a64a4e5256c32758d368004 100644 (file)
@@ -16,8 +16,7 @@
  * @brief Visibility control macros
  */
 
-#ifndef __LIBMEMCACHED_VISIBILITY_H__
-#define __LIBMEMCACHED_VISIBILITY_H__
+#pragma once
 
 /**
  *
@@ -50,5 +49,3 @@
 #  define LIBMEMCACHED_LOCAL
 # endif /* defined(_MSC_VER) */
 #endif /* defined(BUILDING_LIBMEMCACHED) */
-
-#endif /* __LIBMEMCACHED_VISIBILITY_H__ */
index 9a79e4c5b4da94cc00903273b08f55bd21590a31..afb2b96522ce4c1f582e4fa6771c5c2bb2735c31 100644 (file)
@@ -24,8 +24,6 @@
 #include <time.h>
 #include <stdint.h>
 
-#include <libmemcached/memcached.h>
-
 #include <libtest/test.h>
 #include <libtest/failed.h>
 
@@ -370,9 +368,5 @@ cleanup:
 
   world_stats_print(&stats);
 
-#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
-  sasl_done();
-#endif
-
   return stats.failed == 0 ? 0 : 1;
 }
index 58d24373ea8d17e3cf40c5b34ad366f69883fff1..656be1698967f36f92c0d50b6aefbb5b99e4cee0 100644 (file)
@@ -217,6 +217,17 @@ do \
   } \
 } while (0)
 
+#define test_compare(A,B) \
+do \
+{ \
+  if ((A) != (B)) \
+  { \
+    fprintf(stderr, "\n%s:%d: Expected %lu == %lu\n", __FILE__, __LINE__, (unsigned long)(A), (unsigned long)(B)); \
+    create_core(); \
+    return TEST_FAILURE; \
+  } \
+} while (0)
+
 #define test_false(A) \
 do \
 { \
@@ -248,6 +259,16 @@ do \
   } \
 } while (0)
 
+#define test_memcmp(A,B,C) \
+do \
+{ \
+  if (memcmp((A), (B), (C))) \
+  { \
+    fprintf(stderr, "\n%s:%d: %.*s -> %.*s\n", __FILE__, __LINE__, (int)(C), (char *)(A), (int)(C), (char *)(B)); \
+    create_core(); \
+    return TEST_FAILURE; \
+  } \
+} while (0)
 
 #define STRINGIFY(x) #x
 #define TOSTRING(x) STRINGIFY(x)
index afdf0830782bb3c4468a3073cbf157c991616d7e..8563e4ec19e66bb4cf7c47de93839db3e80efac0 100644 (file)
@@ -26,8 +26,8 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <time.h>
-#include "../clients/generator.h"
-#include "../clients/execute.h"
+#include <clients/generator.h>
+#include <clients/execute.h>
 
 #include <libtest/server.h>
 #include <libtest/test.h>
index 140d28fcae35a49d7574c1aa57ad810cea504848..20cf79db0f4e0a7fe1535decf03ac38e3106f84d 100644 (file)
@@ -1,13 +1,16 @@
 /*
   C++ to libhashkit
 */
+
+#include <config.h>
+
 #include <libtest/test.h>
 
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
 
-#include <libhashkit/hashkit.h>
+#include <libhashkit/hashkit.hpp>
 
 #include "hash_results.h"
 
index 2a3e5cb8aa2524561f29faa478de341507db303c..44954b110ffe35d200c7b2dd9b0699dc1b2f72e7 100644 (file)
@@ -67,18 +67,23 @@ tests_testapp_SOURCES= \
 
 tests_testapp_DEPENDENCIES= \
                            $(BUILT_SOURCES) \
+                           $(TESTS_LDADDS) \
                            clients/libgenexec.la \
-                           libmemcached/libmemcachedinternal.la \
-                           $(TESTS_LDADDS)
+                           libhashkit/libhashkit.la \
+                           libmemcached/libmemcachedinternal.la
 
-tests_testapp_LDADD= clients/libgenexec.la \
-                    libmemcached/libmemcachedinternal.la \
-                    $(TESTS_LDADDS) $(LIBSASL)
+tests_testapp_LDADD= \
+                    $(LIBSASL) \
+                    $(TESTS_LDADDS) \
+                    clients/libgenexec.la \
+                    libhashkit/libhashkit.la \
+                    libmemcached/libmemcachedinternal.la
 
 tests_testplus_SOURCES= tests/plus.cpp
 tests_testplus_CXXFLAGS = $(AM_CXXFLAGS) $(NO_EFF_CXX)
 tests_testplus_DEPENDENCIES= $(TESTS_LDADDS)
 tests_testplus_LDADD= $(tests_testplus_DEPENDENCIES) $(LIBSASL)
+check_PROGRAMS+= tests/testplus
 
 tests_atomsmasher_SOURCES= tests/atomsmasher.c
 tests_atomsmasher_DEPENDENCIES= \
@@ -101,12 +106,12 @@ tests_startservers_LDADD= $(tests_startservers_DEPENDENCIES) $(LIBSASL)
 
 tests_testhashkit_SOURCES = tests/hashkit_functions.c
 tests_testhashkit_DEPENDENCIES = libtest/libtest.la libhashkit/libhashkit.la
-tests_testhashkit_LDADD = $(tests_testhashkit_DEPENDENCIES) $(LIBSASL)
+tests_testhashkit_LDADD = $(tests_testhashkit_DEPENDENCIES)
 
-tests_hash_plus_SOURCES = tests/hash_plus.cc
-tests_hash_plus_CXXFLAGS = $(AM_CXXFLAGS) $(NO_EFF_CXX)
-tests_hash_plus_DEPENDENCIES = $(tests_testhashkit_DEPENDENCIES)
-tests_hash_plus_LDADD = $(tests_testhashkit_DEPENDENCIES) $(LIBSASL)
+tests_hash_plus_SOURCES= tests/hash_plus.cc
+tests_hash_plus_CXXFLAGS= $(AM_CXXFLAGS) $(NO_EFF_CXX)
+tests_hash_plus_DEPENDENCIES= $(tests_testhashkit_DEPENDENCIES)
+tests_hash_plus_LDADD= $(tests_testhashkit_DEPENDENCIES)
 check_PROGRAMS+= tests/hash_plus
 
 test: check
index 5a5e15b5c4fb5ff622e08e96d08357025be29fab..4793569c1e14b56165ad110b7e44df961a322f30 100644 (file)
@@ -133,6 +133,10 @@ test_return_t world_destroy(libmemcached_test_container_st *container)
 
   server_shutdown(construct);
 
+#ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
+  sasl_done();
+#endif
+
   return TEST_SUCCESS;
 }
 
index 1ab8d6a3327eebc1ccb2d4b50636f930db486d98..0400ce5ad5ac6dc0363c2f0e864e9d26b5d6a584 100644 (file)
@@ -767,8 +767,10 @@ static test_return_t flush_test(memcached_st *memc)
 {
   memcached_return_t rc;
 
+  uint64_t query_id= memcached_query_id(memc);
   rc= memcached_flush(memc, 0);
-  test_true(rc == MEMCACHED_SUCCESS);
+  test_compare(rc, MEMCACHED_SUCCESS);
+  test_compare(query_id +1, memcached_query_id(memc));
 
   return TEST_SUCCESS;
 }
@@ -806,18 +808,23 @@ static test_return_t bad_key_test(memcached_st *memc)
   size_t max_keylen= 0xffff;
 
   // Just skip if we are in binary mode.
+  uint64_t query_id= memcached_query_id(memc);
   if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL))
     return TEST_SKIPPED;
+  test_compare(query_id, memcached_query_id(memc)); // We should not increase the query_id for memcached_behavior_get()
 
   memc_clone= memcached_clone(NULL, memc);
   test_true(memc_clone);
 
+  query_id= memcached_query_id(memc_clone);
   rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set);
   test_true(rc == MEMCACHED_SUCCESS);
+  test_compare(query_id, memcached_query_id(memc_clone)); // We should not increase the query_id for memcached_behavior_set()
 
   /* All keys are valid in the binary protocol (except for length) */
   if (memcached_behavior_get(memc_clone, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 0)
   {
+    query_id= memcached_query_id(memc_clone);
     string= memcached_get(memc_clone, key, strlen(key),
                           &string_length, &flags, &rc);
     test_true(rc == MEMCACHED_BAD_KEY_PROVIDED);
@@ -825,7 +832,9 @@ static test_return_t bad_key_test(memcached_st *memc)
     test_true(!string);
 
     set= 0;
+    query_id= memcached_query_id(memc_clone);
     rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set);
+    test_compare(query_id, memcached_query_id(memc_clone)); // We should not increase the query_id for memcached_behavior_set()
     test_true(rc == MEMCACHED_SUCCESS);
     string= memcached_get(memc_clone, key, strlen(key),
                           &string_length, &flags, &rc);
@@ -837,14 +846,20 @@ static test_return_t bad_key_test(memcached_st *memc)
     const char *keys[] = { "GoodKey", "Bad Key", "NotMine" };
     size_t key_lengths[] = { 7, 7, 7 };
     set= 1;
+    query_id= memcached_query_id(memc_clone);
     rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set);
     test_true(rc == MEMCACHED_SUCCESS);
+    test_compare(query_id, memcached_query_id(memc_clone));
 
+    query_id= memcached_query_id(memc_clone);
     rc= memcached_mget(memc_clone, keys, key_lengths, 3);
     test_true(rc == MEMCACHED_BAD_KEY_PROVIDED);
+    test_compare(query_id +1, memcached_query_id(memc_clone));
 
+    query_id= memcached_query_id(memc_clone);
     rc= memcached_mget_by_key(memc_clone, "foo daddy", 9, keys, key_lengths, 1);
     test_true(rc == MEMCACHED_BAD_KEY_PROVIDED);
+    test_compare(query_id +1, memcached_query_id(memc_clone));
 
     max_keylen= 250;
 
@@ -970,8 +985,10 @@ static test_return_t get_test(memcached_st *memc)
   size_t string_length;
   uint32_t flags;
 
+  uint64_t query_id= memcached_query_id(memc);
   rc= memcached_delete(memc, key, strlen(key), (time_t)0);
   test_true(rc == MEMCACHED_BUFFERED || rc == MEMCACHED_NOTFOUND);
+  test_compare(query_id +1, memcached_query_id(memc));
 
   string= memcached_get(memc, key, strlen(key),
                         &string_length, &flags, &rc);
@@ -992,18 +1009,22 @@ static test_return_t get_test2(memcached_st *memc)
   size_t string_length;
   uint32_t flags;
 
+  uint64_t query_id= memcached_query_id(memc);
   rc= memcached_set(memc, key, strlen(key),
                     value, strlen(value),
                     (time_t)0, (uint32_t)0);
   test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  test_compare(query_id +1, memcached_query_id(memc));
 
+  query_id= memcached_query_id(memc);
   string= memcached_get(memc, key, strlen(key),
                         &string_length, &flags, &rc);
+  test_compare(query_id +1, memcached_query_id(memc));
 
   test_true(string);
   test_true(rc == MEMCACHED_SUCCESS);
   test_true(string_length == strlen(value));
-  test_true(!memcmp(string, value, string_length));
+  test_memcmp(string, value, string_length);
 
   free(string);
 
@@ -1034,25 +1055,26 @@ static test_return_t set_test3(memcached_st *memc)
   memcached_return_t rc;
   char *value;
   size_t value_length= 8191;
-  unsigned int x;
 
   value = (char*)malloc(value_length);
   test_true(value);
 
-  for (x= 0; x < value_length; x++)
+  for (uint32_t x= 0; x < value_length; x++)
     value[x] = (char) (x % 127);
 
   /* The dump test relies on there being at least 32 items in memcached */
-  for (x= 0; x < 32; x++)
+  for (uint32_t x= 0; x < 32; x++)
   {
     char key[16];
 
     snprintf(key, sizeof(key), "foo%u", x);
 
+    uint64_t query_id= memcached_query_id(memc);
     rc= memcached_set(memc, key, strlen(key),
                       value, value_length,
                       (time_t)0, (uint32_t)0);
     test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+    test_compare(query_id +1, memcached_query_id(memc));
   }
 
   free(value);
@@ -1720,8 +1742,10 @@ static test_return_t mget_execute(memcached_st *memc)
     key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%lu", (unsigned long)x);
     keys[x]= strdup(k);
     test_true(keys[x] != NULL);
+    uint64_t query_id= memcached_query_id(memc);
     rc= memcached_add(memc, keys[x], key_length[x], blob, sizeof(blob), 0, 0);
     test_true(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+    test_compare(query_id +1, memcached_query_id(memc));
   }
 
   /* Try to get all of them with a large multiget */
@@ -1733,8 +1757,10 @@ static test_return_t mget_execute(memcached_st *memc)
   if (rc == MEMCACHED_SUCCESS)
   {
     test_true(binary);
+    uint64_t query_id= memcached_query_id(memc);
     rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
     test_true(rc == MEMCACHED_END);
+    test_compare(query_id, memcached_query_id(memc));
 
     /* Verify that we got all of the items */
     test_true(counter == max_keys);
@@ -2257,7 +2283,7 @@ static test_return_t user_supplied_bug4(memcached_st *memc)
 
   /* We need to empty the server before continueing test */
   rc= memcached_flush(memc, 0);
-  test_true(rc == MEMCACHED_NO_SERVERS);
+  test_compare(rc, MEMCACHED_NO_SERVERS);
 
   rc= memcached_mget(memc, keys, key_length, 3);
   test_true(rc == MEMCACHED_NO_SERVERS);
@@ -2267,7 +2293,7 @@ static test_return_t user_supplied_bug4(memcached_st *memc)
   {
     test_true(return_value);
   }
-  test_true(!return_value);
+  test_false(return_value);
   test_true(return_value_length == 0);
   test_true(rc == MEMCACHED_NO_SERVERS);
 
@@ -2289,7 +2315,7 @@ static test_return_t user_supplied_bug4(memcached_st *memc)
     test_true(return_value);
     test_true(rc == MEMCACHED_SUCCESS);
     test_true(return_key_length == return_value_length);
-    test_true(!memcmp(return_value, return_key, return_value_length));
+    test_memcmp(return_value, return_key, return_value_length);
     free(return_value);
     x++;
   }
@@ -6295,7 +6321,7 @@ collection_st collection[] ={
   {0, 0, 0, 0}
 };
 
-#include "libmemcached_world.h"
+#include "tests/libmemcached_world.h"
 
 void get_world(world_st *world)
 {
index c0c6bb9503713eb3271b4c86ae24dfd567be8285..c4b671153269ea9724082dec199549172c3d4504 100644 (file)
@@ -1,17 +1,16 @@
 /*
   C++ interface test
 */
-#include "libmemcached/memcached.hpp"
+#include <libmemcached/memcached.hpp>
 
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
-#include <time.h>
+#include <ctime>
 
 #include <libtest/server.h>
 
@@ -44,7 +43,7 @@ static void populate_vector(vector<char> &vec, const string &str)
 static void copy_vec_to_string(vector<char> &vec, string &str)
 {
   str.clear();
-  if (! vec.empty())
+  if (not vec.empty())
   {
     str.assign(vec.begin(), vec.end());
   }
@@ -59,31 +58,18 @@ test_return_t basic_test(memcached_st *memc)
 
   populate_vector(value, value_set);
 
-  foo.set("mine", value, 0, 0);
-  foo.get("mine", test_value);
+  test_true(foo.set("mine", value, 0, 0));
+  test_true(foo.get("mine", test_value));
 
-  assert((memcmp(&test_value[0], &value[0], test_value.size()) == 0));
+  test_memcmp(&test_value[0], &value[0], test_value.size());
+  test_false(foo.set("", value, 0, 0));
 
-  /*
-   * Simple test of the exceptions here...this should throw an exception
-   * saying that the key is empty.
-   */
-  try
-  {
-    foo.set("", value, 0, 0);
-  }
-  catch (Error &err)
-  {
-    return TEST_SUCCESS;
-  }
-
-  return TEST_FAILURE;
+  return TEST_SUCCESS;
 }
 
-test_return_t increment_test(memcached_st *memc)
+test_return_t increment_test(memcached_st *original)
 {
-  Memcache mcach(memc);
-  bool rc;
+  Memcache mcach(original);
   const string key("blah");
   const string inc_value("1");
   std::vector<char> inc_val;
@@ -94,40 +80,31 @@ test_return_t increment_test(memcached_st *memc)
 
   populate_vector(inc_val, inc_value);
 
-  rc= mcach.set(key, inc_val, 0, 0);
-  if (rc == false)
-  {
-    return TEST_FAILURE;
-  }
-  mcach.get(key, ret_value);
-  if (ret_value.empty())
-  {
-    return TEST_FAILURE;
-  }
+  test_true(mcach.set(key, inc_val, 0, 0));
+
+  test_true(mcach.get(key, ret_value));
+  test_false(ret_value.empty());
   copy_vec_to_string(ret_value, ret_string);
 
   int_inc_value= uint64_t(atol(inc_value.c_str()));
   int_ret_value= uint64_t(atol(ret_string.c_str()));
-  assert(int_ret_value == int_inc_value);
+  test_compare(int_inc_value, int_ret_value);
 
-  rc= mcach.increment(key, 1, &int_ret_value);
-  assert(rc == true);
-  assert(int_ret_value == 2);
+  test_true(mcach.increment(key, 1, &int_ret_value));
+  test_compare(2, int_ret_value);
 
-  rc= mcach.increment(key, 1, &int_ret_value);
-  assert(rc == true);
-  assert(int_ret_value == 3);
+  test_true(mcach.increment(key, 1, &int_ret_value));
+  test_compare(3, int_ret_value);
 
-  rc= mcach.increment(key, 5, &int_ret_value);
-  assert(rc == true);
-  assert(int_ret_value == 8);
+  test_true(mcach.increment(key, 5, &int_ret_value));
+  test_compare(8, int_ret_value);
 
   return TEST_SUCCESS;
 }
 
-test_return_t basic_master_key_test(memcached_st *memc)
+test_return_t basic_master_key_test(memcached_st *original)
 {
-  Memcache foo(memc);
+  Memcache foo(original);
   const string value_set("Data for server A");
   vector<char> value;
   vector<char> test_value;
@@ -140,12 +117,12 @@ test_return_t basic_master_key_test(memcached_st *memc)
   foo.setByKey(master_key_a, key, value, 0, 0);
   foo.getByKey(master_key_a, key, test_value);
 
-  assert((memcmp(&value[0], &test_value[0], value.size()) == 0));
+  test_true((memcmp(&value[0], &test_value[0], value.size()) == 0));
 
   test_value.clear();
 
   foo.getByKey(master_key_b, key, test_value);
-  assert((memcmp(&value[0], &test_value[0], value.size()) == 0));
+  test_true((memcmp(&value[0], &test_value[0], value.size()) == 0));
 
   return TEST_SUCCESS;
 }
@@ -162,53 +139,9 @@ memcached_return_t callback_counter(const memcached_st *,
   return MEMCACHED_SUCCESS;
 }
 
-test_return_t mget_result_function(memcached_st *memc)
-{
-  Memcache mc(memc);
-  bool rc;
-  string key1("fudge");
-  string key2("son");
-  string key3("food");
-  vector<string> keys;
-  vector< vector<char> *> values;
-  vector<char> val1;
-  vector<char> val2;
-  vector<char> val3;
-  populate_vector(val1, key1);
-  populate_vector(val2, key2);
-  populate_vector(val3, key3);
-  keys.reserve(3);
-  keys.push_back(key1);
-  keys.push_back(key2);
-  keys.push_back(key3);
-  values.reserve(3);
-  values.push_back(&val1);
-  values.push_back(&val2);
-  values.push_back(&val3);
-  unsigned int counter;
-  memcached_execute_fn callbacks[1];
-
-  /* We need to empty the server before we continue the test */
-  rc= mc.flush(0);
-  rc= mc.setAll(keys, values, 50, 9);
-  assert(rc == true);
-
-  rc= mc.mget(keys);
-  assert(rc == true);
-
-  callbacks[0]= &callback_counter;
-  counter= 0;
-  rc= mc.fetchExecute(callbacks, static_cast<void *>(&counter), 1);
-
-  assert(counter == 3);
-
-  return TEST_SUCCESS;
-}
-
-test_return_t mget_test(memcached_st *memc)
+test_return_t mget_test(memcached_st *original)
 {
-  Memcache mc(memc);
-  bool rc;
+  Memcache memc(original);
   memcached_return_t mc_rc;
   vector<string> keys;
   vector< vector<char> *> values;
@@ -231,43 +164,37 @@ test_return_t mget_test(memcached_st *memc)
   vector<char> return_value;
 
   /* We need to empty the server before we continue the test */
-  rc= mc.flush(0);
-  assert(rc == true);
+  test_true(memc.flush(0));
 
-  rc= mc.mget(keys);
-  assert(rc == true);
+  test_true(memc.mget(keys));
 
-  while ((mc_rc= mc.fetch(return_key, return_value)) != MEMCACHED_END)
+  while ((mc_rc= memc.fetch(return_key, return_value)) != MEMCACHED_END)
   {
-    assert(return_value.size() != 0);
+    test_true(return_value.size());
     return_value.clear();
   }
-  assert(mc_rc == MEMCACHED_END);
+  test_compare(mc_rc, MEMCACHED_END);
 
-  rc= mc.setAll(keys, values, 50, 9);
-  assert(rc == true);
+  test_true(memc.setAll(keys, values, 50, 9));
 
-  rc= mc.mget(keys);
-  assert(rc == true);
+  test_true(memc.mget(keys));
 
-  while ((mc_rc= mc.fetch(return_key, return_value)) != MEMCACHED_END)
+  while ((mc_rc= memc.fetch(return_key, return_value)) != MEMCACHED_END)
   {
-    assert(return_key.length() == return_value.size());
-    assert(!memcmp(&return_value[0], return_key.c_str(), return_value.size()));
+    test_compare(return_key.length(), return_value.size());
+    test_memcmp(&return_value[0], return_key.c_str(), return_value.size());
   }
 
   return TEST_SUCCESS;
 }
 
-test_return_t basic_behavior(memcached_st *memc)
+test_return_t basic_behavior(memcached_st *original)
 {
-  Memcache mc(memc);
-  bool rc;
-  uint64_t value = 1;
-  rc = mc.setBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY, value);
-  assert(rc);
-  uint64_t behavior = mc.getBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY);
-  assert(behavior == value);
+  Memcache memc(original);
+  uint64_t value= 1;
+  test_true(memc.setBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY, value));
+  uint64_t behavior= memc.getBehavior(MEMCACHED_BEHAVIOR_VERIFY_KEY);
+  test_compare(behavior, value);
 
   return TEST_SUCCESS;
 }
@@ -281,8 +208,6 @@ test_st tests[] ={
     reinterpret_cast<test_callback_fn>(increment_test) },
   { "mget", 1,
     reinterpret_cast<test_callback_fn>(mget_test) },
-  { "mget_result_function", 1,
-    reinterpret_cast<test_callback_fn>(mget_result_function) },
   { "basic_behavior", 0,
     reinterpret_cast<test_callback_fn>(basic_behavior) },
   {0, 0, 0}
index 35d6eb41f259936f309358e411e0712923e4fed9..aa8a7d6ffb08c33d6c68dec9cc189ec1f3cfcaed 100644 (file)
  *
  */
 
-#include "libmemcached/common.h"
-#include "libmemcached/error.h"
-#include "tests/string.h"
+#define BUILDING_LIBMEMCACHED
+
+#include <libmemcached/common.h>
+#include <libmemcached/error.h>
+#include <tests/string.h>
 
 test_return_t string_static_null(memcached_st *memc)
 {