Merge in code for C++ compiling of libmemcached.
authorBrian Aker <brian@tangent.org>
Thu, 28 Apr 2011 00:30:03 +0000 (17:30 -0700)
committerBrian Aker <brian@tangent.org>
Thu, 28 Apr 2011 00:30:03 +0000 (17:30 -0700)
379 files changed:
ChangeLog
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
docs/client_errors/MEMCACHED_AUTH_CONTINUE.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_AUTH_FAILURE.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_AUTH_PROBLEM.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_BAD_KEY_PROVIDED.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_BUFFERED.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_CLIENT_ERROR.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_CONNECTION_BIND_FAILURE.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_CONNECTION_FAILURE.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_DATA_DOES_NOT_EXIST.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_DATA_EXISTS.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_DELETED.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_DEPRECATED.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_E2BIG.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_END.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_ERRNO.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_FAILURE.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_FAIL_UNIX_SOCKET.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_FETCH_NOTFINISHED.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_HOST_LOOKUP_FAILURE.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_INVALID_ARGUMENTS.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_INVALID_HOST_PROTOCOL.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_ITEM.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_KEY_TOO_BIG.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_MAXIMUM_RETURN.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_MEMORY_ALLOCATION_FAILURE.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_NOTFOUND.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_NOTSTORED.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_NOT_SUPPORTED.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_NO_KEY_PROVIDED.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_NO_SERVERS.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_PARSE_ERROR.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_PARSE_USER_ERROR.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_PARTIAL_READ.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_PROTOCOL_ERROR.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_READ_FAILURE.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_SERVER_ERROR.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_SERVER_MARKED_DEAD.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_SOME_ERRORS.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_STAT.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_STORED.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_SUCCESS.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_TIMEOUT.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_UNKNOWN_READ_FAILURE.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_UNKNOWN_STAT_KEY.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_VALUE.rst [new file with mode: 0644]
docs/client_errors/MEMCACHED_WRITE_FAILURE.rst [new file with mode: 0644]
docs/error_messages.rst [new file with mode: 0644]
docs/hashkit_create.rst
docs/include.am
docs/index.rst
docs/libmemcached.rst
docs/man/hashkit_clone.3
docs/man/hashkit_crc32.3
docs/man/hashkit_create.3
docs/man/hashkit_fnv1_32.3
docs/man/hashkit_fnv1_64.3
docs/man/hashkit_fnv1a_32.3
docs/man/hashkit_fnv1a_64.3
docs/man/hashkit_free.3
docs/man/hashkit_functions.3
docs/man/hashkit_hsieh.3
docs/man/hashkit_is_allocated.3
docs/man/hashkit_jenkins.3
docs/man/hashkit_md5.3
docs/man/hashkit_murmur.3
docs/man/hashkit_value.3
docs/man/libhashkit.3
docs/man/libmemcached.3
docs/man/libmemcached_check_configuration.3
docs/man/libmemcached_configuration.3
docs/man/libmemcached_examples.3
docs/man/libmemcachedutil.3
docs/man/memaslap.1
docs/man/memcached.3
docs/man/memcached_add.3
docs/man/memcached_add_by_key.3
docs/man/memcached_analyze.3
docs/man/memcached_append.3
docs/man/memcached_append_by_key.3
docs/man/memcached_auto.3
docs/man/memcached_behavior.3
docs/man/memcached_behavior_get.3
docs/man/memcached_behavior_set.3
docs/man/memcached_callback.3
docs/man/memcached_callback_get.3
docs/man/memcached_callback_set.3
docs/man/memcached_cas.3
docs/man/memcached_cas_by_key.3
docs/man/memcached_clone.3
docs/man/memcached_create.3
docs/man/memcached_decrement.3
docs/man/memcached_decrement_with_initial.3
docs/man/memcached_delete.3
docs/man/memcached_delete_by_key.3
docs/man/memcached_destroy_sasl_auth_data.3
docs/man/memcached_dump.3
docs/man/memcached_fetch.3
docs/man/memcached_fetch_execute.3
docs/man/memcached_fetch_result.3
docs/man/memcached_flush.3
docs/man/memcached_flush_buffers.3
docs/man/memcached_free.3
docs/man/memcached_generate_hash.3
docs/man/memcached_generate_hash_value.3
docs/man/memcached_get.3
docs/man/memcached_get_by_key.3
docs/man/memcached_get_memory_allocators.3
docs/man/memcached_get_sasl_callbacks.3
docs/man/memcached_get_user_data.3
docs/man/memcached_increment.3
docs/man/memcached_increment_with_initial.3
docs/man/memcached_lib_version.3
docs/man/memcached_memory_allocators.3
docs/man/memcached_mget.3
docs/man/memcached_mget_by_key.3
docs/man/memcached_mget_execute.3
docs/man/memcached_mget_execute_by_key.3
docs/man/memcached_pool.3
docs/man/memcached_pool_behavior_get.3
docs/man/memcached_pool_behavior_set.3
docs/man/memcached_pool_create.3
docs/man/memcached_pool_destroy.3
docs/man/memcached_pool_pop.3
docs/man/memcached_pool_push.3
docs/man/memcached_pool_st.3
docs/man/memcached_prepend.3
docs/man/memcached_prepend_by_key.3
docs/man/memcached_quit.3
docs/man/memcached_replace.3
docs/man/memcached_replace_by_key.3
docs/man/memcached_result_cas.3
docs/man/memcached_result_create.3
docs/man/memcached_result_flags.3
docs/man/memcached_result_free.3
docs/man/memcached_result_key_length.3
docs/man/memcached_result_key_value.3
docs/man/memcached_result_length.3
docs/man/memcached_result_st.3
docs/man/memcached_result_value.3
docs/man/memcached_sasl.3
docs/man/memcached_sasl_set_auth_data.3
docs/man/memcached_server_add.3
docs/man/memcached_server_add_unix_socket.3
docs/man/memcached_server_count.3
docs/man/memcached_server_cursor.3
docs/man/memcached_server_list.3
docs/man/memcached_server_list_append.3
docs/man/memcached_server_list_count.3
docs/man/memcached_server_list_free.3
docs/man/memcached_server_push.3
docs/man/memcached_server_st.3
docs/man/memcached_servers.3
docs/man/memcached_servers_parse.3
docs/man/memcached_servers_reset.3
docs/man/memcached_set.3
docs/man/memcached_set_by_key.3
docs/man/memcached_set_memory_allocators.3
docs/man/memcached_set_memory_allocators_context.3
docs/man/memcached_set_sasl_callbacks.3
docs/man/memcached_set_user_data.3
docs/man/memcached_stat.3
docs/man/memcached_stat_execute.3
docs/man/memcached_stat_get_keys.3
docs/man/memcached_stat_get_value.3
docs/man/memcached_stat_servername.3
docs/man/memcached_stats.3
docs/man/memcached_strerror.3
docs/man/memcached_user_data.3
docs/man/memcached_verbosity.3
docs/man/memcached_version.3
docs/man/memcapable.1
docs/man/memcat.1
docs/man/memcp.1
docs/man/memdump.1
docs/man/memerror.1
docs/man/memflush.1
docs/man/memrm.1
docs/man/memslap.1
docs/man/memstat.1
docs/memcached_callback.rst
docs/memcached_delete.rst
docs/memcached_dump.rst
docs/memcached_get.rst
docs/memcached_memory_allocators.rst
docs/memcached_result_st.rst
docs/memcached_sasl.rst
docs/memcached_set.rst
docs/memcached_version.rst
docs/memcapable.rst
docs/memcp.rst
docs/memdump.rst
docs/memerror.rst
docs/memflush.rst
docs/memslap.rst
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/constants.h
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/options/parser.cc
libmemcached/options/scanner.cc
libmemcached/options/scanner.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 [new file with mode: 0644]
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/ping.c [deleted file]
libmemcached/util/ping.cc [new file with mode: 0644]
libmemcached/util/pool.c [deleted file]
libmemcached/util/pool.cc [new file with mode: 0644]
libmemcached/util/version.c [deleted file]
libmemcached/util/version.cc [new file with mode: 0644]
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
support/libmemcached.spec.in
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 933decf326a9f06a5343022a486eead5a96b2f33..43d3eef6a2fc84d3f9ca31471d14beee3b43be4a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,4 @@
-0.49
+0.49 Thu Apr 14 08:43:37 PDT 2011
   * Fix calls to auto methods so that if value is not passed in nothing bad happens.
   * New parser calls for generating memcached_st objects.
   * New error system.
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 765e7ab..0000000
+++ /dev/null
@@ -1,351 +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[])
-{
-  memcached_return_t rc;
-  memcached_st *memc;
-  memcached_server_st *servers;
-
-  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);
-    }
-  }
-
-  memc= memcached_create(NULL);
-
-  servers= memcached_servers_parse(opt_servers);
-  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);
-  }
-
-  free(opt_servers);
-
-  memcached_free(memc);
-
-  return rc == MEMCACHED_SUCCESS ? 0: -1;
-}
-
-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 ff9329bf028f24cc60a035b11c82ef09e8144878..9b8a82c581c3a0241ed5b3403eb008430a198cfc 100644 (file)
@@ -8,8 +8,8 @@
 # the COPYING file in this directory for full text.
 
 AC_PREREQ(2.59)
-AC_INIT([libmemcached],[0.48],[http://libmemcached.org/])
-AC_CONFIG_SRCDIR([libmemcached/memcached.c])
+AC_INIT([libmemcached],[0.49],[http://libmemcached.org/])
+AC_CONFIG_SRCDIR([libmemcached/memcached.cc])
 AC_CONFIG_AUX_DIR(config)
 
 PANDORA_CANONICAL_TARGET(no-vc-changelog)
@@ -17,9 +17,9 @@ AC_CHECK_PROGS([YACC], ['bison'], [:])
 AC_CHECK_PROGS([LEX], ['flex'], [:])
 
 #shared library versioning
-MEMCACHED_UTIL_LIBRARY_VERSION=1:0:0
+MEMCACHED_UTIL_LIBRARY_VERSION=2:0:0
 MEMCACHED_PROTOCAL_LIBRARY_VERSION=0:0:0
-MEMCACHED_LIBRARY_VERSION=6:0:0
+MEMCACHED_LIBRARY_VERSION=7:0:0
 #                         | | |
 #                  +------+ | +---+
 #                  |        |     |
diff --git a/docs/client_errors/MEMCACHED_AUTH_CONTINUE.rst b/docs/client_errors/MEMCACHED_AUTH_CONTINUE.rst
new file mode 100644 (file)
index 0000000..8a3e6c7
--- /dev/null
@@ -0,0 +1,5 @@
+=======================
+MEMCACHED_AUTH_CONTINUE
+=======================
+
+Authentication has been paused.
diff --git a/docs/client_errors/MEMCACHED_AUTH_FAILURE.rst b/docs/client_errors/MEMCACHED_AUTH_FAILURE.rst
new file mode 100644 (file)
index 0000000..36d5a0c
--- /dev/null
@@ -0,0 +1,5 @@
+======================
+MEMCACHED_AUTH_FAILURE
+======================
+
+The credentials provided are not valid for this server.
diff --git a/docs/client_errors/MEMCACHED_AUTH_PROBLEM.rst b/docs/client_errors/MEMCACHED_AUTH_PROBLEM.rst
new file mode 100644 (file)
index 0000000..196d6f9
--- /dev/null
@@ -0,0 +1,5 @@
+======================
+MEMCACHED_AUTH_PROBLEM
+======================
+
+An unknown issue has occured during authentication.
diff --git a/docs/client_errors/MEMCACHED_BAD_KEY_PROVIDED.rst b/docs/client_errors/MEMCACHED_BAD_KEY_PROVIDED.rst
new file mode 100644 (file)
index 0000000..73aa4f1
--- /dev/null
@@ -0,0 +1,5 @@
+==========================
+MEMCACHED_BAD_KEY_PROVIDED
+==========================
+
+The key provided is not a valid key.
diff --git a/docs/client_errors/MEMCACHED_BUFFERED.rst b/docs/client_errors/MEMCACHED_BUFFERED.rst
new file mode 100644 (file)
index 0000000..d93526a
--- /dev/null
@@ -0,0 +1,5 @@
+==================
+MEMCACHED_BUFFERED
+==================
+
+The request has been buffered.
diff --git a/docs/client_errors/MEMCACHED_CLIENT_ERROR.rst b/docs/client_errors/MEMCACHED_CLIENT_ERROR.rst
new file mode 100644 (file)
index 0000000..1db8286
--- /dev/null
@@ -0,0 +1,5 @@
+======================
+MEMCACHED_CLIENT_ERROR
+======================
+
+An unknown client error has occured internally.
diff --git a/docs/client_errors/MEMCACHED_CONNECTION_BIND_FAILURE.rst b/docs/client_errors/MEMCACHED_CONNECTION_BIND_FAILURE.rst
new file mode 100644 (file)
index 0000000..319701c
--- /dev/null
@@ -0,0 +1,5 @@
+=================================
+MEMCACHED_CONNECTION_BIND_FAILURE
+=================================
+
+We were not able to bind() to the socket.
diff --git a/docs/client_errors/MEMCACHED_CONNECTION_FAILURE.rst b/docs/client_errors/MEMCACHED_CONNECTION_FAILURE.rst
new file mode 100644 (file)
index 0000000..f46fa17
--- /dev/null
@@ -0,0 +1,5 @@
+============================
+MEMCACHED_CONNECTION_FAILURE
+============================
+
+A unknown error has occured while trying to connect to a server.
diff --git a/docs/client_errors/MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE.rst b/docs/client_errors/MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE.rst
new file mode 100644 (file)
index 0000000..4bf2337
--- /dev/null
@@ -0,0 +1,5 @@
+==========================================
+MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE
+==========================================
+
+An error has occurred while trying to connect to a server. It is likely that either the number of file descriptors need to be increased or you are out of memory.
diff --git a/docs/client_errors/MEMCACHED_DATA_DOES_NOT_EXIST.rst b/docs/client_errors/MEMCACHED_DATA_DOES_NOT_EXIST.rst
new file mode 100644 (file)
index 0000000..13d5646
--- /dev/null
@@ -0,0 +1,5 @@
+=============================
+MEMCACHED_DATA_DOES_NOT_EXIST
+=============================
+
+The data requested with the key given was not found.
diff --git a/docs/client_errors/MEMCACHED_DATA_EXISTS.rst b/docs/client_errors/MEMCACHED_DATA_EXISTS.rst
new file mode 100644 (file)
index 0000000..db0de35
--- /dev/null
@@ -0,0 +1,5 @@
+=====================
+MEMCACHED_DATA_EXISTS
+=====================
+
+The data requested with the key given was not found.
diff --git a/docs/client_errors/MEMCACHED_DELETED.rst b/docs/client_errors/MEMCACHED_DELETED.rst
new file mode 100644 (file)
index 0000000..c1e2acf
--- /dev/null
@@ -0,0 +1,5 @@
+=================
+MEMCACHED_DELETED
+=================
+
+The object requested by the key has been deleted.
diff --git a/docs/client_errors/MEMCACHED_DEPRECATED.rst b/docs/client_errors/MEMCACHED_DEPRECATED.rst
new file mode 100644 (file)
index 0000000..733b1c1
--- /dev/null
@@ -0,0 +1,5 @@
+====================
+MEMCACHED_DEPRECATED
+====================
+
+The method that was requested has been deprecated.
diff --git a/docs/client_errors/MEMCACHED_E2BIG.rst b/docs/client_errors/MEMCACHED_E2BIG.rst
new file mode 100644 (file)
index 0000000..16c7b9c
--- /dev/null
@@ -0,0 +1,5 @@
+===============
+MEMCACHED_E2BIG
+===============
+
+Item is too large for the server to store.
diff --git a/docs/client_errors/MEMCACHED_END.rst b/docs/client_errors/MEMCACHED_END.rst
new file mode 100644 (file)
index 0000000..39ad854
--- /dev/null
@@ -0,0 +1,5 @@
+=============
+MEMCACHED_END
+=============
+
+The server has completed returning all of the objects requested.
diff --git a/docs/client_errors/MEMCACHED_ERRNO.rst b/docs/client_errors/MEMCACHED_ERRNO.rst
new file mode 100644 (file)
index 0000000..343f37d
--- /dev/null
@@ -0,0 +1,5 @@
+===============
+MEMCACHED_ERRNO
+===============
+
+An error has occurred in the driver which has set errno.
diff --git a/docs/client_errors/MEMCACHED_FAILURE.rst b/docs/client_errors/MEMCACHED_FAILURE.rst
new file mode 100644 (file)
index 0000000..66c7508
--- /dev/null
@@ -0,0 +1,5 @@
+=================
+MEMCACHED_FAILURE
+=================
+
+A unknown failure has occurred in the server.
diff --git a/docs/client_errors/MEMCACHED_FAIL_UNIX_SOCKET.rst b/docs/client_errors/MEMCACHED_FAIL_UNIX_SOCKET.rst
new file mode 100644 (file)
index 0000000..d078171
--- /dev/null
@@ -0,0 +1,5 @@
+==========================
+MEMCACHED_FAIL_UNIX_SOCKET
+==========================
+
+A connection was not established with the server via a unix domain socket.
diff --git a/docs/client_errors/MEMCACHED_FETCH_NOTFINISHED.rst b/docs/client_errors/MEMCACHED_FETCH_NOTFINISHED.rst
new file mode 100644 (file)
index 0000000..7e90a5a
--- /dev/null
@@ -0,0 +1,5 @@
+===========================
+MEMCACHED_FETCH_NOTFINISHED
+===========================
+
+A request has been made, but the server has not finished the fetch of the last request.
diff --git a/docs/client_errors/MEMCACHED_HOST_LOOKUP_FAILURE.rst b/docs/client_errors/MEMCACHED_HOST_LOOKUP_FAILURE.rst
new file mode 100644 (file)
index 0000000..cbfe70f
--- /dev/null
@@ -0,0 +1,5 @@
+=============================
+MEMCACHED_HOST_LOOKUP_FAILURE
+=============================
+
+A DNS failure has occurred.
diff --git a/docs/client_errors/MEMCACHED_INVALID_ARGUMENTS.rst b/docs/client_errors/MEMCACHED_INVALID_ARGUMENTS.rst
new file mode 100644 (file)
index 0000000..0684dbf
--- /dev/null
@@ -0,0 +1,5 @@
+===========================
+MEMCACHED_INVALID_ARGUMENTS
+===========================
+
+The arguments supplied to the given function were not valid.
diff --git a/docs/client_errors/MEMCACHED_INVALID_HOST_PROTOCOL.rst b/docs/client_errors/MEMCACHED_INVALID_HOST_PROTOCOL.rst
new file mode 100644 (file)
index 0000000..181a959
--- /dev/null
@@ -0,0 +1,5 @@
+===============================
+MEMCACHED_INVALID_HOST_PROTOCOL
+===============================
+
+The server you are connecting too has an invalid protocol. Most likely you are connecting to an older server that does not speak the binary protocol.
diff --git a/docs/client_errors/MEMCACHED_ITEM.rst b/docs/client_errors/MEMCACHED_ITEM.rst
new file mode 100644 (file)
index 0000000..9f19203
--- /dev/null
@@ -0,0 +1,5 @@
+==============
+MEMCACHED_ITEM
+==============
+
+An item has been fetched (this is an internal error only).
diff --git a/docs/client_errors/MEMCACHED_KEY_TOO_BIG.rst b/docs/client_errors/MEMCACHED_KEY_TOO_BIG.rst
new file mode 100644 (file)
index 0000000..cbb2eeb
--- /dev/null
@@ -0,0 +1,5 @@
+=====================
+MEMCACHED_KEY_TOO_BIG
+=====================
+
+The key that has been provided is too large for the given server.
diff --git a/docs/client_errors/MEMCACHED_MAXIMUM_RETURN.rst b/docs/client_errors/MEMCACHED_MAXIMUM_RETURN.rst
new file mode 100644 (file)
index 0000000..d980e6d
--- /dev/null
@@ -0,0 +1,5 @@
+========================
+MEMCACHED_MAXIMUM_RETURN
+========================
+
+This in an internal only state.
diff --git a/docs/client_errors/MEMCACHED_MEMORY_ALLOCATION_FAILURE.rst b/docs/client_errors/MEMCACHED_MEMORY_ALLOCATION_FAILURE.rst
new file mode 100644 (file)
index 0000000..3a3472b
--- /dev/null
@@ -0,0 +1,5 @@
+===================================
+MEMCACHED_MEMORY_ALLOCATION_FAILURE
+===================================
+
+An error has occurred while trying to allocate memory.
diff --git a/docs/client_errors/MEMCACHED_NOTFOUND.rst b/docs/client_errors/MEMCACHED_NOTFOUND.rst
new file mode 100644 (file)
index 0000000..c1a6ac1
--- /dev/null
@@ -0,0 +1,5 @@
+==================
+MEMCACHED_NOTFOUND
+==================
+
+The object requested was not found.
diff --git a/docs/client_errors/MEMCACHED_NOTSTORED.rst b/docs/client_errors/MEMCACHED_NOTSTORED.rst
new file mode 100644 (file)
index 0000000..61ea12b
--- /dev/null
@@ -0,0 +1,5 @@
+===================
+MEMCACHED_NOTSTORED
+===================
+
+The request to store an object failed.
diff --git a/docs/client_errors/MEMCACHED_NOT_SUPPORTED.rst b/docs/client_errors/MEMCACHED_NOT_SUPPORTED.rst
new file mode 100644 (file)
index 0000000..f8befa0
--- /dev/null
@@ -0,0 +1,5 @@
+=======================
+MEMCACHED_NOT_SUPPORTED
+=======================
+
+The given method is not supported in the server.
diff --git a/docs/client_errors/MEMCACHED_NO_KEY_PROVIDED.rst b/docs/client_errors/MEMCACHED_NO_KEY_PROVIDED.rst
new file mode 100644 (file)
index 0000000..73cc54d
--- /dev/null
@@ -0,0 +1,5 @@
+=========================
+MEMCACHED_NO_KEY_PROVIDED
+=========================
+
+No key was provided.
diff --git a/docs/client_errors/MEMCACHED_NO_SERVERS.rst b/docs/client_errors/MEMCACHED_NO_SERVERS.rst
new file mode 100644 (file)
index 0000000..5e61425
--- /dev/null
@@ -0,0 +1,5 @@
+====================
+MEMCACHED_NO_SERVERS
+====================
+
+No servers have been added to the memcached_st object.
diff --git a/docs/client_errors/MEMCACHED_PARSE_ERROR.rst b/docs/client_errors/MEMCACHED_PARSE_ERROR.rst
new file mode 100644 (file)
index 0000000..a9c298e
--- /dev/null
@@ -0,0 +1,5 @@
+=====================
+MEMCACHED_PARSE_ERROR
+=====================
+
+An error has occurred while trying to parse the configuration string. You should use memparse to determine what the error was.
diff --git a/docs/client_errors/MEMCACHED_PARSE_USER_ERROR.rst b/docs/client_errors/MEMCACHED_PARSE_USER_ERROR.rst
new file mode 100644 (file)
index 0000000..035e57b
--- /dev/null
@@ -0,0 +1,5 @@
+==========================
+MEMCACHED_PARSE_USER_ERROR
+==========================
+
+An error has occurred  in parsing the configuration string.
diff --git a/docs/client_errors/MEMCACHED_PARTIAL_READ.rst b/docs/client_errors/MEMCACHED_PARTIAL_READ.rst
new file mode 100644 (file)
index 0000000..7d38998
--- /dev/null
@@ -0,0 +1,5 @@
+======================
+MEMCACHED_PARTIAL_READ
+======================
+
+The read was only partcially successful.
diff --git a/docs/client_errors/MEMCACHED_PROTOCOL_ERROR.rst b/docs/client_errors/MEMCACHED_PROTOCOL_ERROR.rst
new file mode 100644 (file)
index 0000000..add6e90
--- /dev/null
@@ -0,0 +1,5 @@
+========================
+MEMCACHED_PROTOCOL_ERROR
+========================
+
+An unknown error has occurred in the protocol.
diff --git a/docs/client_errors/MEMCACHED_READ_FAILURE.rst b/docs/client_errors/MEMCACHED_READ_FAILURE.rst
new file mode 100644 (file)
index 0000000..0da58b5
--- /dev/null
@@ -0,0 +1,5 @@
+======================
+MEMCACHED_READ_FAILURE
+======================
+
+A read failure has occurred.
diff --git a/docs/client_errors/MEMCACHED_SERVER_ERROR.rst b/docs/client_errors/MEMCACHED_SERVER_ERROR.rst
new file mode 100644 (file)
index 0000000..7803644
--- /dev/null
@@ -0,0 +1,5 @@
+======================
+MEMCACHED_SERVER_ERROR
+======================
+
+An unknown error has occurred in the server.
diff --git a/docs/client_errors/MEMCACHED_SERVER_MARKED_DEAD.rst b/docs/client_errors/MEMCACHED_SERVER_MARKED_DEAD.rst
new file mode 100644 (file)
index 0000000..25c21ef
--- /dev/null
@@ -0,0 +1,5 @@
+============================
+MEMCACHED_SERVER_MARKED_DEAD
+============================
+
+The requested server has been marked dead.
diff --git a/docs/client_errors/MEMCACHED_SOME_ERRORS.rst b/docs/client_errors/MEMCACHED_SOME_ERRORS.rst
new file mode 100644 (file)
index 0000000..6666c3d
--- /dev/null
@@ -0,0 +1,5 @@
+=====================
+MEMCACHED_SOME_ERRORS
+=====================
+
+A multi request has been made, and some underterminate number of errors have occurred.
diff --git a/docs/client_errors/MEMCACHED_STAT.rst b/docs/client_errors/MEMCACHED_STAT.rst
new file mode 100644 (file)
index 0000000..39f8109
--- /dev/null
@@ -0,0 +1,5 @@
+==============
+MEMCACHED_STAT
+==============
+
+A "stat" command has been returned in the protocol.
diff --git a/docs/client_errors/MEMCACHED_STORED.rst b/docs/client_errors/MEMCACHED_STORED.rst
new file mode 100644 (file)
index 0000000..daebc62
--- /dev/null
@@ -0,0 +1,5 @@
+================
+MEMCACHED_STORED
+================
+
+The requested object has been successfully stored on the server.
diff --git a/docs/client_errors/MEMCACHED_SUCCESS.rst b/docs/client_errors/MEMCACHED_SUCCESS.rst
new file mode 100644 (file)
index 0000000..f4e398c
--- /dev/null
@@ -0,0 +1,5 @@
+=================
+MEMCACHED_SUCCESS
+=================
+
+The request was successfully executed.
diff --git a/docs/client_errors/MEMCACHED_TIMEOUT.rst b/docs/client_errors/MEMCACHED_TIMEOUT.rst
new file mode 100644 (file)
index 0000000..27479a7
--- /dev/null
@@ -0,0 +1,5 @@
+=================
+MEMCACHED_TIMEOUT
+=================
+
+Operation has timed out.
diff --git a/docs/client_errors/MEMCACHED_UNKNOWN_READ_FAILURE.rst b/docs/client_errors/MEMCACHED_UNKNOWN_READ_FAILURE.rst
new file mode 100644 (file)
index 0000000..2056c4d
--- /dev/null
@@ -0,0 +1,5 @@
+==============================
+MEMCACHED_UNKNOWN_READ_FAILURE
+==============================
+
+An unknown read failure only occurs when either there is a bug in the server, or in rare cases where an ethernet nic is reporting dubious information.
diff --git a/docs/client_errors/MEMCACHED_UNKNOWN_STAT_KEY.rst b/docs/client_errors/MEMCACHED_UNKNOWN_STAT_KEY.rst
new file mode 100644 (file)
index 0000000..0fe362e
--- /dev/null
@@ -0,0 +1,5 @@
+==========================
+MEMCACHED_UNKNOWN_STAT_KEY
+==========================
+
+The server you are communicating with has a stat key which has not be defined in the protocol.
diff --git a/docs/client_errors/MEMCACHED_VALUE.rst b/docs/client_errors/MEMCACHED_VALUE.rst
new file mode 100644 (file)
index 0000000..3eae4a1
--- /dev/null
@@ -0,0 +1,5 @@
+===============
+MEMCACHED_VALUE
+===============
+
+A value has been returned from the server (this is an internal condition only).
diff --git a/docs/client_errors/MEMCACHED_WRITE_FAILURE.rst b/docs/client_errors/MEMCACHED_WRITE_FAILURE.rst
new file mode 100644 (file)
index 0000000..72388ff
--- /dev/null
@@ -0,0 +1,5 @@
+=======================
+MEMCACHED_WRITE_FAILURE
+=======================
+
+An error has occured while trying to write to a server.
diff --git a/docs/error_messages.rst b/docs/error_messages.rst
new file mode 100644 (file)
index 0000000..34cc304
--- /dev/null
@@ -0,0 +1,55 @@
+=====================
+Client Error messages
+=====================
+
+.. toctree::
+   :maxdepth: 1
+
+   client_errors/MEMCACHED_AUTH_CONTINUE
+   client_errors/MEMCACHED_AUTH_FAILURE
+   client_errors/MEMCACHED_AUTH_PROBLEM
+   client_errors/MEMCACHED_BAD_KEY_PROVIDED
+   client_errors/MEMCACHED_BUFFERED
+   client_errors/MEMCACHED_CLIENT_ERROR
+   client_errors/MEMCACHED_CONNECTION_BIND_FAILURE
+   client_errors/MEMCACHED_CONNECTION_FAILURE
+   client_errors/MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE
+   client_errors/MEMCACHED_DATA_DOES_NOT_EXIST
+   client_errors/MEMCACHED_DATA_EXISTS
+   client_errors/MEMCACHED_DELETED
+   client_errors/MEMCACHED_DEPRECATED
+   client_errors/MEMCACHED_E2BIG
+   client_errors/MEMCACHED_END
+   client_errors/MEMCACHED_ERRNO
+   client_errors/MEMCACHED_FAILURE
+   client_errors/MEMCACHED_FAIL_UNIX_SOCKET
+   client_errors/MEMCACHED_FETCH_NOTFINISHED
+   client_errors/MEMCACHED_HOST_LOOKUP_FAILURE
+   client_errors/MEMCACHED_INVALID_ARGUMENTS
+   client_errors/MEMCACHED_INVALID_HOST_PROTOCOL
+   client_errors/MEMCACHED_ITEM
+   client_errors/MEMCACHED_KEY_TOO_BIG
+   client_errors/MEMCACHED_MAXIMUM_RETURN
+   client_errors/MEMCACHED_MEMORY_ALLOCATION_FAILURE
+   client_errors/MEMCACHED_NOTFOUND
+   client_errors/MEMCACHED_NOTSTORED
+   client_errors/MEMCACHED_NOT_SUPPORTED
+   client_errors/MEMCACHED_NO_KEY_PROVIDED
+   client_errors/MEMCACHED_NO_SERVERS
+   client_errors/MEMCACHED_PARSE_ERROR
+   client_errors/MEMCACHED_PARSE_USER_ERROR
+   client_errors/MEMCACHED_PARTIAL_READ
+   client_errors/MEMCACHED_PROTOCOL_ERROR
+   client_errors/MEMCACHED_READ_FAILURE
+   client_errors/MEMCACHED_SERVER_ERROR
+   client_errors/MEMCACHED_SERVER_MARKED_DEAD
+   client_errors/MEMCACHED_SOME_ERRORS
+   client_errors/MEMCACHED_STAT
+   client_errors/MEMCACHED_STORED
+   client_errors/MEMCACHED_SUCCESS
+   client_errors/MEMCACHED_TIMEOUT
+   client_errors/MEMCACHED_UNKNOWN_READ_FAILURE
+   client_errors/MEMCACHED_UNKNOWN_STAT_KEY
+   client_errors/MEMCACHED_VALUE
+   client_errors/MEMCACHED_WRITE_FAILURE
+   
index cf11e83e00d2b21907fdced0894b24339fe41162..e0c9c71c0fd48c06cae541faad9347fad45def16 100644 (file)
@@ -3,35 +3,24 @@ Creating a hashkit structure
 ============================
 
 
-Create and destroy hashkit objects
-
-
--------
-LIBRARY
--------
-
-
-C Library for hashing algorithms (libmemcached, -lhashkit)
-
-
 --------
 SYNOPSIS
 --------
 
+C Library for hashing algorithms (libmemcached, -lhashkit)
 
 
-.. code-block:: perl
-
-   #include <libmemcached/hashkit.h>
-   hashkit_st *hashkit_create(hashkit_st *hash);
+#include <libhashkit/hashkit.h>
  
-   hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr);
+.. c:function:: hashkit_st *hashkit_create(hashkit_st *hash);
  
-   void hashkit_free(hashkit_st *hash);
-   bool hashkit_is_allocated(const hashkit_st *hash);
+.. c:function:: hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr);
+
+.. c:function:: void hashkit_free(hashkit_st *hash);
+
+.. c:function:: bool hashkit_is_allocated(const hashkit_st *hash);
 
+Compile and link with -lmemcached
 
 
 -----------
index 12ebed36ce42fac7cfba4b29b76912f38940db0a..5cd682b71d6bbf3fa3f5d4f806c166a248bc252c 100644 (file)
@@ -4,6 +4,54 @@
 
 EXTRA_DIST+= \
             docs/conf.py \
+            docs/error_messages.rst \
+            docs/client_errors/MEMCACHED_AUTH_CONTINUE.rst \
+            docs/client_errors/MEMCACHED_AUTH_FAILURE.rst \
+            docs/client_errors/MEMCACHED_AUTH_PROBLEM.rst \
+            docs/client_errors/MEMCACHED_BAD_KEY_PROVIDED.rst \
+            docs/client_errors/MEMCACHED_BUFFERED.rst \
+            docs/client_errors/MEMCACHED_CLIENT_ERROR.rst \
+            docs/client_errors/MEMCACHED_CONNECTION_BIND_FAILURE.rst \
+            docs/client_errors/MEMCACHED_CONNECTION_FAILURE.rst \
+            docs/client_errors/MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE.rst \
+            docs/client_errors/MEMCACHED_DATA_DOES_NOT_EXIST.rst \
+            docs/client_errors/MEMCACHED_DATA_EXISTS.rst \
+            docs/client_errors/MEMCACHED_DELETED.rst \
+            docs/client_errors/MEMCACHED_DEPRECATED.rst \
+            docs/client_errors/MEMCACHED_E2BIG.rst \
+            docs/client_errors/MEMCACHED_END.rst \
+            docs/client_errors/MEMCACHED_ERRNO.rst \
+            docs/client_errors/MEMCACHED_FAILURE.rst \
+            docs/client_errors/MEMCACHED_FAIL_UNIX_SOCKET.rst \
+            docs/client_errors/MEMCACHED_FETCH_NOTFINISHED.rst \
+            docs/client_errors/MEMCACHED_HOST_LOOKUP_FAILURE.rst \
+            docs/client_errors/MEMCACHED_INVALID_ARGUMENTS.rst \
+            docs/client_errors/MEMCACHED_INVALID_HOST_PROTOCOL.rst \
+            docs/client_errors/MEMCACHED_ITEM.rst \
+            docs/client_errors/MEMCACHED_KEY_TOO_BIG.rst \
+            docs/client_errors/MEMCACHED_MAXIMUM_RETURN.rst \
+            docs/client_errors/MEMCACHED_MEMORY_ALLOCATION_FAILURE.rst \
+            docs/client_errors/MEMCACHED_NOTFOUND.rst \
+            docs/client_errors/MEMCACHED_NOTSTORED.rst \
+            docs/client_errors/MEMCACHED_NOT_SUPPORTED.rst \
+            docs/client_errors/MEMCACHED_NO_KEY_PROVIDED.rst \
+            docs/client_errors/MEMCACHED_NO_SERVERS.rst \
+            docs/client_errors/MEMCACHED_PARSE_ERROR.rst \
+            docs/client_errors/MEMCACHED_PARSE_USER_ERROR.rst \
+            docs/client_errors/MEMCACHED_PARTIAL_READ.rst \
+            docs/client_errors/MEMCACHED_PROTOCOL_ERROR.rst \
+            docs/client_errors/MEMCACHED_READ_FAILURE.rst \
+            docs/client_errors/MEMCACHED_SERVER_ERROR.rst \
+            docs/client_errors/MEMCACHED_SERVER_MARKED_DEAD.rst \
+            docs/client_errors/MEMCACHED_SOME_ERRORS.rst \
+            docs/client_errors/MEMCACHED_STAT.rst \
+            docs/client_errors/MEMCACHED_STORED.rst \
+            docs/client_errors/MEMCACHED_SUCCESS.rst \
+            docs/client_errors/MEMCACHED_TIMEOUT.rst \
+            docs/client_errors/MEMCACHED_UNKNOWN_READ_FAILURE.rst \
+            docs/client_errors/MEMCACHED_UNKNOWN_STAT_KEY.rst \
+            docs/client_errors/MEMCACHED_VALUE.rst \
+            docs/client_errors/MEMCACHED_WRITE_FAILURE.rst \
             docs/hashkit_create.rst \
             docs/hashkit_functions.rst \
             docs/hashkit_value.rst \
index 79ce45e259bfc099c00bb58169ce9a331b9f5157..d9d3e033008a527e700490e3e2743dfe9bf7f2e5 100644 (file)
@@ -19,6 +19,7 @@ Basics
    memcached_create
    libmemcached_examples
    libmemcached_configuration
+   error_messages
 
 
 #################
index bb0f0461d3cd932374bba50c038939fd5a144d26..23ec93b49a9974e6b0b7646d00b96a6f747d1a62 100644 (file)
@@ -10,6 +10,17 @@ SYNOPSIS
 
 Compile and link with -lmemcached
 
+libMemcached is an open source C/C++ client library and tools for the memcached server (http://danga.com/memcached). It has been designed to be light on memory usage, thread safe, and provide full access to server side methods.
+
+libMemcached was designed to provide the greatest number of options to use Memcached. Some of the features provided:
+
+1. Asynchronous and Synchronous Transport Support.
+2. Consistent Hashing and Distribution.
+3. Tunable Hashing algorithm to match keys.
+4. Access to large object support.
+5. Local replication.
+6. A complete reference guide and documentation to the API.
+7. Tools to Manage your Memcached networks.
 
 -----------
 DESCRIPTION
@@ -21,14 +32,14 @@ system, generic in nature, but intended for use in speeding up dynamic web
 applications by alleviating database load." `http://danga.com/memcached/ <http://danga.com/memcached/>`_
 
 \ **libmemcached**\  is a small, thread-safe client library for the
-memcached protocol. The code has all been written with an eye to allow
+memcached protocol. The code has all been written to allow
 for both web and embedded usage. It handles the work behind routing
-particular keys to specific servers that you specify (and values are
-matched based on server order as supplied by you). It implements both
-a modula and consistent method of object distribution.
+individual keys to specific servers specified by the developer (and values are
+matched based on server order as supplied by the user). It implements
+a modular and consistent method of object distribution.
 
 There are multiple implemented routing and hashing methods. See the
-memcached_behavior_set() manpage.
+memcached_behavior_set() manpage for more information.
 
 All operations are performed against a \ ``memcached_st``\  structure.
 These structures can either be dynamically allocated or statically
@@ -117,9 +128,9 @@ THREADS AND PROCESSES
 ---------------------
 
 
-When using threads or forked processes it is important to keep an instance
+When using threads or forked processes it is important to keep one instance
 of \ ``memcached_st``\  per process or thread. Without creating your own locking
-structures you can not share a single \ ``memcached_st``\ . You can though call
+structures you can not share a single \ ``memcached_st``\ . However, you can call
 memcached_quit(3) on a \ ``memcached_st``\  and then use the resulting cloned
 structure.
 
index fd7b5ee64800bc807eef24df3e52299a68188cf2..d41f71d63a802b57a23312f88b9926a7f01b044a 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_CLONE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_CLONE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_clone \- libhashkit Documentation
 .
index ede2edcf2d7fb008a186835deacd8077587ad8da..2dc8b5843f61dcb2266d872834ba4ec6d8c3b557 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_CRC32" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_CRC32" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_crc32 \- libhashkit Documentation
 .
index cbd33a66b9363ec42f310c967c2e6064dd26708e..54d4a3e959fdabd6f52c35af07a3631d23b78b0c 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_CREATE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_CREATE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_create \- libhashkit Documentation
 .
index 2b4934c69bba9ac8c058f905cc0f375a589a6e36..5869566381371f50a0a01f9ad4af199eeab3bbec 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_FNV1_32" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_FNV1_32" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_fnv1_32 \- libhashkit Documentation
 .
index 339cf53c9bead5ffb4d9e284748d836503da11ef..ac2485ab4c7bdca53082445e4425d0ee09c50ca1 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_FNV1_64" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_FNV1_64" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_fnv1_64 \- libhashkit Documentation
 .
index 59ab6456185659121ae1d8640b28df101fcb2fe6..1bf4291e1819edbec80ca1a2f7ec403ec5d1bdcc 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_FNV1A_32" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_FNV1A_32" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_fnv1a_32 \- libhashkit Documentation
 .
index 46f2d6ff931c84c659ebbde9f9e159ebb8c543db..f274bbb78380705beafa4b595d830c1cc8542068 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_FNV1A_64" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_FNV1A_64" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_fnv1a_64 \- libhashkit Documentation
 .
index e38a46f162f6b7450c79630a3335a1c15146a227..c31372d650b6b3e6f2bc3062e7f175a12ed6fc6b 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_FREE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_FREE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_free \- libhashkit Documentation
 .
index 34b2a3124a31dd3059bd2f72c03761d8d4d3d48a..b610e1e27b0a5641bc3702d2b37fc8825f245f23 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_FUNCTIONS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_FUNCTIONS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_functions \- libhashkit Documentation
 .
index 3b2147fff810938edf689c7eeb67527d58af99b1..0d1f7b6d0bcd3bc3d0448e2147817e843308a717 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_HSIEH" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_HSIEH" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_hsieh \- libhashkit Documentation
 .
index be1014620b800368260401449fe2ad1c44d8f266..a5a5e7067ecacfde0d1ac0e2ea31842fe3b438bc 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_IS_ALLOCATED" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_IS_ALLOCATED" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_is_allocated \- libhashkit Documentation
 .
index 95a5fa099211f5c1a94070f16a0af90cf5310a7e..992f9e8a4d2f057606f64f1e9c44d836bd4286bf 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_JENKINS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_JENKINS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_jenkins \- libhashkit Documentation
 .
index 3085fd8749d958cbfef44b25904d1caccc0d6649..38489b1701d7234f726774f06eadf659ad831686 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_MD5" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_MD5" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_md5 \- libhashkit Documentation
 .
index 6d100a1a2bfdab3cfcff95aa5057b71c981fc057..5063628d170dfcc365764b7b493cb92c0a9f63fe 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_MURMUR" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_MURMUR" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_murmur \- libhashkit Documentation
 .
index b6499fda228cc3fc3eb1694974be6d38a531c1ec..aeb33a23a937933cfd03152bb14d7d645f396627 100644 (file)
@@ -1,4 +1,4 @@
-.TH "HASHKIT_VALUE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "HASHKIT_VALUE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 hashkit_value \- libhashkit Documentation
 .
index 679feed5a4f330a204e7a392a856428803821105..c1343532a5d4d1c557e0b20266cda1bbe47d04dc 100644 (file)
@@ -1,4 +1,4 @@
-.TH "LIBHASHKIT" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "LIBHASHKIT" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 libhashkit \- libhashkit Documentation
 .
index 0891b66e074f0951b7639482c14737e79b7acad8..433cd52aca9e9352181f49797115719669cd5030 100644 (file)
@@ -1,4 +1,4 @@
-.TH "LIBMEMCACHED" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "LIBMEMCACHED" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 libmemcached \- Introducing the C Client Library for memcached
 .
index 3f166b52c6982a55438504c77fb06ca80b638116..d4b1d1d5b46eb95261377aa53a24a95c57e3d13f 100644 (file)
@@ -1,4 +1,4 @@
-.TH "LIBMEMCACHED_CHECK_CONFIGURATION" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "LIBMEMCACHED_CHECK_CONFIGURATION" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 libmemcached_check_configuration \- libmemcached Documentation
 .
index 034dec92710a326277e35e0dca5b9e3eb396669a..3918f73588392be444c134b9db59ae1ab47ba54d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "LIBMEMCACHED_CONFIGURATION" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "LIBMEMCACHED_CONFIGURATION" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 libmemcached_configuration \- libmemcached Documentation
 .
index 1909596f96cc27888bcfb661c22d46df2f10e4ae..374900024dbaeaca990f5a66ea819a1e750311ee 100644 (file)
@@ -1,4 +1,4 @@
-.TH "LIBMEMCACHED_EXAMPLES" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "LIBMEMCACHED_EXAMPLES" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 libmemcached_examples \- libmemcached Documentation
 .
index 4e1e25b174cb2e67a04f9c9ddb4a76bf964073f4..a09c93200c21bc23f02c22ae85337aac29592d3c 100644 (file)
@@ -1,4 +1,4 @@
-.TH "LIBMEMCACHEDUTIL" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "LIBMEMCACHEDUTIL" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 libmemcachedutil \- libmemcached Documentation
 .
index a5886722a16dd0a91c2ea5b17cc719206c637b83..25859161116e9036a11a9ae4a080ce2773a74cbf 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMASLAP" "1" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMASLAP" "1" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memaslap \- libmemcached Documentation
 .
index 302545f664e270be270a06adcafc30cd9c2ee27f..5756dbfcc7437697249811e02b1ff09c49e031da 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached \- libmemcached Documentation
 .
index 3a601230eff9b608a22b954eb935e5504bfb820f..475a8589870f1cabc9a822607011391abbfc4ad7 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_ADD" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_ADD" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_add \- Storing and Replacing Data
 .
index 092dc0f76abea5fda136d758beb68f97216eb1eb..8c7dad81d494940dcf24dfd34d7e3f71c08bd8de 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_ADD_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_ADD_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_add_by_key \- Storing and Replacing Data
 .
index 310d4b5d5a1fef85cbfa6da75018d5478b4e5a6b..d2840a4b8f5ecfdecb8d6fde4288196dd29f83b1 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_ANALYZE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_ANALYZE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_analyze \- libmemcached Documentation
 .
index fa1c7827a27bae26547881a5a6ffe79afdbf6158..0bdc00d2d1d0fdbe2348a5263282773b8169f617 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_APPEND" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_APPEND" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_append \- Storing and Replacing Data
 .
index fe79cd9e92b8a174f3f3d1959f30ff100732f969..5fec40be49a9cc95bc4e6cc7de6230009cd28691 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_APPEND_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_APPEND_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_append_by_key \- Storing and Replacing Data
 .
index 8bb2089d33e09aa91a61df5fa11ab0d8250f9125..6322d95b9df9d5f38f3816177951b0e330f6d704 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_AUTO" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_AUTO" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_auto \- Incrementing and Decrementing Values
 .
index 2d2bed5cd69557ff5395ebe71c0ca21b7f367ca2..fa566e5b3765b6b44ccb9718024a4e56efd92947 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_BEHAVIOR" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_BEHAVIOR" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_behavior \- libmemcached Documentation
 .
index 869db4b70d60996901abeae2f6cdd06aa603749c..f0bb38dd0fa8aca26ac6c55ef4f83556215e6707 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_BEHAVIOR_GET" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_BEHAVIOR_GET" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_behavior_get \- libmemcached Documentation
 .
index ad41e06004ee911367c7403a7186399371b84822..7dcc6fa90fb37432f48201ca60509abdabcec53d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_BEHAVIOR_SET" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_BEHAVIOR_SET" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_behavior_set \- libmemcached Documentation
 .
index 21c614da0a5ceb6b8497a3c68c0960a498bca58a..482bb19e66995f137362970ffbbcc6afa13d2e63 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_CALLBACK" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_CALLBACK" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_callback \- libmemcached Documentation
 .
index 83c95ae788e549e3471feee868bdd8cfb56f23be..0215431d74fdb48bbb6401b15c49ee2b09f664c3 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_CALLBACK_GET" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_CALLBACK_GET" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_callback_get \- libmemcached Documentation
 .
index dcce9e6aad4b8371350663a1894d5e57a5f4eeff..c13e24c08aaf3a05fdb19fe0ed673b7764629069 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_CALLBACK_SET" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_CALLBACK_SET" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_callback_set \- libmemcached Documentation
 .
index d8e5a1187c40e8a8fdb327045faa60829246e93b..73e8653c425cd9fc19c9dc86c8e1217c20624cc6 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_CAS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_CAS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_cas \- Storing and Replacing Data
 .
index dba38cf79bcac7c6fe8eb5ae9acd6b43dd33aa99..4b4ea9b6cdbea810ac27148250b7578c59d8ef76 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_CAS_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_CAS_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_cas_by_key \- Storing and Replacing Data
 .
index 12bbd403e2f3273ee0938d922cddb8e79ad98d5d..65d3f6eca966691675638a0a312d9d32f67a03f1 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_CLONE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_CLONE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_clone \- libmemcached Documentation
 .
index d9a1bb8ff88818498b6d940deda1c2ae2e5352eb..d1c3d2dc1f1ec7758772322f84d3d23dfe6a7a4e 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_CREATE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_CREATE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_create \- libmemcached Documentation
 .
index 18679060bd82b99bf736d8c6001a81d5fca48e4c..a79c6685dd4483a758fcbab757057be1f128364c 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_DECREMENT" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_DECREMENT" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_decrement \- Incrementing and Decrementing Values
 .
index cd0e035f93dd4974f4a06abd86eee820c32c600b..994726474991fee5061b2b0e322d8136f97b2b9e 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_DECREMENT_WITH_INITIAL" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_DECREMENT_WITH_INITIAL" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_decrement_with_initial \- Incrementing and Decrementing Values
 .
index d691991919a035432414867ddd704eab6a4c09b5..d4215c9b1a82ea1f4701b0cf952fc00b21a0128d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_DELETE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_DELETE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_delete \- libmemcached Documentation
 .
index ae99f61e0f10ed01271d8557ee7b27f900b20e1d..6d4ef4169d524f17a1dea70279d55ae75ecce91b 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_DELETE_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_DELETE_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_delete_by_key \- libmemcached Documentation
 .
index 928fb74ae9b98a2dac55625e297648a1e2e002df..ff347c88c224628272e81ba5345d9c818aa8f92e 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_DESTROY_SASL_AUTH_DATA" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_DESTROY_SASL_AUTH_DATA" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_destroy_sasl_auth_data \- libmemcached Documentation
 .
index c311fe21b0d67173640ebbddfbfb65856df08f0f..5df723dee642dfaadf43a3fa98b0a09419989cec 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_DUMP" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_DUMP" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_dump \- libmemcached Documentation
 .
index 68eab8f82fd830ea02a6d4bdcbe334c6f0896f7d..ca505f965ae90a0dfec7a8770634b2e83bdb5fa0 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_FETCH" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_FETCH" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_fetch \- Retrieving data from the server
 .
index c999cb2037dfa84b5432e611c11d35abad8beb15..5052fff9ae73db8d5ddaa249a3a5fe3e11f6af92 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_FETCH_EXECUTE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_FETCH_EXECUTE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_fetch_execute \- Retrieving data from the server
 .
index 80ed3cb9bcf9ea465f2d1e6e77ffee89af6a10bf..aabe6719c13633c61f23f92448be4a8a444045aa 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_FETCH_RESULT" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_FETCH_RESULT" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_fetch_result \- Retrieving data from the server
 .
index 61449b470eb62770e239ea0b48eae92132ef0b5d..48709ea39d1d0906c189eb394d069aeadf65aa91 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_FLUSH" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_FLUSH" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_flush \- libmemcached Documentation
 .
index 45c6bbf5b106e99a0565f89c130ed378aca46e3f..500d334f29b920f65db672f8557948f0fe7caa00 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_FLUSH_BUFFERS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_FLUSH_BUFFERS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_flush_buffers \- libmemcached Documentation
 .
index 1ab8e7ae37cb864ac2599f3926dde84a29c30c86..34b8b1153d785e4d0b58eaaf2026080869191aab 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_FREE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_FREE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_free \- libmemcached Documentation
 .
index 48008e8f902688c5dc81685c13df002e1187f695..07c3109942535af1eb5f9874ed42020bdd6d7185 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_GENERATE_HASH" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_GENERATE_HASH" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_generate_hash \- Generating hash values directly
 .
index 831f1760f312bb9d919eac915c57201d1eecec5a..037a9cee1f1c7ffdacc676cf7b9aeac6e9e16c4b 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_GENERATE_HASH_VALUE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_GENERATE_HASH_VALUE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_generate_hash_value \- Generating hash values directly
 .
index f8c513b611d7a4383520a01fce35fc7a549c4b95..f1d8caf9aa92dbdb6b4b8197de0427a129c8df14 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_GET" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_GET" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_get \- Retrieving data from the server
 .
index 91aaa444d86c016e3188bb73e9c2787d0c1dc89f..e334c296e1ab037254ce2773bd464ab3b9d791ef 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_GET_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_GET_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_get_by_key \- Retrieving data from the server
 .
index 41576bb9942f4ebffeaa1a141c0538fc9adab34b..6eb34eb9af7c30d88cc6c4a3b648ac7ea408f366 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_GET_MEMORY_ALLOCATORS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_GET_MEMORY_ALLOCATORS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_get_memory_allocators \- libmemcached Documentation
 .
index 440234273c40bc05cb8c6dc7c4e0f355d9f5706e..653c445fa28c036322cf5c1ac5533867c1dc43b8 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_GET_SASL_CALLBACKS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_GET_SASL_CALLBACKS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_get_sasl_callbacks \- libmemcached Documentation
 .
index 6303ca3142a8880c865e8c0f194daa00c8c9b0bc..990c5772fa4295a884501c60ad247d6278df9da6 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_GET_USER_DATA" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_GET_USER_DATA" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_get_user_data \- libmemcached Documentation
 .
index 37c066aff225d745e5da91142c30008b8df428db..fb161b95401b131bbb4e93b159c316f5425432ae 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_INCREMENT" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_INCREMENT" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_increment \- Incrementing and Decrementing Values
 .
index 64147f044a668190e66c3abaa5f3deb7f89f1445..5a43ea9ca2cdcd4d09f659b0aa73417d738b4299 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_INCREMENT_WITH_INITIAL" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_INCREMENT_WITH_INITIAL" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_increment_with_initial \- Incrementing and Decrementing Values
 .
index 2c75bac4c27c8a8d424fde36cf7165d5b3af12d2..e6b419cec47e6d264fa6c334e90992c5acaab8a7 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_LIB_VERSION" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_LIB_VERSION" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_lib_version \- libmemcached Documentation
 .
index f4b2f6b9985cc35191b01d1133e6fedc9060aaa6..2a4a57f9864ea6a0f4bd7aed1db0c3349fa6c6ff 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_MEMORY_ALLOCATORS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_MEMORY_ALLOCATORS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_memory_allocators \- libmemcached Documentation
 .
index 2f05bd78c70e06f67a1a6ac2ecfafb900087355d..0315eed339a121234ad88df866a5b9f234d2948e 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_MGET" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_MGET" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_mget \- Retrieving data from the server
 .
index 420a78089afefae4f4d9b0181c72bd0d06cbc55d..1b2e4a6990a5d9aabc1f663b8769759bca7b1321 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_MGET_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_MGET_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_mget_by_key \- Retrieving data from the server
 .
index fdb5787fafeb349692dcd73effb38d90acdf9418..28a43b7754f92f9c3da16afc62c2691445073827 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_MGET_EXECUTE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_MGET_EXECUTE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_mget_execute \- Retrieving data from the server
 .
index 2b4ad9ac08b50eecbd02bc4efc30121d2f1f1e0b..8e591b9119cf353cc78a5d8e7df9199b8c38c61a 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_MGET_EXECUTE_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_MGET_EXECUTE_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_mget_execute_by_key \- Retrieving data from the server
 .
index 758a89ff73dc3e8f669928c9fbff3228e8a27b37..2ddf8c7656b720945bfb6aaccd9594573de99ea9 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_POOL" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_POOL" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_pool \- libmemcached Documentation
 .
index 164e34070081282f1cca9df55ca9c92f268e6ced..73550dabc678bbb4a807471185cdb97169fb9bbf 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_POOL_BEHAVIOR_GET" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_POOL_BEHAVIOR_GET" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_pool_behavior_get \- libmemcached Documentation
 .
index b88eaaaa7e0620431ed11f26d4b8d791b5dc7c4a..7551191828e119f449707bf46729264951b6b930 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_POOL_BEHAVIOR_SET" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_POOL_BEHAVIOR_SET" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_pool_behavior_set \- libmemcached Documentation
 .
index d3e542249208b777145a7d420af6d5501c3299a8..740c8e0c12a4200f8dd6542d2b3655be9fba6aff 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_POOL_CREATE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_POOL_CREATE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_pool_create \- libmemcached Documentation
 .
index 5c97f510c6c9b09c3901b26105cace32f75a5d58..b1c96d708fbeeb9ca9ad4948634b7024988164b2 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_POOL_DESTROY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_POOL_DESTROY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_pool_destroy \- libmemcached Documentation
 .
index d9cf40cbedf7fefb2430603ae409801adb2df4e1..10338aa55620c7c951a6c54f0a083a3b1d6fc4e4 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_POOL_POP" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_POOL_POP" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_pool_pop \- libmemcached Documentation
 .
index 615a39a58f2126452c6a1f70d9ad441455818043..ff8cbe45b507b16d142c6018191ce3f3c33909c2 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_POOL_PUSH" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_POOL_PUSH" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_pool_push \- libmemcached Documentation
 .
index 642b70ec7084fa086d5572f30f18623999b53aec..e61579a61b30d0f56a083292c66ac6a5e78cd636 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_POOL_ST" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_POOL_ST" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_pool_st \- libmemcached Documentation
 .
index 3ff2f08008b081ca83b775f7c0b76d022dc6d728..c18fb4f631f449de41bae679753264e112b23c0e 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_PREPEND" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_PREPEND" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_prepend \- Storing and Replacing Data
 .
index 321e9fa6b3a041ecfff14caaa495123a64c1b57b..fef8339dca1684cfe11f68bd39f1d9f3014481c8 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_PREPEND_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_PREPEND_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_prepend_by_key \- Storing and Replacing Data
 .
index 3995eed9b8138babf16c628915566998e165ae8e..ebca6513f70513cf181465a99b325911ab0383fe 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_QUIT" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_QUIT" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_quit \- libmemcached Documentation
 .
index e13fabc675092cebb01d185e0198412555444d4b..16ca5449a74b007094859b20fd6bdf1b27e8a3e4 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_REPLACE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_REPLACE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_replace \- Storing and Replacing Data
 .
index dace8f26e2b82c74e18ae51e24cec58abda4e227..986923d35b41f2b2497f74837ec2a00303d9af4a 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_REPLACE_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_REPLACE_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_replace_by_key \- Storing and Replacing Data
 .
index 8fb29d95404db0de1d65def36aef785f23e763ff..89ea077a5265a7237f1f5459df3f479156111a25 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_RESULT_CAS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_RESULT_CAS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_result_cas \- Working with result sets
 .
index 427a8a51bf4ba438d6725ad5cc6eae5440f27db3..952513d61a864d37526cbc7f0b65fe3ac88ad924 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_RESULT_CREATE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_RESULT_CREATE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_result_create \- Working with result sets
 .
index 38e0b2d75ec9217aa40968d7197bd52b9723d816..0bc087471a402765062488c5b1656261a70e1d93 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_RESULT_FLAGS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_RESULT_FLAGS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_result_flags \- Working with result sets
 .
index b3560e17fc90dd2cc66d0520bdea31ffb1779253..a7093f337dba9e8d55c5bab9c0860ce46a06fc57 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_RESULT_FREE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_RESULT_FREE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_result_free \- Working with result sets
 .
index abbe59c57efcf9c26481c1413d098ff5a093ead1..86619527955024ae0ee5a306a77a25e8190e8b41 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_RESULT_KEY_LENGTH" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_RESULT_KEY_LENGTH" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_result_key_length \- Working with result sets
 .
index 175531a8d0954c3cc2aedbc409e9cd99cfb0d246..4572bb4a543e25656889c611147648a634f726bf 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_RESULT_KEY_VALUE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_RESULT_KEY_VALUE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_result_key_value \- Working with result sets
 .
index 080d150878f62db67f2250c0aae75ba25da9cb2e..4978d9214ad43622056016e762ce3814f44a0875 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_RESULT_LENGTH" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_RESULT_LENGTH" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_result_length \- Working with result sets
 .
index 5b30c3e750ad57d6d2a9048245a0e8c3bfe65408..14c7bdf8b9d2ab061a5560ab17f80b2d703ae1bd 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_RESULT_ST" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_RESULT_ST" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_result_st \- Working with result sets
 .
index 8af1561f1e19f8b274396d58b1d33735f941fa00..b153a95710ee17445c206c976d2c4fca84426f6e 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_RESULT_VALUE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_RESULT_VALUE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_result_value \- Working with result sets
 .
index a3c93c526597f755a40655a81b7e178ec53bc4dc..fc954c8a0ed5ccb267f393aecbf7839c48b2133b 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SASL" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SASL" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_sasl \- libmemcached Documentation
 .
index cdd1bf7ec0094f2bc9894a58f1869be797b15223..caa34279626013944e3bfac7a1eb1b352ddea426 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SASL_SET_AUTH_DATA" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SASL_SET_AUTH_DATA" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_sasl_set_auth_data \- libmemcached Documentation
 .
index c1ce80bfad29da762950c97357f309aa3aad5761..5f6331176e1ebf9dbdfe35d8151e2ff59b0d98d9 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVER_ADD" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVER_ADD" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_server_add \- libmemcached Documentation
 .
index 9d3cc215f7b688d9bf767e43e5b434e137d43086..010aa35fc8f413b6246358770aa0581232d7dc41 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVER_ADD_UNIX_SOCKET" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVER_ADD_UNIX_SOCKET" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_server_add_unix_socket \- libmemcached Documentation
 .
index 74d1f0ccf12d45d20c39d3457157b3583aaaabde..1e330dc4fca32ca2419f1bd8268fab5aed2eeae9 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVER_COUNT" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVER_COUNT" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_server_count \- libmemcached Documentation
 .
index 51dae118bf944393149480e205b3bbea50897842..f979b7137f69f1747550e9afe1034add7fe7fba0 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVER_CURSOR" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVER_CURSOR" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_server_cursor \- libmemcached Documentation
 .
index 0b6e854c76fae3238ac621aefc25c42e0ca4fd47..bdb0ff08a7614a993c12ec51ef7b4033538ad85a 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVER_LIST" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVER_LIST" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_server_list \- libmemcached Documentation
 .
index d93f1b1531692a93ff83cfd10790bace4e5c9ae7..6340c564a86614bd065366bfe3765796b7a8cb75 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVER_LIST_APPEND" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVER_LIST_APPEND" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_server_list_append \- libmemcached Documentation
 .
index 8c3029732eb95db4bcadace7c649eedf9b66475b..bbb504d1056d408171b9957e8741e55ef47e297a 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVER_LIST_COUNT" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVER_LIST_COUNT" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_server_list_count \- libmemcached Documentation
 .
index cffefbc373fdbdd6659d7cd6e0d054dd85d45dd9..217396bdb6d0cfe4023cf488b9e76740013fe964 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVER_LIST_FREE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVER_LIST_FREE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_server_list_free \- libmemcached Documentation
 .
index b2c4b7e159e71630bdfa775becee345e698cc4d6..fc1c1123bc1d669a6b106d97503fa6b3e6db4f3d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVER_PUSH" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVER_PUSH" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_server_push \- libmemcached Documentation
 .
index a4041290e70ccffafd8179ee71c0778c91f4c67b..1e13334257ee049022969c8ec9d1d4a80d322b8d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVER_ST" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVER_ST" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_server_st \- libmemcached Documentation
 .
index 702d6fa58b89fc3958b7baa55544af0320ae2871..924703046d197626f6b0ea94ba3684f252343b4d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVERS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVERS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_servers \- libmemcached Documentation
 .
index e692e9c188442d979c342c75bd09ed7767e32460..cbb4ecdaaee0a455b5e09c468199ccb37261fd81 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVERS_PARSE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVERS_PARSE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_servers_parse \- libmemcached Documentation
 .
index 83d02d593b168e0d2b6e0aa17f3d18ef7c34c8ef..7942d59aaa454ccd2f4d9e17be5fb212c10e2ade 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SERVERS_RESET" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SERVERS_RESET" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_servers_reset \- libmemcached Documentation
 .
index 326dd461252ce8bd7d237752ec1a08fa139741c4..0bef67c24fa3c79dcd142284b31ad6e0118bdf4c 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SET" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SET" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_set \- Storing and Replacing Data
 .
index 1c45ac42c5970398aafe9a30149a4fc1a7d87880..e96b4094a99fcd45232b4d5317758babff810acc 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SET_BY_KEY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SET_BY_KEY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_set_by_key \- Storing and Replacing Data
 .
index faa98be0f03ddf30253e402dd48acc66a9f5a060..0f74f9ef5c894e925f33ff746ed2b5d89d1a86af 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SET_MEMORY_ALLOCATORS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SET_MEMORY_ALLOCATORS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_set_memory_allocators \- libmemcached Documentation
 .
index d2a0f1e1efe8853f5405021afcf83c090b928c15..819314a9651b2a6a577d77c6461530712a178bf1 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SET_MEMORY_ALLOCATORS_CONTEXT" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SET_MEMORY_ALLOCATORS_CONTEXT" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_set_memory_allocators_context \- libmemcached Documentation
 .
index e7321ff8b9b46fef4f075a8944194075c9c5af76..b9221c6037de8561daed2da9bf9b347f675f23a8 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SET_SASL_CALLBACKS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SET_SASL_CALLBACKS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_set_sasl_callbacks \- libmemcached Documentation
 .
index 838e24a0a01ebf61449ef78978d098cef099991c..c24fb4a7c9c69261ccffedbbb2bc10436a7be3ff 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_SET_USER_DATA" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_SET_USER_DATA" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_set_user_data \- libmemcached Documentation
 .
index 3c2817d72a3557dbebd85f3739b54d604b9f3b86..e4960a4e8b2de67b20b982f1c9be1621e5d59fc8 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_STAT" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_STAT" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_stat \- libmemcached Documentation
 .
index 4aa87a0e89cb25b9beefc014669fd53189c59056..f7da60bd55c5a56ddb85092e0cc23b56286629f5 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_STAT_EXECUTE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_STAT_EXECUTE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_stat_execute \- libmemcached Documentation
 .
index e03b7dfc5aa16833d366a1110edd7416f565c28c..bb4bfb548f05c192df839d721041667867cd6dcc 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_STAT_GET_KEYS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_STAT_GET_KEYS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_stat_get_keys \- libmemcached Documentation
 .
index 0e94a6bb8e1a8344ebd979e6aa495dfcd945de8f..7ace4aa484297e7957d697abb9fae8637d0a6e87 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_STAT_GET_VALUE" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_STAT_GET_VALUE" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_stat_get_value \- libmemcached Documentation
 .
index 66dd061350fc4bd2eab74b87a630b6a0d157cbba..10f01bfd9fab8923f43504928aa98025c24918a5 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_STAT_SERVERNAME" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_STAT_SERVERNAME" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_stat_servername \- libmemcached Documentation
 .
index 60a558284c954c68403df3d9ce93f14d4c6591c7..a3c6fb3c3e4a34b8650cfaf827e779be2c67aba0 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_STATS" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_STATS" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_stats \- libmemcached Documentation
 .
index bf5d35e8b6fbd562ccbbef4930bb1e020f6ead61..0fcd30363307aab4f60e82bc4c61b989c7afba84 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_STRERROR" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_STRERROR" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_strerror \- libmemcached Documentation
 .
index 01f3e08859d8f42548262315fbba80508f9b734a..dc88434926a1533735ac53d7838f5501d529260f 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_USER_DATA" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_USER_DATA" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_user_data \- libmemcached Documentation
 .
index 2eef9f5101a5b48cca4862239ade14546b82cc24..3ed1fa3c557c55000da1944102856e0a25123c79 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_VERBOSITY" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_VERBOSITY" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_verbosity \- libmemcached Documentation
 .
index 64d744e4a3c45a6542f936d5e0a415b409d2b47c..16829ecfb2451ba9978716f43d9255a3a75fd8fc 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCACHED_VERSION" "3" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCACHED_VERSION" "3" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcached_version \- libmemcached Documentation
 .
index a0aa1d67cc2a7fb14b7c63035f640b0cbd6d396e..5a5943cc332c6eebee479442f1c833b12d3f9705 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCAPABLE" "1" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCAPABLE" "1" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcapable \- libmemcached Documentation
 .
index c3af50aff45f22e928f082e9f506e0ef8c03f979..5a998e8fa203b65df93ec89054027f6870c2a9c7 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCAT" "1" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCAT" "1" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcat \- libmemcached Documentation
 .
index 7b43c2a6e15aea654a75f1ad039f00336507327a..c97a5bad7e6558fc1dff226448765268a8a4f92f 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMCP" "1" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMCP" "1" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memcp \- libmemcached Documentation
 .
index 857c7689c811889d85ad17341b7647576c92eec5..edf99b392e1f4b9237864f444b987fb897d8b921 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMDUMP" "1" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMDUMP" "1" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memdump \- libmemcached Documentation
 .
index 7063a7641fe6366a7d77a856db8f9dcce0b7b3ed..fc69e5510fa385c87f5234bd95d40d5a88e8108c 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMERROR" "1" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMERROR" "1" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memerror \- libmemcached Documentation
 .
index b71454ccf90dcdd9405a70316bc227f68a838c7f..ae670fd0e7802a9d1a126a286aaafd3b4a9d3b9f 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMFLUSH" "1" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMFLUSH" "1" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memflush \- libmemcached Documentation
 .
index 0dc96a7ee2109717e6bc73a8093c56391694f00c..0d44a36019a9e0df595180b2f0f09811c51b0fc3 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMRM" "1" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMRM" "1" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memrm \- libmemcached Documentation
 .
index 33346488ce971d2408c0e0f18271e1e5b6009008..47bc8094abf4e822eb6c086b5291e89f10fa4ca7 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMSLAP" "1" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMSLAP" "1" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memslap \- libmemcached Documentation
 .
index 2e9f99291b0f34b7915d52ce31747e4089892b28..848b84e215c7375282d3b5e5930048c3d5f786b3 100644 (file)
@@ -1,4 +1,4 @@
-.TH "MEMSTAT" "1" "April 13, 2011" "0.47" "libmemcached"
+.TH "MEMSTAT" "1" "April 14, 2011" "0.47" "libmemcached"
 .SH NAME
 memstat \- libmemcached Documentation
 .
index 787bc49ad77c8d66811f532dee4745591136c033..aac70391f2fcc68eb4d98f44f0f677f4684c20d2 100644 (file)
@@ -41,73 +41,71 @@ function set by memcached_callback_set().
 memcached_callback_set() changes the function/structure assigned by a
 callback flag. No connections are reset.
 
-You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for any 
-of the callbacks
+You can use MEMCACHED_CALLBACK_USER_DATA to provide custom context if required for any of the callbacks.
 
 
 .. c:var:: MEMCACHED_CALLBACK_CLEANUP_FUNCTION
  
- When memcached_delete() is called this function will be excuted. At the
- point of its execution all connections have been closed.
+When memcached_delete() is called this function will be excuted. At the point of its execution all connections are closed.
  
 
 
 .. c:var:: MEMCACHED_CALLBACK_CLONE_FUNCTION
  
- When memcached_delete() is called this function will be excuted. At the
- point of its execution all connections have been closed.
+When memcached_delete() is called this function will be excuted. At the
+point of its execution all connections are closed.
  
 
 
 .. c:var:: MEMCACHED_CALLBACK_PREFIX_KEY
  
- You can set a value which will be used to create a domain for your keys.
- The value specified here will be prefixed to each of your keys. The value can not
- be greater then MEMCACHED_PREFIX_KEY_MAX_SIZE - 1 and will reduce MEMCACHED_MAX_KEY by
- the value of your key. The prefix key is only applied to the primary key,
- not the master key. MEMCACHED_FAILURE will be returned if no key is set. In the case
- of a key which is too long MEMCACHED_BAD_KEY_PROVIDED will be returned.
+You can set a value which will be used to create a domain for your keys.
+The value specified here will be prefixed to each of your keys. The value can not be greater then MEMCACHED_PREFIX_KEY_MAX_SIZE - 1 and will reduce MEMCACHED_MAX_KEY by the value of your key. 
+
+The prefix key is only applied to the primary key, not the master key. MEMCACHED_FAILURE will be returned if no key is set. In the case of a key which is too long, MEMCACHED_BAD_KEY_PROVIDED will be returned.
  
- If you set a value with the value being NULL then the prefix key is disabled.
+If you set a value with the value being NULL then the prefix key is disabled.
 
 
 .. c:var:: MEMCACHED_CALLBACK_USER_DATA
  
- This allows you to store a pointer to a specifc piece of data. This can be
- retrieved from inside of memcached_fetch_execute(). Cloning a memcached_st
- will copy the pointer to the clone.
+This allows you to store a pointer to a specifc piece of data. This can be
+retrieved from inside of memcached_fetch_execute(). Cloning a memcached_st
+will copy the pointer to the clone.
  
 
 
 .. c:var:: MEMCACHED_CALLBACK_MALLOC_FUNCTION
  
- DEPRECATED: use memcached_set_memory_allocators instead.
+DEPRECATED: use memcached_set_memory_allocators instead.
  
 
 
 .. c:var:: MEMCACHED_CALLBACK_REALLOC_FUNCTION
  
- DEPRECATED: use memcached_set_memory_allocators instead.
+DEPRECATED: use memcached_set_memory_allocators instead.
  
 
 
 .. c:var:: MEMCACHED_CALLBACK_FREE_FUNCTION
  
- DEPRECATED: use memcached_set_memory_allocators instead.
+DEPRECATED: use memcached_set_memory_allocators instead.
  
 
 
 .. c:var:: MEMCACHED_CALLBACK_GET_FAILURE
  
- This function implements the read through cache behavior. On failure of retrieval this callback will be called. 
- You are responsible for populating the result object provided. This result object will then be stored in the server and
- returned to the calling process. You must clone the memcached_st in order to
- make use of it. The value will be stored only if you return
- MEMCACHED_SUCCESS or MEMCACHED_BUFFERED. Returning MEMCACHED_BUFFERED will
- cause the object to be buffered and not sent immediatly (if this is the default behavior based on your connection setup this will happen automatically).
+This function implements the read through cache behavior. On failure of retrieval this callback will be called. 
+
+You are responsible for populating the result object provided. This result object will then be stored in the server and returned to the calling process. 
+
+You must clone the memcached_st in order to
+make use of it. The value will be stored only if you return
+MEMCACHED_SUCCESS or MEMCACHED_BUFFERED. Returning MEMCACHED_BUFFERED will
+cause the object to be buffered and not sent immediatly (if this is the default behavior based on your connection setup this will happen automatically).
  
- The prototype for this is:
- memcached_return_t (\*memcached_trigger_key)(memcached_st \*ptr, char \*key, size_t key_length, memcached_result_st \*result);
+The prototype for this is:
+memcached_return_t (\*memcached_trigger_key)(memcached_st \*ptr, char \*key, size_t key_length, memcached_result_st \*result);
  
 
 
index 5afccee7f4e5f3fe349e9a4a9c8c7b4bdd77f4dd..f628f69e96a68e887f15bc4880c8961aacb15a8d 100644 (file)
@@ -25,8 +25,8 @@ memcached_delete_by_key() works the same, but it takes a master key to
 find the given value.
 
 Expiration works by placing the item into a delete queue, which means that
-it won't possible to retrieve it by the "get" command, but "add" and 
-"replace" command with this key will also fail (the "set" command will 
+it won't be possible to retrieve it by the "get" command. The "add" and 
+"replace" commands with this key will also fail (the "set" command will 
 succeed, however). After the time passes, the item is finally deleted from server memory.
 
 Please note the the Danga memcached server removed tests for expiration in
index 9b6e887e1ced9b70055c075c48d8ea95c61e70ce..a7dcb4fe54587ace8b1ab02ec2f563ac4ec2a51c 100644 (file)
@@ -42,12 +42,12 @@ DESCRIPTION
 -----------
 
 
-memcached_dump() is used to get a list of keys found  memcached(1) servers.
+memcached_dump() is used to get a list of keys found in memcached(1) servers.
 Because memcached(1) does not guarentee to dump all keys you can not assume
 you have fetched all keys from the server. The function takes an array
 of callbacks that it will use to execute on keys as they are found.
 
-Currently the binar protocol is not testsed.
+Currently the binary protocol is not testsed.
 
 
 ------
index f6813d45c493f865985033f0ce07fb5e87613b72..dcb931c77e9a31ee7bab44d592ed7814ad6c8c12 100644 (file)
@@ -65,7 +65,7 @@ memcached_return_t pointer to hold any error. The object will be returned
 upon success and NULL will be returned on failure. MEMCACHD_END is returned
 by the \*error value when all objects that have been found are returned.
 The final value upon MEMCACHED_END is null. Values returned by
-memcached_fetch() musted be free'ed by the caller. memcached_fetch() will
+memcached_fetch() must be freed by the caller. memcached_fetch() will
 be DEPRECATED in the near future, memcached_fetch_result() should be used
 instead.
 
@@ -89,7 +89,7 @@ memcached_mget_execute() and memcached_mget_execute_by_key() is
 similar to memcached_mget(), but it may trigger the supplied callbacks
 with result sets while sending out the queries. If you try to perform
 a really large multiget with memcached_mget() you may encounter a
-deadlock in the OS kernel (we fail to write data to the socket because
+deadlock in the OS kernel (it will fail to write data to the socket because
 the input buffer is full). memcached_mget_execute() solves this
 problem by processing some of the results before continuing sending
 out requests. Please note that this function is only available in the
@@ -100,9 +100,9 @@ as memcached_get() and memcached_mget(). The difference is that they take
 a master key that is used for determining which server an object was stored
 if key partitioning was used for storage.
 
-All of the above functions are not testsed when the \ ``MEMCACHED_BEHAVIOR_USE_UDP``\ 
+All of the above functions are not tested when the \ ``MEMCACHED_BEHAVIOR_USE_UDP``\ 
 has been set. Executing any of these functions with this behavior on will result in
-\ ``MEMCACHED_NOT_SUPPORTED``\  being returned or, for those functions which do not return
+\ ``MEMCACHED_NOT_SUPPORTED``\  being returned, or for those functions which do not return
 a \ ``memcached_return_t``\ , the error function parameter will be set to
 \ ``MEMCACHED_NOT_SUPPORTED``\ .
 
index 7f1cd10e49d5a79d4130fc5497589eaccd56acd9..40219079d9f4281b79c4fee0352cb199515c9c3a 100644 (file)
@@ -45,7 +45,7 @@ DESCRIPTION
 -----------
 
 
-libmemcached(3) allows you to specify your own memory allocators optimized
+libmemcached(3) allows you to specify your own memory allocators, optimized
 for your application. This enables libmemcached to be used inside of applications that have their own malloc implementation.
 
 memcached_set_memory_allocators() is used to set the memory allocators used
index 9243d6b478b8d25c6281763d216f53a3c316ce0b..e8aba51842a009d50d6c2b982c13036806e59223 100644 (file)
@@ -59,9 +59,9 @@ DESCRIPTION
 
 libmemcached(3) can optionally return a memcached_result_st which acts as a
 result object. The result objects have added benefits over the character
-pointer returns in that they are forward compatible with new return items
+pointer returns, in that they are forward compatible with new return items
 that future memcached servers may implement (the best current example of
-this is the CAS return item). The structures can also be reused which will
+this is the CAS return item). The structures can also be reused, which will
 save on calls to malloc(3). It is suggested that you use result objects over
 char \* return functions.
 
@@ -72,7 +72,7 @@ memcached_result_create() will either allocate memory for a
 memcached_result_st or will initialize a structure passed to it.
 
 memcached_result_free() will deallocate any memory attached to the
-structure. If the structure was also alloacted, it will deallocate it.
+structure. If the structure was also allocated, it will deallocate it.
 
 memcached_result_key_value() returns the key value associated with the
 current result object.
@@ -91,7 +91,7 @@ current result object.
 
 memcached_result_cas() returns the cas associated with the
 current result object. This value will only be available if the server
-testss it.
+tests it.
 
 memcached_result_set_value() takes a byte array and a size and sets
 the result to this value. This function is used for trigger responses.
index 30aa72ca7ed2f72e48d6f87fa90816dda5b5efb8..bf0251dd9415e70542bd5474e57408e8fe917921 100644 (file)
@@ -44,7 +44,7 @@ libsasl to perform SASL authentication.
 Please note that SASL requires the memcached binary protocol, and you have
 to specify the callbacks before you connect to the server.
 
-memcached_set_sasl_auth_data() is a helper function for you defining
+memcached_set_sasl_auth_data() is a helper function defining
 the basic functionality for you, but it will store the username and password
 in memory. If you choose to use this method you have to call
 memcached_destroy_sasl_auth_data before calling memcached_free to avoid
index c2f08b3c4f527f19cf1eb23ed9c524266a768a89..4cdbd99440a706ebed6a76ffa01f47c01fecfb0a 100644 (file)
@@ -49,8 +49,8 @@ DESCRIPTION
 memcached_set(), memcached_add(), and memcached_replace() are all used to
 store information on the server. All methods take a key, and its length to
 store the object. Keys are currently limited to 250 characters by the
-memcached(1) server. You must also supply a value and a length. Optionally you
-may tests an expiration time for the object and a 16 byte value (it is
+memcached(1) server. You must supply both a value and a length. Optionally you
+may test an expiration time for the object and a 16 byte value (it is
 meant to be used as a bitmap).
 
 memcached_set() will write an object to the server. If an object already
@@ -87,12 +87,12 @@ If you are looking for performance, memcached_set() with non-blocking IO is
 the fastest way to store data on the server.
 
 All of the above functions are testsed with the \ ``MEMCACHED_BEHAVIOR_USE_UDP``\ 
-behavior enabled. But when using these operations with this behavior on, there 
+behavior enabled. However, when using these operations with this behavior on, there 
 are limits to the size of the payload being sent to the server.  The reason for 
-these limits is that the Memcahed Server does not allow multi-datagram requests
+these limits is that the Memcached Server does not allow multi-datagram requests
 and the current server implementation sets a datagram size to 1400 bytes. Due 
 to protocol overhead, the actual limit of the user supplied data is less than 
-1400 bytes and depends on the protocol in use as well as the operation being 
+1400 bytes and depends on the protocol in use as, well as the operation being 
 executed. When running with the binary protocol, \ `` MEMCACHED_BEHAVIOR_BINARY_PROTOCOL``\ , 
 the size of the key,value, flags and expiry combined may not exceed 1368 bytes. 
 When running with the ASCII protocol, the exact limit fluctuates depending on 
index 01403a16480141e17a352ef322e41dd8e09c7c6e..a670c78f8e3280c475dd4c9b405675b43e03d559 100644 (file)
@@ -39,7 +39,7 @@ DESCRIPTION
 
 
 memcached_lib_version() is used to return a simple version string representing
-the libmemcached version (version of the client library, not server)
+the libmemcached version (client library version, not server version)
 
 memcached_version() is used to set the major, minor, and micro versions of each
 memcached server being used by the memcached_st connection structure. It returns the 
index a8ac4e435ebf7832fa4a0956e6d4b8199d85b769..b9d2f5a80424363bd56e7f238be97e921a102163 100644 (file)
@@ -16,29 +16,29 @@ SYNOPSIS
 
 .. option:: -h hostname
  
- Specify the hostname to connect to. The default is \ *localhost*\ 
+Specify the hostname to connect to. The default is \ *localhost*\ 
 
 .. option:: -p port
  
- Specify the port number to connect to. The default is \ *11211*\ 
+Specify the port number to connect to. The default is \ *11211*\ 
  
 
 
 .. option:: -c
  
- Generate a coredump when it detects an error from the server.
+Generate a coredump when it detects an error from the server.
  
 
 
 .. option:: -v
  
-  Print out the comparison when it detects an error from the server.
+Print out the comparison when it detects an error from the server.
  
 
 
 .. option:: -t n
  
- Set the timeout from an IO operation to/from the server to \ *n*\  seconds.
+Set the timeout from an IO operation to/from the server to \ *n*\  seconds.
  
 -----------
 DESCRIPTION
index 6e12bedd4410f25c6482b96302504f64fa1375e1..7e620ccaf10fc3e5a6595311ca9cfd19060a0700 100644 (file)
@@ -26,11 +26,10 @@ DESCRIPTION
 It is similar to the standard UNIX cp(1) command.
 
 The key names will be the names of the files,
-without any directory path part.
+without any directory path.
 
 You can specify servers via the \ **--servers**\  option or via the
-environment variable \ ``MEMCACHED_SERVERS``\ . If you specify neither of
-these, the final value in the command line list is the name of a
+environment variable \ ``MEMCACHED_SERVERS``\. If you do not specify either these, the final value in the command line list is the name of a
 server(s).
 
 For a full list of operations run the tool with the \ **--help**\  option.
index 74e1254f17efc1518987099efc924399fd9ab9d9..fbdb8c1c163df162f1f17368af9279f9f1f5bdce 100644 (file)
@@ -21,7 +21,7 @@ DESCRIPTION
 -----------
 
 
-\ **memdump**\  currently dumps a list of "keys" from all servers that 
+\ **memdump**\  dumps a list of "keys" from all servers that 
 it is told to fetch from. Because memcached does not guarentee to
 provide all keys it is not possible to get a complete "dump".
 
index 7e2d967f4e59a5a95fa0349155be0ab46bfec82f..7501c07108422e7513311dde29b5f9b2411bc96f 100644 (file)
@@ -3,7 +3,7 @@ memerror - translate an error code to a string
 ==============================================
 
 
-Translate a memcached error code to a string
+Translates a memcached error code into a string
 
 
 --------
@@ -21,7 +21,7 @@ DESCRIPTION
 -----------
 
 
-\ **memerror**\  translate an error code from libmemcached(3) to  a human
+\ **memerror**\  translate an error code from libmemcached(3) into a human
 readable string.
 
 For a full list of operations run the tool with the \ **--help**\  option.
index 6cb0472809ed6912e3e5dbfa604654dba25223eb..e02969bd2106e26127bc2b413669ddbf7ba537cb 100644 (file)
@@ -22,7 +22,7 @@ DESCRIPTION
 
 
 \ **memflush**\  resets the contents of memcached(1) servers.
-This means all data in these servers will be deleted.
+This means that all data in the specified servers will be deleted.
 
 You can specify servers via the \ **--servers**\  option or via the
 environment variable \ ``MEMCACHED_SERVERS``\ .
index cde4ace733c8f2972a6116639289bda1be7303a8..1996b99f779b4cf4f6b03622994244bfb32f9963 100644 (file)
@@ -20,12 +20,9 @@ DESCRIPTION
 
 
 \ **memslap**\  is a load generation and benchmark tool for memcached(1)
-servers. It generates configurable workload such as threads, concurrencies, connections,
-run time, overwrite, miss rate, key size, value size, get/set proportion,
-expected throughput, and so on. 
+servers. It generates configurable workload such as threads, concurrencies, connections, run time, overwrite, miss rate, key size, value size, get/set proportion, expected throughput, and so on. 
 
-You can specify servers via the \ **--servers**\  option or via the
-environment variable \ ``MEMCACHED_SERVERS``\ .
+You can specify servers via the \ **--servers**\  option or via the environment variable \ ``MEMCACHED_SERVERS``\ .
 
 
 --------
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;
+}
index b4a87257957ba366e8ae188e2189e1118ec0d9f7..3fe44739de7e2b1bdda083d5a0086d076e1b4ba7 100644 (file)
 #define MEMCACHED_VERSION_STRING_LENGTH 24
 
 
-enum memcached_return_t {
-  MEMCACHED_SUCCESS,
-  MEMCACHED_FAILURE,
-  MEMCACHED_HOST_LOOKUP_FAILURE,
-  MEMCACHED_CONNECTION_FAILURE,
-  MEMCACHED_CONNECTION_BIND_FAILURE,
-  MEMCACHED_WRITE_FAILURE,
-  MEMCACHED_READ_FAILURE,
-  MEMCACHED_UNKNOWN_READ_FAILURE,
-  MEMCACHED_PROTOCOL_ERROR,
-  MEMCACHED_CLIENT_ERROR,
-  MEMCACHED_SERVER_ERROR,
-  MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE,
-  MEMCACHED_DATA_EXISTS,
-  MEMCACHED_DATA_DOES_NOT_EXIST,
-  MEMCACHED_NOTSTORED,
-  MEMCACHED_STORED,
-  MEMCACHED_NOTFOUND,
-  MEMCACHED_MEMORY_ALLOCATION_FAILURE,
-  MEMCACHED_PARTIAL_READ,
-  MEMCACHED_SOME_ERRORS,
-  MEMCACHED_NO_SERVERS,
-  MEMCACHED_END,
-  MEMCACHED_DELETED,
-  MEMCACHED_VALUE,
-  MEMCACHED_STAT,
-  MEMCACHED_ITEM,
-  MEMCACHED_ERRNO,
-  MEMCACHED_FAIL_UNIX_SOCKET,
-  MEMCACHED_NOT_SUPPORTED,
-  MEMCACHED_NO_KEY_PROVIDED, /* Deprecated. Use MEMCACHED_BAD_KEY_PROVIDED! */
-  MEMCACHED_FETCH_NOTFINISHED,
-  MEMCACHED_TIMEOUT,
-  MEMCACHED_BUFFERED,
-  MEMCACHED_BAD_KEY_PROVIDED,
-  MEMCACHED_INVALID_HOST_PROTOCOL,
-  MEMCACHED_SERVER_MARKED_DEAD,
-  MEMCACHED_UNKNOWN_STAT_KEY,
-  MEMCACHED_E2BIG,
-  MEMCACHED_INVALID_ARGUMENTS,
-  MEMCACHED_KEY_TOO_BIG,
-  MEMCACHED_AUTH_PROBLEM,
-  MEMCACHED_AUTH_FAILURE,
-  MEMCACHED_AUTH_CONTINUE,
-  MEMCACHED_PARSE_ERROR,
-  MEMCACHED_PARSE_USER_ERROR,
-  MEMCACHED_DEPRECATED,
-  MEMCACHED_MAXIMUM_RETURN /* Always add new error code before */
-};
-
-#ifndef __cplusplus
-typedef enum memcached_return_t memcached_return_t;
-#endif
-
-
 enum memcached_server_distribution_t {
   MEMCACHED_DISTRIBUTION_MODULA,
   MEMCACHED_DISTRIBUTION_CONSISTENT,
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 93f830a..0000000
+++ /dev/null
@@ -1,468 +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);
-}
-
-memcached_return_t memcached_server_add_parsed(memcached_st *ptr,
-                                               const char *hostname,
-                                               size_t hostname_length,
-                                               in_port_t port,
-                                               uint32_t weight)
-{
-  char buffer[NI_MAXHOST];
-
-  memcpy(buffer, hostname, hostname_length);
-  buffer[hostname_length]= 0;
-
-  return server_add(ptr, buffer,
-                    port,
-                    weight,
-                    MEMCACHED_CONNECTION_TCP);
-}
diff --git a/libmemcached/hosts.cc b/libmemcached/hosts.cc
new file mode 100644 (file)
index 0000000..d38b12e
--- /dev/null
@@ -0,0 +1,467 @@
+/* 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);
+}
+
+memcached_return_t memcached_server_add_parsed(memcached_st *ptr,
+                                               const char *hostname,
+                                               size_t hostname_length,
+                                               in_port_t port,
+                                               uint32_t weight)
+{
+  char buffer[NI_MAXHOST];
+
+  memcpy(buffer, hostname, hostname_length);
+  buffer[hostname_length]= 0;
+
+  return server_add(ptr, buffer,
+                    port,
+                    weight,
+                    MEMCACHED_CONNECTION_TCP);
+}
index 5a4b8b09ed0fd9cdb8e073af0f12272b69b024d5..28c5513a4cbc7742ff856176ec720b27ea7cdc90 100644 (file)
@@ -55,6 +55,7 @@ nobase_include_HEADERS+= \
                         libmemcached/protocol/callback.h \
                         libmemcached/protocol_handler.h \
                         libmemcached/quit.h \
+                        libmemcached/return.h \
                          libmemcached/platform.h \
                         libmemcached/result.h \
                          libmemcached/sasl.h \
@@ -70,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.c \
-                                         libmemcached/util/pool.c \
-                                         libmemcached/util/version.c
-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 3c58350..0000000
+++ /dev/null
@@ -1,437 +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.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 2f1caf2b74abb66795836cf6af4ede772b55b163..f32fe0e794cf2105a6e5864b1bca5ad8a70c3d2e 100644 (file)
@@ -35,8 +35,7 @@
  *
  */
 
-#ifndef __LIBMEMCACHED_MEMCACHED_H__
-#define __LIBMEMCACHED_MEMCACHED_H__
+#pragma once
 
 #include <inttypes.h>
 #include <stdlib.h>
 #include <libmemcached/configure.h>
 #include <libmemcached/platform.h>
 #include <libmemcached/constants.h>
+#include <libmemcached/return.h>
 #include <libmemcached/types.h>
 #include <libmemcached/string.h>
 #include <libmemcached/array.h>
 #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;
@@ -161,6 +156,7 @@ struct memcached_st {
   struct {
     uint32_t initial_pool_size;
     uint32_t max_pool_size;
+    int32_t version; // This is used by pool and others to determine if the memcached_st is out of date.
     struct memcached_array_st *filename;
   } configure;
   struct {
@@ -209,9 +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
-
-#endif /* __LIBMEMCACHED_MEMCACHED_H__ */
-
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;
 
index 91dfcd297ff905448632176b8a4ad0e6dba558ae..c0c5cc25294f0c48b1b98020bb3af178600c0bd8 100644 (file)
 
 #include <stdint.h>
 
+#include <libmemcached/common.h>
 #include <libmemcached/options/context.h>
 #include <libmemcached/options/string.h>
 #include <libmemcached/options/symbol.h>
-#include <libmemcached/visibility.h>
-#include <libmemcached/prefix_key.h>
+#include <libmemcached/options/scanner.h>
 
 #pragma GCC diagnostic ignored "-Wold-style-cast"
-#include <libmemcached/options/scanner.h>
 
 int conf_lex(YYSTYPE* lvalp, void* scanner);
 
@@ -104,7 +103,7 @@ inline void config_error(Context *context, yyscan_t *scanner, const char *error)
 
 
 /* Line 189 of yacc.c  */
-#line 108 "libmemcached/options/parser.cc"
+#line 107 "libmemcached/options/parser.cc"
 
 /* Enabling traces.  */
 #ifndef YYDEBUG
@@ -215,7 +214,7 @@ inline void config_error(Context *context, yyscan_t *scanner, const char *error)
 
 
 /* Line 264 of yacc.c  */
-#line 219 "libmemcached/options/parser.cc"
+#line 218 "libmemcached/options/parser.cc"
 
 #ifdef short
 # undef short
@@ -524,13 +523,13 @@ static const yytype_int8 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   157,   157,   158,   162,   164,   166,   168,   173,   178,
-     182,   186,   197,   205,   213,   217,   221,   225,   229,   236,
-     243,   254,   261,   268,   275,   281,   285,   289,   293,   297,
-     301,   305,   309,   313,   317,   321,   325,   332,   336,   340,
-     344,   348,   352,   356,   360,   364,   368,   372,   376,   383,
-     384,   389,   390,   395,   399,   403,   407,   411,   415,   419,
-     423,   427,   434,   438,   446,   450,   454
+       0,   156,   156,   157,   161,   163,   165,   167,   172,   177,
+     181,   185,   196,   204,   212,   216,   220,   224,   228,   235,
+     242,   253,   260,   267,   274,   280,   284,   288,   292,   296,
+     300,   304,   308,   312,   316,   320,   324,   331,   335,   339,
+     343,   347,   351,   355,   359,   363,   367,   371,   375,   382,
+     383,   388,   389,   394,   398,   402,   406,   410,   414,   418,
+     422,   426,   433,   437,   445,   449,   453
 };
 #endif
 
@@ -1522,28 +1521,28 @@ yyreduce:
         case 4:
 
 /* Line 1464 of yacc.c  */
-#line 163 "libmemcached/options/parser.yy"
+#line 162 "libmemcached/options/parser.yy"
     { ;}
     break;
 
   case 5:
 
 /* Line 1464 of yacc.c  */
-#line 165 "libmemcached/options/parser.yy"
+#line 164 "libmemcached/options/parser.yy"
     { ;}
     break;
 
   case 6:
 
 /* Line 1464 of yacc.c  */
-#line 167 "libmemcached/options/parser.yy"
+#line 166 "libmemcached/options/parser.yy"
     { ;}
     break;
 
   case 7:
 
 /* Line 1464 of yacc.c  */
-#line 169 "libmemcached/options/parser.yy"
+#line 168 "libmemcached/options/parser.yy"
     {
             context->set_end();
             YYACCEPT;
@@ -1553,7 +1552,7 @@ yyreduce:
   case 8:
 
 /* Line 1464 of yacc.c  */
-#line 174 "libmemcached/options/parser.yy"
+#line 173 "libmemcached/options/parser.yy"
     {
             context->rc= MEMCACHED_PARSE_USER_ERROR;
             parser_abort(context, NULL);
@@ -1563,7 +1562,7 @@ yyreduce:
   case 9:
 
 /* Line 1464 of yacc.c  */
-#line 179 "libmemcached/options/parser.yy"
+#line 178 "libmemcached/options/parser.yy"
     {
             memcached_reset(context->memc);
           ;}
@@ -1572,7 +1571,7 @@ yyreduce:
   case 10:
 
 /* Line 1464 of yacc.c  */
-#line 183 "libmemcached/options/parser.yy"
+#line 182 "libmemcached/options/parser.yy"
     {
             yydebug= 1;
           ;}
@@ -1581,7 +1580,7 @@ yyreduce:
   case 11:
 
 /* Line 1464 of yacc.c  */
-#line 187 "libmemcached/options/parser.yy"
+#line 186 "libmemcached/options/parser.yy"
     {
             if ((context->rc= memcached_parse_configure_file(context->memc, (yyvsp[(3) - (3)].string).c_str, (yyvsp[(3) - (3)].string).length)) != MEMCACHED_SUCCESS)
             {
@@ -1593,7 +1592,7 @@ yyreduce:
   case 12:
 
 /* Line 1464 of yacc.c  */
-#line 198 "libmemcached/options/parser.yy"
+#line 197 "libmemcached/options/parser.yy"
     {
             if ((context->rc= memcached_server_add_with_weight(context->memc, (yyvsp[(2) - (4)].server).c_str, (yyvsp[(2) - (4)].server).port, (yyvsp[(2) - (4)].server).weight)) != MEMCACHED_SUCCESS)
             {
@@ -1606,7 +1605,7 @@ yyreduce:
   case 13:
 
 /* Line 1464 of yacc.c  */
-#line 206 "libmemcached/options/parser.yy"
+#line 205 "libmemcached/options/parser.yy"
     {
             if ((context->rc= memcached_server_add_with_weight(context->memc, (yyvsp[(2) - (4)].server).c_str, (yyvsp[(2) - (4)].server).port, (yyvsp[(2) - (4)].server).weight)) != MEMCACHED_SUCCESS)
             {
@@ -1619,7 +1618,7 @@ yyreduce:
   case 14:
 
 /* Line 1464 of yacc.c  */
-#line 214 "libmemcached/options/parser.yy"
+#line 213 "libmemcached/options/parser.yy"
     {
             memcached_set_configuration_file(context->memc, (yyvsp[(2) - (2)].string).c_str, (yyvsp[(2) - (2)].string).length);
           ;}
@@ -1628,7 +1627,7 @@ yyreduce:
   case 15:
 
 /* Line 1464 of yacc.c  */
-#line 218 "libmemcached/options/parser.yy"
+#line 217 "libmemcached/options/parser.yy"
     {
             context->memc->configure.initial_pool_size= (yyvsp[(2) - (2)].number);
           ;}
@@ -1637,7 +1636,7 @@ yyreduce:
   case 16:
 
 /* Line 1464 of yacc.c  */
-#line 222 "libmemcached/options/parser.yy"
+#line 221 "libmemcached/options/parser.yy"
     {
             context->memc->configure.max_pool_size= (yyvsp[(2) - (2)].number);
           ;}
@@ -1646,7 +1645,7 @@ yyreduce:
   case 18:
 
 /* Line 1464 of yacc.c  */
-#line 230 "libmemcached/options/parser.yy"
+#line 229 "libmemcached/options/parser.yy"
     {
             if ((context->rc= memcached_set_prefix_key(context->memc, (yyvsp[(2) - (2)].string).c_str, (yyvsp[(2) - (2)].string).length)) != MEMCACHED_SUCCESS)
             {
@@ -1658,7 +1657,7 @@ yyreduce:
   case 19:
 
 /* Line 1464 of yacc.c  */
-#line 237 "libmemcached/options/parser.yy"
+#line 236 "libmemcached/options/parser.yy"
     {
             if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, (yyvsp[(2) - (2)].distribution))) != MEMCACHED_SUCCESS)
             {
@@ -1670,7 +1669,7 @@ yyreduce:
   case 20:
 
 /* Line 1464 of yacc.c  */
-#line 244 "libmemcached/options/parser.yy"
+#line 243 "libmemcached/options/parser.yy"
     {
             if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, (yyvsp[(2) - (4)].distribution))) != MEMCACHED_SUCCESS)
             {
@@ -1686,7 +1685,7 @@ yyreduce:
   case 21:
 
 /* Line 1464 of yacc.c  */
-#line 255 "libmemcached/options/parser.yy"
+#line 254 "libmemcached/options/parser.yy"
     {
             if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_HASH, (yyvsp[(2) - (2)].hash))) != MEMCACHED_SUCCESS)
             {
@@ -1698,7 +1697,7 @@ yyreduce:
   case 22:
 
 /* Line 1464 of yacc.c  */
-#line 262 "libmemcached/options/parser.yy"
+#line 261 "libmemcached/options/parser.yy"
     {
             if ((context->rc= memcached_behavior_set(context->memc, (yyvsp[(1) - (2)].behavior), (yyvsp[(2) - (2)].number))) != MEMCACHED_SUCCESS)
             {
@@ -1710,7 +1709,7 @@ yyreduce:
   case 23:
 
 /* Line 1464 of yacc.c  */
-#line 269 "libmemcached/options/parser.yy"
+#line 268 "libmemcached/options/parser.yy"
     {
             if ((context->rc= memcached_behavior_set(context->memc, (yyvsp[(1) - (1)].behavior), true)) != MEMCACHED_SUCCESS)
             {
@@ -1722,7 +1721,7 @@ yyreduce:
   case 24:
 
 /* Line 1464 of yacc.c  */
-#line 276 "libmemcached/options/parser.yy"
+#line 275 "libmemcached/options/parser.yy"
     {
           ;}
     break;
@@ -1730,7 +1729,7 @@ yyreduce:
   case 25:
 
 /* Line 1464 of yacc.c  */
-#line 282 "libmemcached/options/parser.yy"
+#line 281 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS;
           ;}
@@ -1739,7 +1738,7 @@ yyreduce:
   case 26:
 
 /* Line 1464 of yacc.c  */
-#line 286 "libmemcached/options/parser.yy"
+#line 285 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT;
           ;}
@@ -1748,7 +1747,7 @@ yyreduce:
   case 27:
 
 /* Line 1464 of yacc.c  */
-#line 290 "libmemcached/options/parser.yy"
+#line 289 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK;
           ;}
@@ -1757,7 +1756,7 @@ yyreduce:
   case 28:
 
 /* Line 1464 of yacc.c  */
-#line 294 "libmemcached/options/parser.yy"
+#line 293 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK;
           ;}
@@ -1766,7 +1765,7 @@ yyreduce:
   case 29:
 
 /* Line 1464 of yacc.c  */
-#line 298 "libmemcached/options/parser.yy"
+#line 297 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH;
           ;}
@@ -1775,7 +1774,7 @@ yyreduce:
   case 30:
 
 /* Line 1464 of yacc.c  */
-#line 302 "libmemcached/options/parser.yy"
+#line 301 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS;
           ;}
@@ -1784,7 +1783,7 @@ yyreduce:
   case 31:
 
 /* Line 1464 of yacc.c  */
-#line 306 "libmemcached/options/parser.yy"
+#line 305 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_POLL_TIMEOUT;
           ;}
@@ -1793,7 +1792,7 @@ yyreduce:
   case 32:
 
 /* Line 1464 of yacc.c  */
-#line 310 "libmemcached/options/parser.yy"
+#line 309 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_RCV_TIMEOUT;
           ;}
@@ -1802,7 +1801,7 @@ yyreduce:
   case 33:
 
 /* Line 1464 of yacc.c  */
-#line 314 "libmemcached/options/parser.yy"
+#line 313 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_RETRY_TIMEOUT;
           ;}
@@ -1811,7 +1810,7 @@ yyreduce:
   case 34:
 
 /* Line 1464 of yacc.c  */
-#line 318 "libmemcached/options/parser.yy"
+#line 317 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_SND_TIMEOUT;
           ;}
@@ -1820,7 +1819,7 @@ yyreduce:
   case 35:
 
 /* Line 1464 of yacc.c  */
-#line 322 "libmemcached/options/parser.yy"
+#line 321 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE;
           ;}
@@ -1829,7 +1828,7 @@ yyreduce:
   case 36:
 
 /* Line 1464 of yacc.c  */
-#line 326 "libmemcached/options/parser.yy"
+#line 325 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE;
           ;}
@@ -1838,7 +1837,7 @@ yyreduce:
   case 37:
 
 /* Line 1464 of yacc.c  */
-#line 333 "libmemcached/options/parser.yy"
+#line 332 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_BINARY_PROTOCOL;
           ;}
@@ -1847,7 +1846,7 @@ yyreduce:
   case 38:
 
 /* Line 1464 of yacc.c  */
-#line 337 "libmemcached/options/parser.yy"
+#line 336 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_BUFFER_REQUESTS;
           ;}
@@ -1856,7 +1855,7 @@ yyreduce:
   case 39:
 
 /* Line 1464 of yacc.c  */
-#line 341 "libmemcached/options/parser.yy"
+#line 340 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY;
           ;}
@@ -1865,7 +1864,7 @@ yyreduce:
   case 40:
 
 /* Line 1464 of yacc.c  */
-#line 345 "libmemcached/options/parser.yy"
+#line 344 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_NOREPLY;
           ;}
@@ -1874,7 +1873,7 @@ yyreduce:
   case 41:
 
 /* Line 1464 of yacc.c  */
-#line 349 "libmemcached/options/parser.yy"
+#line 348 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ;
           ;}
@@ -1883,7 +1882,7 @@ yyreduce:
   case 42:
 
 /* Line 1464 of yacc.c  */
-#line 353 "libmemcached/options/parser.yy"
+#line 352 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_SORT_HOSTS;
           ;}
@@ -1892,7 +1891,7 @@ yyreduce:
   case 43:
 
 /* Line 1464 of yacc.c  */
-#line 357 "libmemcached/options/parser.yy"
+#line 356 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_SUPPORT_CAS;
           ;}
@@ -1901,7 +1900,7 @@ yyreduce:
   case 44:
 
 /* Line 1464 of yacc.c  */
-#line 361 "libmemcached/options/parser.yy"
+#line 360 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_TCP_NODELAY;
           ;}
@@ -1910,7 +1909,7 @@ yyreduce:
   case 45:
 
 /* Line 1464 of yacc.c  */
-#line 365 "libmemcached/options/parser.yy"
+#line 364 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_TCP_KEEPALIVE;
           ;}
@@ -1919,7 +1918,7 @@ yyreduce:
   case 46:
 
 /* Line 1464 of yacc.c  */
-#line 369 "libmemcached/options/parser.yy"
+#line 368 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_TCP_KEEPIDLE;
           ;}
@@ -1928,7 +1927,7 @@ yyreduce:
   case 47:
 
 /* Line 1464 of yacc.c  */
-#line 373 "libmemcached/options/parser.yy"
+#line 372 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_USE_UDP;
           ;}
@@ -1937,7 +1936,7 @@ yyreduce:
   case 48:
 
 /* Line 1464 of yacc.c  */
-#line 377 "libmemcached/options/parser.yy"
+#line 376 "libmemcached/options/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_VERIFY_KEY;
           ;}
@@ -1946,35 +1945,35 @@ yyreduce:
   case 49:
 
 /* Line 1464 of yacc.c  */
-#line 383 "libmemcached/options/parser.yy"
+#line 382 "libmemcached/options/parser.yy"
     { ;}
     break;
 
   case 50:
 
 /* Line 1464 of yacc.c  */
-#line 385 "libmemcached/options/parser.yy"
+#line 384 "libmemcached/options/parser.yy"
     { ;}
     break;
 
   case 51:
 
 /* Line 1464 of yacc.c  */
-#line 389 "libmemcached/options/parser.yy"
+#line 388 "libmemcached/options/parser.yy"
     { ;}
     break;
 
   case 52:
 
 /* Line 1464 of yacc.c  */
-#line 391 "libmemcached/options/parser.yy"
+#line 390 "libmemcached/options/parser.yy"
     { ;}
     break;
 
   case 53:
 
 /* Line 1464 of yacc.c  */
-#line 396 "libmemcached/options/parser.yy"
+#line 395 "libmemcached/options/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_MD5;
           ;}
@@ -1983,7 +1982,7 @@ yyreduce:
   case 54:
 
 /* Line 1464 of yacc.c  */
-#line 400 "libmemcached/options/parser.yy"
+#line 399 "libmemcached/options/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_CRC;
           ;}
@@ -1992,7 +1991,7 @@ yyreduce:
   case 55:
 
 /* Line 1464 of yacc.c  */
-#line 404 "libmemcached/options/parser.yy"
+#line 403 "libmemcached/options/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_FNV1_64;
           ;}
@@ -2001,7 +2000,7 @@ yyreduce:
   case 56:
 
 /* Line 1464 of yacc.c  */
-#line 408 "libmemcached/options/parser.yy"
+#line 407 "libmemcached/options/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_FNV1A_64;
           ;}
@@ -2010,7 +2009,7 @@ yyreduce:
   case 57:
 
 /* Line 1464 of yacc.c  */
-#line 412 "libmemcached/options/parser.yy"
+#line 411 "libmemcached/options/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_FNV1_32;
           ;}
@@ -2019,7 +2018,7 @@ yyreduce:
   case 58:
 
 /* Line 1464 of yacc.c  */
-#line 416 "libmemcached/options/parser.yy"
+#line 415 "libmemcached/options/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_FNV1A_32;
           ;}
@@ -2028,7 +2027,7 @@ yyreduce:
   case 59:
 
 /* Line 1464 of yacc.c  */
-#line 420 "libmemcached/options/parser.yy"
+#line 419 "libmemcached/options/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_HSIEH;
           ;}
@@ -2037,7 +2036,7 @@ yyreduce:
   case 60:
 
 /* Line 1464 of yacc.c  */
-#line 424 "libmemcached/options/parser.yy"
+#line 423 "libmemcached/options/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_MURMUR;
           ;}
@@ -2046,7 +2045,7 @@ yyreduce:
   case 61:
 
 /* Line 1464 of yacc.c  */
-#line 428 "libmemcached/options/parser.yy"
+#line 427 "libmemcached/options/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_JENKINS;
           ;}
@@ -2055,7 +2054,7 @@ yyreduce:
   case 62:
 
 /* Line 1464 of yacc.c  */
-#line 435 "libmemcached/options/parser.yy"
+#line 434 "libmemcached/options/parser.yy"
     {
             (yyval.string)= (yyvsp[(1) - (1)].string);
           ;}
@@ -2064,7 +2063,7 @@ yyreduce:
   case 63:
 
 /* Line 1464 of yacc.c  */
-#line 439 "libmemcached/options/parser.yy"
+#line 438 "libmemcached/options/parser.yy"
     {
             (yyval.string).c_str= (yyvsp[(1) - (1)].string).c_str +1; // +1 to move use passed the initial quote
             (yyval.string).length= (yyvsp[(1) - (1)].string).length -1; // -1 removes the end quote
@@ -2074,7 +2073,7 @@ yyreduce:
   case 64:
 
 /* Line 1464 of yacc.c  */
-#line 447 "libmemcached/options/parser.yy"
+#line 446 "libmemcached/options/parser.yy"
     {
             (yyval.distribution)= MEMCACHED_DISTRIBUTION_CONSISTENT;
           ;}
@@ -2083,7 +2082,7 @@ yyreduce:
   case 65:
 
 /* Line 1464 of yacc.c  */
-#line 451 "libmemcached/options/parser.yy"
+#line 450 "libmemcached/options/parser.yy"
     {
             (yyval.distribution)= MEMCACHED_DISTRIBUTION_MODULA;
           ;}
@@ -2092,7 +2091,7 @@ yyreduce:
   case 66:
 
 /* Line 1464 of yacc.c  */
-#line 455 "libmemcached/options/parser.yy"
+#line 454 "libmemcached/options/parser.yy"
     {
             (yyval.distribution)= MEMCACHED_DISTRIBUTION_RANDOM;
           ;}
@@ -2101,7 +2100,7 @@ yyreduce:
 
 
 /* Line 1464 of yacc.c  */
-#line 2105 "libmemcached/options/parser.cc"
+#line 2104 "libmemcached/options/parser.cc"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -2313,7 +2312,7 @@ yyreturn:
 
 
 /* Line 1684 of yacc.c  */
-#line 460 "libmemcached/options/parser.yy"
+#line 459 "libmemcached/options/parser.yy"
  
 
 void Context::start() 
index b6143087c24ed1bd6dd18511126f999fc335a788..7af88fd02394cdd2725545b8725a07789790027c 100644 (file)
@@ -1,21 +1,22 @@
 #line 2 "libmemcached/options/scanner.cc"
 #line 22 "libmemcached/options/scanner.l"
 
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#pragma GCC diagnostic ignored "-Wsign-compare"
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-
+#include <libmemcached/common.h>
 #include <libmemcached/options/context.h>
 #include <libmemcached/options/parser.h>
 #include <libmemcached/options/string.h>
 #include <libmemcached/options/symbol.h>
 
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
 #define YY_EXTRA_TYPE Context*
 
 
 
 
-#line 19 "libmemcached/options/scanner.cc"
+#line 20 "libmemcached/options/scanner.cc"
 
 #define  YY_INT_ALIGNED short int
 
@@ -1075,13 +1076,13 @@ static yyconst flex_int16_t yy_chk[1722] =
 
 static yyconst flex_int16_t yy_rule_linenum[64] =
     {   0,
-       77,   79,   81,   83,   85,   88,   92,   94,   95,   96,
-       97,   98,   99,  100,  101,  102,  103,  104,  105,  106,
-      107,  108,  109,  110,  111,  112,  113,  114,  115,  116,
-      117,  118,  119,  120,  121,  123,  124,  126,  128,  129,
-      130,  131,  132,  133,  135,  136,  139,  144,  145,  146,
-      148,  149,  150,  151,  152,  153,  154,  155,  156,  158,
-      167,  185,  191
+       78,   80,   82,   84,   86,   89,   93,   95,   96,   97,
+       98,   99,  100,  101,  102,  103,  104,  105,  106,  107,
+      108,  109,  110,  111,  112,  113,  114,  115,  116,  117,
+      118,  119,  120,  121,  122,  124,  125,  127,  129,  130,
+      131,  132,  133,  134,  136,  137,  140,  145,  146,  147,
+      149,  150,  151,  152,  153,  154,  155,  156,  157,  159,
+      168,  186,  192
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -1112,7 +1113,7 @@ static yyconst flex_int16_t yy_rule_linenum[64] =
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#line 38 "libmemcached/options/scanner.l"
+#line 39 "libmemcached/options/scanner.l"
 #include <cstdlib>
 #include <cstring>
 
@@ -1136,7 +1137,7 @@ static yyconst flex_int16_t yy_rule_linenum[64] =
 
 #define YY_INPUT(buffer, result, max_size) get_lex_chars(buffer, result, max_size, PARAM)
 
-#line 1140 "libmemcached/options/scanner.cc"
+#line 1141 "libmemcached/options/scanner.cc"
 
 #define INITIAL 0
 
@@ -1439,11 +1440,11 @@ YY_DECL
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
 /* %% [7.0] user's declarations go here */
-#line 74 "libmemcached/options/scanner.l"
+#line 75 "libmemcached/options/scanner.l"
 
 
 
-#line 1447 "libmemcached/options/scanner.cc"
+#line 1448 "libmemcached/options/scanner.cc"
 
     yylval = yylval_param;
 
@@ -1562,28 +1563,28 @@ do_action:      /* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 77 "libmemcached/options/scanner.l"
+#line 78 "libmemcached/options/scanner.l"
 { return yytext[0];}
        YY_BREAK
 case 2:
 YY_RULE_SETUP
-#line 79 "libmemcached/options/scanner.l"
+#line 80 "libmemcached/options/scanner.l"
 { yylval->number = atoi(yytext); return (NUMBER); }
        YY_BREAK
 case 3:
 YY_RULE_SETUP
-#line 81 "libmemcached/options/scanner.l"
+#line 82 "libmemcached/options/scanner.l"
 { yylval->server.port = atoi(yytext +1); return PORT; }
        YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 83 "libmemcached/options/scanner.l"
+#line 84 "libmemcached/options/scanner.l"
 { yylval->server.weight = atoi(yytext +2); return WEIGHT_START; }
        YY_BREAK
 case 5:
 /* rule 5 can match eol */
 YY_RULE_SETUP
-#line 85 "libmemcached/options/scanner.l"
+#line 86 "libmemcached/options/scanner.l"
 ; /* skip whitespace */
        YY_BREAK
 case 6:
@@ -1591,214 +1592,214 @@ case 6:
 yyg->yy_c_buf_p = yy_cp -= 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 88 "libmemcached/options/scanner.l"
+#line 89 "libmemcached/options/scanner.l"
 {
       return COMMENT;
     }
        YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 92 "libmemcached/options/scanner.l"
+#line 93 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; yyextra->set_server(); return SERVER; }
        YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 94 "libmemcached/options/scanner.l"
+#line 95 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return BINARY_PROTOCOL; }
        YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 95 "libmemcached/options/scanner.l"
+#line 96 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return BUFFER_REQUESTS; }
        YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 96 "libmemcached/options/scanner.l"
+#line 97 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return CONFIGURE_FILE; }
        YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 97 "libmemcached/options/scanner.l"
+#line 98 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return CONNECT_TIMEOUT; }
        YY_BREAK
 case 12:
 YY_RULE_SETUP
-#line 98 "libmemcached/options/scanner.l"
+#line 99 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return DISTRIBUTION; }
        YY_BREAK
 case 13:
 YY_RULE_SETUP
-#line 99 "libmemcached/options/scanner.l"
+#line 100 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return HASH_WITH_NAMESPACE; }
        YY_BREAK
 case 14:
 YY_RULE_SETUP
-#line 100 "libmemcached/options/scanner.l"
+#line 101 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return HASH; }
        YY_BREAK
 case 15:
 YY_RULE_SETUP
-#line 101 "libmemcached/options/scanner.l"
+#line 102 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return IO_BYTES_WATERMARK; }
        YY_BREAK
 case 16:
 YY_RULE_SETUP
-#line 102 "libmemcached/options/scanner.l"
+#line 103 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return IO_KEY_PREFETCH; }
        YY_BREAK
 case 17:
 YY_RULE_SETUP
-#line 103 "libmemcached/options/scanner.l"
+#line 104 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return IO_MSG_WATERMARK; }
        YY_BREAK
 case 18:
 YY_RULE_SETUP
-#line 104 "libmemcached/options/scanner.l"
+#line 105 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return NOREPLY; }
        YY_BREAK
 case 19:
 YY_RULE_SETUP
-#line 105 "libmemcached/options/scanner.l"
+#line 106 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return NUMBER_OF_REPLICAS; }
        YY_BREAK
 case 20:
 YY_RULE_SETUP
-#line 106 "libmemcached/options/scanner.l"
+#line 107 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return POLL_TIMEOUT; }
        YY_BREAK
 case 21:
 YY_RULE_SETUP
-#line 107 "libmemcached/options/scanner.l"
+#line 108 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return RANDOMIZE_REPLICA_READ; }
        YY_BREAK
 case 22:
 YY_RULE_SETUP
-#line 108 "libmemcached/options/scanner.l"
+#line 109 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return RCV_TIMEOUT; }
        YY_BREAK
 case 23:
 YY_RULE_SETUP
-#line 109 "libmemcached/options/scanner.l"
+#line 110 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return REMOVE_FAILED_SERVERS; }
        YY_BREAK
 case 24:
 YY_RULE_SETUP
-#line 110 "libmemcached/options/scanner.l"
+#line 111 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return RETRY_TIMEOUT; }
        YY_BREAK
 case 25:
 YY_RULE_SETUP
-#line 111 "libmemcached/options/scanner.l"
+#line 112 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return SND_TIMEOUT; }
        YY_BREAK
 case 26:
 YY_RULE_SETUP
-#line 112 "libmemcached/options/scanner.l"
+#line 113 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return SOCKET_RECV_SIZE; }
        YY_BREAK
 case 27:
 YY_RULE_SETUP
-#line 113 "libmemcached/options/scanner.l"
+#line 114 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return SOCKET_SEND_SIZE; }
        YY_BREAK
 case 28:
 YY_RULE_SETUP
-#line 114 "libmemcached/options/scanner.l"
+#line 115 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return SORT_HOSTS; }
        YY_BREAK
 case 29:
 YY_RULE_SETUP
-#line 115 "libmemcached/options/scanner.l"
+#line 116 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return SUPPORT_CAS; }
        YY_BREAK
 case 30:
 YY_RULE_SETUP
-#line 116 "libmemcached/options/scanner.l"
+#line 117 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return _TCP_KEEPALIVE; }
        YY_BREAK
 case 31:
 YY_RULE_SETUP
-#line 117 "libmemcached/options/scanner.l"
+#line 118 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return _TCP_KEEPIDLE; }
        YY_BREAK
 case 32:
 YY_RULE_SETUP
-#line 118 "libmemcached/options/scanner.l"
+#line 119 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return _TCP_NODELAY; }
        YY_BREAK
 case 33:
 YY_RULE_SETUP
-#line 119 "libmemcached/options/scanner.l"
+#line 120 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return USE_UDP; }
        YY_BREAK
 case 34:
 YY_RULE_SETUP
-#line 120 "libmemcached/options/scanner.l"
+#line 121 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return USER_DATA; }
        YY_BREAK
 case 35:
 YY_RULE_SETUP
-#line 121 "libmemcached/options/scanner.l"
+#line 122 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return VERIFY_KEY; }
        YY_BREAK
 case 36:
 YY_RULE_SETUP
-#line 123 "libmemcached/options/scanner.l"
+#line 124 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return POOL_MIN; }
        YY_BREAK
 case 37:
 YY_RULE_SETUP
-#line 124 "libmemcached/options/scanner.l"
+#line 125 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return POOL_MAX; }
        YY_BREAK
 case 38:
 YY_RULE_SETUP
-#line 126 "libmemcached/options/scanner.l"
+#line 127 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return NAMESPACE; }
        YY_BREAK
 case 39:
 YY_RULE_SETUP
-#line 128 "libmemcached/options/scanner.l"
+#line 129 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return INCLUDE; }
        YY_BREAK
 case 40:
 YY_RULE_SETUP
-#line 129 "libmemcached/options/scanner.l"
+#line 130 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return RESET; }
        YY_BREAK
 case 41:
 YY_RULE_SETUP
-#line 130 "libmemcached/options/scanner.l"
+#line 131 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return PARSER_DEBUG; }
        YY_BREAK
 case 42:
 YY_RULE_SETUP
-#line 131 "libmemcached/options/scanner.l"
+#line 132 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return SERVERS; }
        YY_BREAK
 case 43:
 YY_RULE_SETUP
-#line 132 "libmemcached/options/scanner.l"
+#line 133 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return END; }
        YY_BREAK
 case 44:
 YY_RULE_SETUP
-#line 133 "libmemcached/options/scanner.l"
+#line 134 "libmemcached/options/scanner.l"
 { yyextra->begin= yytext; return ERROR; }
        YY_BREAK
 case 45:
 YY_RULE_SETUP
-#line 135 "libmemcached/options/scanner.l"
+#line 136 "libmemcached/options/scanner.l"
 { return TRUE; }
        YY_BREAK
 case 46:
 YY_RULE_SETUP
-#line 136 "libmemcached/options/scanner.l"
+#line 137 "libmemcached/options/scanner.l"
 { return FALSE; }
        YY_BREAK
 case 47:
 YY_RULE_SETUP
-#line 139 "libmemcached/options/scanner.l"
+#line 140 "libmemcached/options/scanner.l"
 {
       yyextra->begin= yytext;
       return UNKNOWN_OPTION;
@@ -1806,67 +1807,67 @@ YY_RULE_SETUP
        YY_BREAK
 case 48:
 YY_RULE_SETUP
-#line 144 "libmemcached/options/scanner.l"
+#line 145 "libmemcached/options/scanner.l"
 { return CONSISTENT; }
        YY_BREAK
 case 49:
 YY_RULE_SETUP
-#line 145 "libmemcached/options/scanner.l"
+#line 146 "libmemcached/options/scanner.l"
 { return MODULA; }
        YY_BREAK
 case 50:
 YY_RULE_SETUP
-#line 146 "libmemcached/options/scanner.l"
+#line 147 "libmemcached/options/scanner.l"
 { return RANDOM; }
        YY_BREAK
 case 51:
 YY_RULE_SETUP
-#line 148 "libmemcached/options/scanner.l"
+#line 149 "libmemcached/options/scanner.l"
 { return MD5; }
        YY_BREAK
 case 52:
 YY_RULE_SETUP
-#line 149 "libmemcached/options/scanner.l"
+#line 150 "libmemcached/options/scanner.l"
 { return CRC; }
        YY_BREAK
 case 53:
 YY_RULE_SETUP
-#line 150 "libmemcached/options/scanner.l"
+#line 151 "libmemcached/options/scanner.l"
 { return FNV1_64; }
        YY_BREAK
 case 54:
 YY_RULE_SETUP
-#line 151 "libmemcached/options/scanner.l"
+#line 152 "libmemcached/options/scanner.l"
 { return FNV1A_64; }
        YY_BREAK
 case 55:
 YY_RULE_SETUP
-#line 152 "libmemcached/options/scanner.l"
+#line 153 "libmemcached/options/scanner.l"
 { return FNV1_32; }
        YY_BREAK
 case 56:
 YY_RULE_SETUP
-#line 153 "libmemcached/options/scanner.l"
+#line 154 "libmemcached/options/scanner.l"
 { return FNV1A_32; }
        YY_BREAK
 case 57:
 YY_RULE_SETUP
-#line 154 "libmemcached/options/scanner.l"
+#line 155 "libmemcached/options/scanner.l"
 { return HSIEH; }
        YY_BREAK
 case 58:
 YY_RULE_SETUP
-#line 155 "libmemcached/options/scanner.l"
+#line 156 "libmemcached/options/scanner.l"
 { return MURMUR; }
        YY_BREAK
 case 59:
 YY_RULE_SETUP
-#line 156 "libmemcached/options/scanner.l"
+#line 157 "libmemcached/options/scanner.l"
 { return JENKINS; }
        YY_BREAK
 case 60:
 YY_RULE_SETUP
-#line 158 "libmemcached/options/scanner.l"
+#line 159 "libmemcached/options/scanner.l"
 {
       yylval->server.port= MEMCACHED_DEFAULT_PORT;
       yylval->server.weight= 1;
@@ -1878,7 +1879,7 @@ YY_RULE_SETUP
        YY_BREAK
 case 61:
 YY_RULE_SETUP
-#line 167 "libmemcached/options/scanner.l"
+#line 168 "libmemcached/options/scanner.l"
 {
       if (yyextra->is_server())
       {
@@ -1899,7 +1900,7 @@ YY_RULE_SETUP
        YY_BREAK
 case 62:
 YY_RULE_SETUP
-#line 185 "libmemcached/options/scanner.l"
+#line 186 "libmemcached/options/scanner.l"
 {
       yylval->string.c_str = yytext;
       yylval->string.length = yyleng;
@@ -1908,7 +1909,7 @@ YY_RULE_SETUP
        YY_BREAK
 case 63:
 YY_RULE_SETUP
-#line 191 "libmemcached/options/scanner.l"
+#line 192 "libmemcached/options/scanner.l"
 {
       yyextra->begin= yytext;
       return UNKNOWN;
@@ -1916,10 +1917,10 @@ YY_RULE_SETUP
        YY_BREAK
 case 64:
 YY_RULE_SETUP
-#line 196 "libmemcached/options/scanner.l"
+#line 197 "libmemcached/options/scanner.l"
 ECHO;
        YY_BREAK
-#line 1923 "libmemcached/options/scanner.cc"
+#line 1924 "libmemcached/options/scanner.cc"
 case YY_STATE_EOF(INITIAL):
        yyterminate();
 
@@ -3185,7 +3186,7 @@ void config_free (void * ptr , yyscan_t yyscanner)
 
 /* %ok-for-header */
 
-#line 196 "libmemcached/options/scanner.l"
+#line 197 "libmemcached/options/scanner.l"
 
 
 
index b5bddde3ddd6ee51e6330194ab8e056c0a336150..1742031a2adb77013caeb89a43c435e22099821d 100644 (file)
@@ -5,21 +5,22 @@
 #line 6 "libmemcached/options/scanner.h"
 #line 22 "libmemcached/options/scanner.l"
 
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#pragma GCC diagnostic ignored "-Wsign-compare"
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-
+#include <libmemcached/common.h>
 #include <libmemcached/options/context.h>
 #include <libmemcached/options/parser.h>
 #include <libmemcached/options/string.h>
 #include <libmemcached/options/symbol.h>
 
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
 #define YY_EXTRA_TYPE Context*
 
 
 
 
-#line 23 "libmemcached/options/scanner.h"
+#line 24 "libmemcached/options/scanner.h"
 
 #define  YY_INT_ALIGNED short int
 
@@ -471,9 +472,9 @@ extern int config_lex \
 #undef YY_DECL
 #endif
 
-#line 196 "libmemcached/options/scanner.l"
+#line 197 "libmemcached/options/scanner.l"
 
 
-#line 478 "libmemcached/options/scanner.h"
+#line 479 "libmemcached/options/scanner.h"
 #undef config_IN_HEADER
 #endif /* config_HEADER_H */
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;
+}
diff --git a/libmemcached/return.h b/libmemcached/return.h
new file mode 100644 (file)
index 0000000..048c067
--- /dev/null
@@ -0,0 +1,94 @@
+/*  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
+
+enum memcached_return_t {
+  MEMCACHED_SUCCESS,
+  MEMCACHED_FAILURE,
+  MEMCACHED_HOST_LOOKUP_FAILURE,
+  MEMCACHED_CONNECTION_FAILURE,
+  MEMCACHED_CONNECTION_BIND_FAILURE,
+  MEMCACHED_WRITE_FAILURE,
+  MEMCACHED_READ_FAILURE,
+  MEMCACHED_UNKNOWN_READ_FAILURE,
+  MEMCACHED_PROTOCOL_ERROR,
+  MEMCACHED_CLIENT_ERROR,
+  MEMCACHED_SERVER_ERROR,
+  MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE,
+  MEMCACHED_DATA_EXISTS,
+  MEMCACHED_DATA_DOES_NOT_EXIST,
+  MEMCACHED_NOTSTORED,
+  MEMCACHED_STORED,
+  MEMCACHED_NOTFOUND,
+  MEMCACHED_MEMORY_ALLOCATION_FAILURE,
+  MEMCACHED_PARTIAL_READ,
+  MEMCACHED_SOME_ERRORS,
+  MEMCACHED_NO_SERVERS,
+  MEMCACHED_END,
+  MEMCACHED_DELETED,
+  MEMCACHED_VALUE,
+  MEMCACHED_STAT,
+  MEMCACHED_ITEM,
+  MEMCACHED_ERRNO,
+  MEMCACHED_FAIL_UNIX_SOCKET,
+  MEMCACHED_NOT_SUPPORTED,
+  MEMCACHED_NO_KEY_PROVIDED, /* Deprecated. Use MEMCACHED_BAD_KEY_PROVIDED! */
+  MEMCACHED_FETCH_NOTFINISHED,
+  MEMCACHED_TIMEOUT,
+  MEMCACHED_BUFFERED,
+  MEMCACHED_BAD_KEY_PROVIDED,
+  MEMCACHED_INVALID_HOST_PROTOCOL,
+  MEMCACHED_SERVER_MARKED_DEAD,
+  MEMCACHED_UNKNOWN_STAT_KEY,
+  MEMCACHED_E2BIG,
+  MEMCACHED_INVALID_ARGUMENTS,
+  MEMCACHED_KEY_TOO_BIG,
+  MEMCACHED_AUTH_PROBLEM,
+  MEMCACHED_AUTH_FAILURE,
+  MEMCACHED_AUTH_CONTINUE,
+  MEMCACHED_PARSE_ERROR,
+  MEMCACHED_PARSE_USER_ERROR,
+  MEMCACHED_DEPRECATED,
+  MEMCACHED_MAXIMUM_RETURN /* Always add new error code before */
+};
+
+#ifndef __cplusplus
+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
+
diff --git a/libmemcached/util/ping.c b/libmemcached/util/ping.c
deleted file mode 100644 (file)
index 3d5471a..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: connects to a host, and makes sure it is alive.
- *
- */
-
-#include "libmemcached/common.h"
-#include "libmemcached/memcached_util.h"
-
-
-bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_return_t *ret)
-{
-  memcached_return_t rc;
-  memcached_st memc, *memc_ptr;
-
-  memc_ptr= memcached_create(&memc);
-
-  rc= memcached_server_add(memc_ptr, hostname, port);
-
-  if (rc == MEMCACHED_SUCCESS)
-  {
-    rc= memcached_version(memc_ptr);
-  }
-
-  memcached_free(memc_ptr);
-
-  if (ret)
-  {
-    *ret= rc;
-  }
-
-  return rc == MEMCACHED_SUCCESS;
-}
diff --git a/libmemcached/util/ping.cc b/libmemcached/util/ping.cc
new file mode 100644 (file)
index 0000000..3d5471a
--- /dev/null
@@ -0,0 +1,38 @@
+/* LibMemcached
+ * Copyright (C) 2010 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: connects to a host, and makes sure it is alive.
+ *
+ */
+
+#include "libmemcached/common.h"
+#include "libmemcached/memcached_util.h"
+
+
+bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_return_t *ret)
+{
+  memcached_return_t rc;
+  memcached_st memc, *memc_ptr;
+
+  memc_ptr= memcached_create(&memc);
+
+  rc= memcached_server_add(memc_ptr, hostname, port);
+
+  if (rc == MEMCACHED_SUCCESS)
+  {
+    rc= memcached_version(memc_ptr);
+  }
+
+  memcached_free(memc_ptr);
+
+  if (ret)
+  {
+    *ret= rc;
+  }
+
+  return rc == MEMCACHED_SUCCESS;
+}
diff --git a/libmemcached/util/pool.c b/libmemcached/util/pool.c
deleted file mode 100644 (file)
index 948f765..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: connects to a host, and makes sure it is alive.
- *
- */
-
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/common.h"
-#include "libmemcached/memcached_util.h"
-
-#include <errno.h>
-#include <pthread.h>
-
-struct memcached_pool_st
-{
-  pthread_mutex_t mutex;
-  pthread_cond_t cond;
-  memcached_st *master;
-  memcached_st **mmc;
-  int firstfree;
-  uint32_t size;
-  uint32_t current_size;
-  bool _owns_master;
-  char *version;
-};
-
-static memcached_return_t mutex_enter(pthread_mutex_t *mutex)
-{
-  int ret;
-  do
-    ret= pthread_mutex_lock(mutex);
-  while (ret == -1 && errno == EINTR);
-
-  return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
-}
-
-static memcached_return_t mutex_exit(pthread_mutex_t *mutex)
-{
-  int ret;
-  do
-    ret= pthread_mutex_unlock(mutex);
-  while (ret == -1 && errno == EINTR);
-
-  return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
-}
-
-/**
- * Grow the connection pool by creating a connection structure and clone the
- * original memcached handle.
- */
-static int grow_pool(memcached_pool_st* pool)
-{
-  memcached_st *obj= calloc(1, sizeof(*obj));
-
-  if (obj == NULL)
-    return -1;
-
-  if (memcached_clone(obj, pool->master) == NULL)
-  {
-    free(obj);
-    return -1;
-  }
-
-  pool->mmc[++pool->firstfree] = obj;
-  pool->current_size++;
-
-  return EXIT_SUCCESS;
-}
-
-static inline memcached_pool_st *_pool_create(memcached_st* mmc, uint32_t initial, uint32_t max)
-{
-  memcached_pool_st* ret= NULL;
-
-  if (! initial || ! max || initial > max)
-  {
-    errno= EINVAL;
-    return NULL;
-  }
-
-  memcached_pool_st object= { .mutex = PTHREAD_MUTEX_INITIALIZER,
-    .cond= PTHREAD_COND_INITIALIZER,
-    .master= mmc,
-    .mmc= calloc(max, sizeof(memcached_st*)),
-    .firstfree= -1,
-    .size= max,
-    .current_size= 0,
-    ._owns_master= false};
-
-  if (object.mmc != NULL)
-  {
-    ret= (memcached_pool_st*)calloc(1, sizeof(memcached_pool_st));
-    if (ret == NULL)
-    {
-      free(object.mmc);
-      errno= ENOMEM; // Set this for the failed calloc
-      return NULL;
-    }
-
-    *ret= object;
-
-    /*
-      Try to create the initial size of the pool. An allocation failure at
-      this time is not fatal..
-    */
-    for (unsigned int ii= 0; ii < initial; ++ii)
-    {
-      if (grow_pool(ret) == -1)
-        break;
-    }
-  }
-
-  return ret;
-}
-
-memcached_pool_st *memcached_pool_create(memcached_st* mmc, uint32_t initial, uint32_t max)
-{
-  return _pool_create(mmc, initial, max);
-}
-
-memcached_pool_st * memcached_pool(const char *option_string, size_t option_string_length)
-{
-  memcached_pool_st *self;
-  memcached_st *memc= memcached(option_string, option_string_length);
-
-  if (! memc)
-    return NULL;
-
-  self= memcached_pool_create(memc, memc->configure.initial_pool_size, memc->configure.max_pool_size);
-  if (! self)
-  {
-    memcached_free(memc);
-    errno= ENOMEM;
-    return NULL;
-  }
-  errno= 0;
-
-  self->_owns_master= true;
-
-  return self;
-}
-
-memcached_st*  memcached_pool_destroy(memcached_pool_st* pool)
-{
-  if (! pool)
-    return NULL;
-
-  memcached_st *ret= pool->master;
-
-  for (int xx= 0; xx <= pool->firstfree; ++xx)
-  {
-    memcached_free(pool->mmc[xx]);
-    free(pool->mmc[xx]);
-    pool->mmc[xx] = NULL;
-  }
-
-  pthread_mutex_destroy(&pool->mutex);
-  pthread_cond_destroy(&pool->cond);
-  free(pool->mmc);
-  if (pool->_owns_master)
-  {
-    memcached_free(pool->master);
-    ret= NULL;
-  }
-  free(pool);
-
-  return ret;
-}
-
-memcached_st* memcached_pool_pop(memcached_pool_st* pool,
-                                 bool block,
-                                 memcached_return_t *rc)
-{
-  if (! pool || ! rc)
-  {
-    errno= EINVAL;
-    return NULL;
-  }
-
-  memcached_st *ret= NULL;
-  if ((*rc= mutex_enter(&pool->mutex)) != MEMCACHED_SUCCESS)
-  {
-    return NULL;
-  }
-
-  do
-  {
-    if (pool->firstfree > -1)
-    {
-      ret= pool->mmc[pool->firstfree--];
-    }
-    else if (pool->current_size == pool->size)
-    {
-      if (!block)
-      {
-        *rc= mutex_exit(&pool->mutex);
-        return NULL;
-      }
-
-      if (pthread_cond_wait(&pool->cond, &pool->mutex) == -1)
-      {
-        int err= errno;
-        mutex_exit(&pool->mutex);
-        errno= err;
-        *rc= MEMCACHED_ERRNO;
-        return NULL;
-      }
-    }
-    else if (grow_pool(pool) == -1)
-    {
-      *rc= mutex_exit(&pool->mutex);
-      return NULL;
-    }
-  }
-  while (ret == NULL);
-
-  *rc= mutex_exit(&pool->mutex);
-
-  return ret;
-}
-
-memcached_return_t memcached_pool_push(memcached_pool_st* pool,
-                                       memcached_st *mmc)
-{
-  if (! pool)
-    return MEMCACHED_INVALID_ARGUMENTS;
-
-  memcached_return_t rc= mutex_enter(&pool->mutex);
-
-  if (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  char* version= memcached_get_user_data(mmc);
-  /* Someone updated the behavior on the object.. */
-  if (version != pool->version)
-  {
-    memcached_free(mmc);
-    memset(mmc, 0, sizeof(*mmc));
-    if (memcached_clone(mmc, pool->master) == NULL)
-    {
-      rc= MEMCACHED_SOME_ERRORS;
-    }
-  }
-
-  pool->mmc[++pool->firstfree]= mmc;
-
-  if (pool->firstfree == 0 && pool->current_size == pool->size)
-  {
-    /* we might have people waiting for a connection.. wake them up :-) */
-    pthread_cond_broadcast(&pool->cond);
-  }
-
-  memcached_return_t rval= mutex_exit(&pool->mutex);
-  if (rc == MEMCACHED_SOME_ERRORS)
-    return rc;
-
-  return rval;
-}
-
-
-memcached_return_t memcached_pool_behavior_set(memcached_pool_st *pool,
-                                               memcached_behavior_t flag,
-                                               uint64_t data)
-{
-  if (! pool)
-    return MEMCACHED_INVALID_ARGUMENTS;
-
-  memcached_return_t rc= mutex_enter(&pool->mutex);
-  if (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  /* update the master */
-  rc= memcached_behavior_set(pool->master, flag, data);
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    mutex_exit(&pool->mutex);
-    return rc;
-  }
-
-  ++pool->version;
-  memcached_set_user_data(pool->master, pool->version);
-  /* update the clones */
-  for (int xx= 0; xx <= pool->firstfree; ++xx)
-  {
-    rc= memcached_behavior_set(pool->mmc[xx], flag, data);
-    if (rc == MEMCACHED_SUCCESS)
-    {
-      memcached_set_user_data(pool->mmc[xx], pool->version);
-    }
-    else
-    {
-      memcached_free(pool->mmc[xx]);
-      memset(pool->mmc[xx], 0, sizeof(*pool->mmc[xx]));
-
-      if (memcached_clone(pool->mmc[xx], pool->master) == NULL)
-      {
-        /* I'm not sure what to do in this case.. this would happen
-          if we fail to push the server list inside the client..
-          I should add a testcase for this, but I believe the following
-          would work, except that you would add a hole in the pool list..
-          in theory you could end up with an empty pool....
-        */
-        free(pool->mmc[xx]);
-        pool->mmc[xx]= NULL;
-      }
-    }
-  }
-
-  return mutex_exit(&pool->mutex);
-}
-
-memcached_return_t memcached_pool_behavior_get(memcached_pool_st *pool,
-                                               memcached_behavior_t flag,
-                                               uint64_t *value)
-{
-  if (! pool)
-    return MEMCACHED_INVALID_ARGUMENTS;
-
-  memcached_return_t rc= mutex_enter(&pool->mutex);
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    return rc;
-  }
-
-  *value= memcached_behavior_get(pool->master, flag);
-
-  return mutex_exit(&pool->mutex);
-}
diff --git a/libmemcached/util/pool.cc b/libmemcached/util/pool.cc
new file mode 100644 (file)
index 0000000..17cff07
--- /dev/null
@@ -0,0 +1,392 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ *
+ *      * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *
+ *      * Redistributions in binary form must reproduce the above
+ *  copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the
+ *  distribution.
+ *
+ *      * The names of its contributors may not be used to endorse or
+ *  promote products derived from this software without specific prior
+ *  written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+#include <libmemcached/memcached_util.h>
+
+#include <cassert>
+#include <cerrno>
+#include <pthread.h>
+#include <memory>
+
+static bool grow_pool(memcached_pool_st* pool);
+
+struct memcached_pool_st
+{
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
+  memcached_st *master;
+  memcached_st **server_pool;
+  int firstfree;
+  const uint32_t size;
+  uint32_t current_size;
+  bool _owns_master;
+
+  memcached_pool_st(memcached_st *master_arg, size_t max_arg) :
+    master(master_arg),
+    server_pool(NULL),
+    firstfree(-1),
+    size(max_arg),
+    current_size(0),
+    _owns_master(false)
+  {
+    pthread_mutex_init(&mutex, NULL);
+    pthread_cond_init(&cond, NULL);
+  }
+
+  bool init(uint32_t initial)
+  {
+    server_pool= new (std::nothrow) memcached_st *[size];
+    if (not server_pool)
+      return false;
+
+    /*
+      Try to create the initial size of the pool. An allocation failure at
+      this time is not fatal..
+    */
+    for (unsigned int x= 0; x < initial; ++x)
+    {
+      if (not grow_pool(this))
+        break;
+    }
+
+    return true;
+  }
+
+  ~memcached_pool_st()
+  {
+    for (int x= 0; x <= firstfree; ++x)
+    {
+      memcached_free(server_pool[x]);
+      server_pool[x] = NULL;
+    }
+
+    pthread_mutex_destroy(&mutex);
+    pthread_cond_destroy(&cond);
+    delete [] server_pool;
+    if (_owns_master)
+    {
+      memcached_free(master);
+    }
+  }
+
+  void increment_version()
+  {
+    ++master->configure.version;
+  }
+
+  bool compare_version(const memcached_st *arg) const
+  {
+    return (arg->configure.version == version());
+  }
+
+  int32_t version() const
+  {
+    return master->configure.version;
+  }
+};
+
+static memcached_return_t mutex_enter(pthread_mutex_t *mutex)
+{
+  int ret;
+  do
+  {
+    ret= pthread_mutex_lock(mutex);
+  } while (ret == -1 && errno == EINTR);
+
+  return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t mutex_exit(pthread_mutex_t *mutex)
+{
+  int ret;
+  do
+  {
+    ret= pthread_mutex_unlock(mutex);
+  } while (ret == -1 && errno == EINTR);
+
+  return (ret == -1) ? MEMCACHED_ERRNO : MEMCACHED_SUCCESS;
+}
+
+/**
+ * Grow the connection pool by creating a connection structure and clone the
+ * original memcached handle.
+ */
+static bool grow_pool(memcached_pool_st* pool)
+{
+  memcached_st *obj;
+  if (not (obj= memcached_clone(NULL, pool->master)))
+  {
+    return false;
+  }
+
+  pool->server_pool[++pool->firstfree]= obj;
+  pool->current_size++;
+  obj->configure.version= pool->version();
+
+  return true;
+}
+
+static inline memcached_pool_st *_pool_create(memcached_st* master, uint32_t initial, uint32_t max)
+{
+  if (! initial || ! max || initial > max)
+  {
+    errno= EINVAL;
+    return NULL;
+  }
+
+  memcached_pool_st *object= new (std::nothrow) memcached_pool_st(master, max);
+  if (not object)
+  {
+    errno= ENOMEM; // Set this for the failed calloc
+    return NULL;
+  }
+
+  /*
+    Try to create the initial size of the pool. An allocation failure at
+    this time is not fatal..
+  */
+  if (not object->init(initial))
+  {
+    delete object;
+    return NULL;
+  }
+
+  return object;
+}
+
+memcached_pool_st *memcached_pool_create(memcached_st* master, uint32_t initial, uint32_t max)
+{
+  return _pool_create(master, initial, max);
+}
+
+memcached_pool_st * memcached_pool(const char *option_string, size_t option_string_length)
+{
+  memcached_st *memc= memcached(option_string, option_string_length);
+
+  if (not memc)
+    return NULL;
+
+  memcached_pool_st *self;
+  self= memcached_pool_create(memc, memc->configure.initial_pool_size, memc->configure.max_pool_size);
+  if (not self)
+  {
+    memcached_free(memc);
+    errno= ENOMEM;
+    return NULL;
+  }
+  errno= 0;
+
+  self->_owns_master= true;
+
+  return self;
+}
+
+memcached_st*  memcached_pool_destroy(memcached_pool_st* pool)
+{
+  if (not pool)
+    return NULL;
+
+  // Legacy that we return the original structure
+  memcached_st *ret= NULL;
+  if (pool->_owns_master)
+  { }
+  else
+  {
+    ret= pool->master;
+  }
+
+  delete pool;
+
+  return ret;
+}
+
+memcached_st* memcached_pool_pop(memcached_pool_st* pool,
+                                 bool block,
+                                 memcached_return_t *rc)
+{
+  assert(pool);
+  assert(rc);
+  if (not pool ||  not rc)
+  {
+    errno= EINVAL;
+    return NULL;
+  }
+
+  if ((*rc= mutex_enter(&pool->mutex)) != MEMCACHED_SUCCESS)
+  {
+    return NULL;
+  }
+
+  memcached_st *ret= NULL;
+  do
+  {
+    if (pool->firstfree > -1)
+    {
+      ret= pool->server_pool[pool->firstfree--];
+    }
+    else if (pool->current_size == pool->size)
+    {
+      if (not block)
+      {
+        *rc= mutex_exit(&pool->mutex); // this should be a different error
+        return NULL;
+      }
+
+      if (pthread_cond_wait(&pool->cond, &pool->mutex) == -1)
+      {
+        int err= errno;
+        mutex_exit(&pool->mutex);
+        errno= err;
+        *rc= MEMCACHED_ERRNO;
+        return NULL;
+      }
+    }
+    else if (not grow_pool(pool))
+    {
+      (void)mutex_exit(&pool->mutex);
+      *rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+      return NULL;
+    }
+  }
+  while (ret == NULL);
+
+  *rc= mutex_exit(&pool->mutex);
+
+  return ret;
+}
+
+memcached_return_t memcached_pool_push(memcached_pool_st* pool, memcached_st *released)
+{
+  if (not pool)
+    return MEMCACHED_INVALID_ARGUMENTS;
+
+  memcached_return_t rc= mutex_enter(&pool->mutex);
+
+  if (rc != MEMCACHED_SUCCESS)
+    return rc;
+
+  /* Someone updated the behavior on the object.. */
+  if (not pool->compare_version(released))
+  {
+    memcached_free(released);
+    if (not (released= memcached_clone(NULL, pool->master)))
+    {
+      rc= MEMCACHED_SOME_ERRORS;
+    }
+  }
+
+  pool->server_pool[++pool->firstfree]= released;
+
+  if (pool->firstfree == 0 && pool->current_size == pool->size)
+  {
+    /* we might have people waiting for a connection.. wake them up :-) */
+    pthread_cond_broadcast(&pool->cond);
+  }
+
+  memcached_return_t rval= mutex_exit(&pool->mutex);
+  if (rc == MEMCACHED_SOME_ERRORS)
+    return rc;
+
+  return rval;
+}
+
+
+memcached_return_t memcached_pool_behavior_set(memcached_pool_st *pool,
+                                               memcached_behavior_t flag,
+                                               uint64_t data)
+{
+  if (not pool)
+    return MEMCACHED_INVALID_ARGUMENTS;
+
+  memcached_return_t rc= mutex_enter(&pool->mutex);
+  if (rc != MEMCACHED_SUCCESS)
+    return rc;
+
+  /* update the master */
+  rc= memcached_behavior_set(pool->master, flag, data);
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    mutex_exit(&pool->mutex);
+    return rc;
+  }
+
+  pool->increment_version();
+  /* update the clones */
+  for (int xx= 0; xx <= pool->firstfree; ++xx)
+  {
+    rc= memcached_behavior_set(pool->server_pool[xx], flag, data);
+    if (rc == MEMCACHED_SUCCESS)
+    {
+      pool->server_pool[xx]->configure.version= pool->version();
+    }
+    else
+    {
+      memcached_free(pool->server_pool[xx]);
+      if (not (pool->server_pool[xx]= memcached_clone(NULL, pool->master)))
+      {
+        /* I'm not sure what to do in this case.. this would happen
+          if we fail to push the server list inside the client..
+          I should add a testcase for this, but I believe the following
+          would work, except that you would add a hole in the pool list..
+          in theory you could end up with an empty pool....
+        */
+      }
+    }
+  }
+
+  return mutex_exit(&pool->mutex);
+}
+
+memcached_return_t memcached_pool_behavior_get(memcached_pool_st *pool,
+                                               memcached_behavior_t flag,
+                                               uint64_t *value)
+{
+  if (! pool)
+    return MEMCACHED_INVALID_ARGUMENTS;
+
+  memcached_return_t rc= mutex_enter(&pool->mutex);
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    return rc;
+  }
+
+  *value= memcached_behavior_get(pool->master, flag);
+
+  return mutex_exit(&pool->mutex);
+}
diff --git a/libmemcached/util/version.c b/libmemcached/util/version.c
deleted file mode 100644 (file)
index a0b6925..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* LibMemcached
- * Copyright (C) 2010 Brian Aker
- * All rights reserved.
- *
- * Use and distribution licensed under the BSD license.  See
- * the COPYING file in the parent directory for full text.
- *
- * Summary: connect to all hosts, and make sure they meet a minimum version
- *
- */
-
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/common.h"
-#include "libmemcached/memcached_util.h"
-
-struct local_context
-{
-  uint8_t major_version;
-  uint8_t minor_version;
-  uint8_t micro_version;
-
-  bool truth;
-};
-
-static memcached_return_t check_server_version(const memcached_st *ptr,
-                                               const memcached_server_st *instance,
-                                               void *context)
-{
-  /* Do Nothing */
-  struct local_context *check= (struct local_context *)context;
-  (void)ptr;
-
-  if (instance->major_version != UINT8_MAX &&
-      instance->major_version >= check->major_version &&
-      instance->minor_version >= check->minor_version &&
-      instance->micro_version >= check->micro_version )
-  {
-    return MEMCACHED_SUCCESS;
-  }
-
-  check->truth= false;
-
-  return MEMCACHED_FAILURE;
-}
-
-bool libmemcached_util_version_check(memcached_st *memc,
-                                     uint8_t major_version,
-                                     uint8_t minor_version,
-                                     uint8_t micro_version)
-{
-  memcached_server_fn callbacks[1];
-  memcached_return_t rc= memcached_version(memc);
-
-  if (rc != MEMCACHED_SUCCESS)
-    return false;
-
-  struct local_context check= { .major_version= major_version, .minor_version= minor_version, .micro_version= micro_version, .truth= true };
-
-  callbacks[0]= check_server_version;
-  memcached_server_cursor(memc, callbacks, (void *)&check,  1);
-
-  return check.truth;
-}
diff --git a/libmemcached/util/version.cc b/libmemcached/util/version.cc
new file mode 100644 (file)
index 0000000..a820829
--- /dev/null
@@ -0,0 +1,87 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  Libmemcached library
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2010 Brian Aker All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ *
+ *      * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *
+ *      * Redistributions in binary form must reproduce the above
+ *  copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the
+ *  distribution.
+ *
+ *      * The names of its contributors may not be used to endorse or
+ *  promote products derived from this software without specific prior
+ *  written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <libmemcached/common.h>
+#include <libmemcached/memcached_util.h>
+
+struct local_context
+{
+  uint8_t major_version;
+  uint8_t minor_version;
+  uint8_t micro_version;
+
+  bool truth;
+};
+
+static memcached_return_t check_server_version(const memcached_st *ptr,
+                                               const memcached_server_st *instance,
+                                               void *context)
+{
+  /* Do Nothing */
+  struct local_context *check= (struct local_context *)context;
+  (void)ptr;
+
+  if (instance->major_version != UINT8_MAX &&
+      instance->major_version >= check->major_version &&
+      instance->minor_version >= check->minor_version &&
+      instance->micro_version >= check->micro_version )
+  {
+    return MEMCACHED_SUCCESS;
+  }
+
+  check->truth= false;
+
+  return MEMCACHED_FAILURE;
+}
+
+bool libmemcached_util_version_check(memcached_st *memc,
+                                     uint8_t major_version,
+                                     uint8_t minor_version,
+                                     uint8_t micro_version)
+{
+  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);
+
+  return check.truth;
+}
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 2e93ffb9bf136f3b3c0f946cf7ea1da98baf4389..10f9eff396db9d781c082fb886d5432d2ac43115 100644 (file)
@@ -83,13 +83,13 @@ you will need to install %{name}-devel.
 %exclude %{_libdir}/libmemcachedutil.la
 %exclude %{_libdir}/libmemcachedprotocol.la
 %{_libdir}/libhashkit.so.1.0.0
-%{_libdir}/libmemcached.so.6.0.0
-%{_libdir}/libmemcachedutil.so.1.0.0
+%{_libdir}/libmemcached.so.7.0.0
+%{_libdir}/libmemcachedutil.so.2.0.0
 %{_libdir}/libmemcachedprotocol.so.0.0.0
 %{_libdir}/libhashkit.so.1
-%{_libdir}/libmemcached.so.6
+%{_libdir}/libmemcached.so.7
 %{_libdir}/libmemcachedprotocol.so.0
-%{_libdir}/libmemcachedutil.so.1
+%{_libdir}/libmemcachedutil.so.2
 %{_mandir}/man1/memcapable.1.gz
 %{_mandir}/man1/memcat.1.gz
 %{_mandir}/man1/memcp.1.gz
@@ -188,6 +188,7 @@ you will need to install %{name}-devel.
 %{_mandir}/man3/libmemcached_configuration.3.gz
 %{_mandir}/man3/libmemcached_examples.3.gz
 %{_mandir}/man3/libmemcachedutil.3.gz
+%{_mandir}/man3/memcached.3.gz
 %{_mandir}/man3/memcached_add.3.gz
 %{_mandir}/man3/memcached_add_by_key.3.gz
 %{_mandir}/man3/memcached_analyze.3.gz
@@ -201,7 +202,6 @@ you will need to install %{name}-devel.
 %{_mandir}/man3/memcached_cas_by_key.3.gz
 %{_mandir}/man3/memcached_clone.3.gz
 %{_mandir}/man3/memcached_create.3.gz
-%{_mandir}/man3/memcached_create_with_options.3.gz
 %{_mandir}/man3/memcached_decrement.3.gz
 %{_mandir}/man3/memcached_decrement_with_initial.3.gz
 %{_mandir}/man3/memcached_delete.3.gz
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 a5e28e6949c0182f7d6b31a294e4a94cd018e290..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++;
   }
@@ -4310,6 +4336,7 @@ static void* connection_release(void *arg)
   } *resource= arg;
 
   usleep(250);
+  // Release all of the memc we are holding
   assert(memcached_pool_push(resource->pool, resource->mmc) == MEMCACHED_SUCCESS);
   return arg;
 }
@@ -4322,6 +4349,7 @@ static test_return_t connection_pool_test(memcached_st *memc)
   memcached_st *mmc[POOL_SIZE];
   memcached_return_t rc;
 
+  // Fill up our array that we will store the memc that are in the pool
   for (size_t x= 0; x < POOL_SIZE; ++x)
   {
     mmc[x]= memcached_pool_pop(pool, false, &rc);
@@ -4329,6 +4357,7 @@ static test_return_t connection_pool_test(memcached_st *memc)
     test_true(rc == MEMCACHED_SUCCESS);
   }
 
+  // All memc should be gone
   test_true(memcached_pool_pop(pool, false, &rc) == NULL);
   test_true(rc == MEMCACHED_SUCCESS);
 
@@ -4337,11 +4366,12 @@ static test_return_t connection_pool_test(memcached_st *memc)
     memcached_pool_st* pool;
     memcached_st* mmc;
   } item= { .pool = pool, .mmc = mmc[9] };
+
   pthread_create(&tid, NULL, connection_release, &item);
   mmc[9]= memcached_pool_pop(pool, true, &rc);
   test_true(rc == MEMCACHED_SUCCESS);
   pthread_join(tid, NULL);
-  test_true(mmc[9] == item.mmc);
+  test_true(mmc[9]);
   const char *key= "key";
   size_t keylen= strlen(key);
 
@@ -6291,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)
 {