Merge Thomason's cork patch.
authorBrian Aker <brian@gaz>
Fri, 15 Jan 2010 00:35:02 +0000 (16:35 -0800)
committerBrian Aker <brian@gaz>
Fri, 15 Jan 2010 00:35:02 +0000 (16:35 -0800)
276 files changed:
.bzrignore
AUTHORS
ChangeLog
Makefile.am
clients/Makefile.am [deleted file]
clients/client_options.h
clients/execute.c
clients/execute.h
clients/generator.c
clients/generator.h
clients/include.am [new file with mode: 0644]
clients/memcapable.c
clients/memcat.c
clients/memcp.c
clients/memdump.c
clients/memerror.c
clients/memflush.c
clients/memrm.c
clients/memslap.c
clients/memstat.c
clients/ms_atomic.h [new file with mode: 0644]
clients/ms_conn.c [new file with mode: 0644]
clients/ms_conn.h [new file with mode: 0644]
clients/ms_memslap.h [new file with mode: 0644]
clients/ms_setting.c [new file with mode: 0644]
clients/ms_setting.h [new file with mode: 0644]
clients/ms_sigsegv.c [new file with mode: 0644]
clients/ms_sigsegv.h [new file with mode: 0644]
clients/ms_stats.c [new file with mode: 0644]
clients/ms_stats.h [new file with mode: 0644]
clients/ms_task.c [new file with mode: 0644]
clients/ms_task.h [new file with mode: 0644]
clients/ms_thread.c [new file with mode: 0644]
clients/ms_thread.h [new file with mode: 0644]
clients/utilities.c
clients/utilities.h
config/bootstrap [deleted symlink]
configure.ac
docs/Makefile.am
docs/hashkit_create.pod [new file with mode: 0644]
docs/hashkit_functions.pod [new file with mode: 0644]
docs/hashkit_value.pod [new file with mode: 0644]
docs/libmemcached.pod
docs/libmemcached_examples.pod
docs/libmemcachedutil.pod
docs/make_index.pl [new file with mode: 0644]
docs/memcached_analyze.pod
docs/memcached_auto.pod
docs/memcached_behavior.pod
docs/memcached_callback.pod
docs/memcached_create.pod
docs/memcached_delete.pod
docs/memcached_dump.pod
docs/memcached_flush.pod
docs/memcached_flush_buffers.pod
docs/memcached_generate_hash_value.pod
docs/memcached_get.pod
docs/memcached_memory_allocators.pod
docs/memcached_pool.pod
docs/memcached_quit.pod
docs/memcached_result_st.pod
docs/memcached_server_st.pod
docs/memcached_servers.pod
docs/memcached_set.pod
docs/memcached_stats.pod
docs/memcached_strerror.pod
docs/memcached_user_data.pod
docs/memcached_verbosity.pod
docs/memcached_version.pod
docs/memcapable.pod
docs/memcat.pod
docs/memcp.pod
docs/memdump.pod
docs/memerror.pod
docs/memflush.pod
docs/memrm.pod
docs/memslap.pod
docs/memstat.pod
example/Makefile.am [deleted file]
example/include.am [new file with mode: 0644]
example/interface_v1.c
example/memcached_light.c
libhashkit/algorithm.h [new file with mode: 0644]
libhashkit/behavior.c [new file with mode: 0644]
libhashkit/behavior.h [new file with mode: 0644]
libhashkit/common.h [new file with mode: 0644]
libhashkit/crc32.c [new file with mode: 0644]
libhashkit/default.c [new file with mode: 0644]
libhashkit/fnv.c [new file with mode: 0644]
libhashkit/hashkit.c [new file with mode: 0644]
libhashkit/hashkit.h [new file with mode: 0644]
libhashkit/hsieh.c [new file with mode: 0644]
libhashkit/include.am [new file with mode: 0644]
libhashkit/jenkins.c [new file with mode: 0644]
libhashkit/ketama.c [new file with mode: 0644]
libhashkit/md5.c [new file with mode: 0644]
libhashkit/murmur.c [new file with mode: 0644]
libhashkit/strerror.c [new file with mode: 0644]
libhashkit/strerror.h [new file with mode: 0644]
libhashkit/types.h [new file with mode: 0644]
libhashkit/visibility.h [new file with mode: 0644]
libmemcached/Makefile.am [deleted file]
libmemcached/allocators.c [new file with mode: 0644]
libmemcached/analyze.c [new file with mode: 0644]
libmemcached/analyze.h [new file with mode: 0644]
libmemcached/auto.c [new file with mode: 0644]
libmemcached/auto.h [new file with mode: 0644]
libmemcached/behavior.c [new file with mode: 0644]
libmemcached/behavior.h [new file with mode: 0644]
libmemcached/byteorder.c
libmemcached/byteorder.h
libmemcached/callback.c [new file with mode: 0644]
libmemcached/callback.h [new file with mode: 0644]
libmemcached/common.h
libmemcached/configure.h.in [new file with mode: 0644]
libmemcached/connect.c [new file with mode: 0644]
libmemcached/constants.h [new file with mode: 0644]
libmemcached/delete.c [new file with mode: 0644]
libmemcached/do.c [new file with mode: 0644]
libmemcached/dump.c [new file with mode: 0644]
libmemcached/dump.h [new file with mode: 0644]
libmemcached/fetch.c [new file with mode: 0644]
libmemcached/flush.c [new file with mode: 0644]
libmemcached/flush_buffers.c [new file with mode: 0644]
libmemcached/get.c [new file with mode: 0644]
libmemcached/get.h [new file with mode: 0644]
libmemcached/hash.c [new file with mode: 0644]
libmemcached/hosts.c [new file with mode: 0644]
libmemcached/include.am [new file with mode: 0644]
libmemcached/internal.h [new file with mode: 0644]
libmemcached/io.c [new file with mode: 0644]
libmemcached/io.h [new file with mode: 0644]
libmemcached/jenkins_hash.c
libmemcached/key.c [new file with mode: 0644]
libmemcached/libmemcached.ver [deleted file]
libmemcached/libmemcached_probes.h
libmemcached/memcached.c
libmemcached/memcached.h
libmemcached/memcached.hpp
libmemcached/memcached/protocol_binary.h
libmemcached/memcached_allocators.c [deleted file]
libmemcached/memcached_analyze.c [deleted file]
libmemcached/memcached_auto.c [deleted file]
libmemcached/memcached_behavior.c [deleted file]
libmemcached/memcached_callback.c [deleted file]
libmemcached/memcached_configure.h.in [deleted file]
libmemcached/memcached_connect.c [deleted file]
libmemcached/memcached_constants.h [deleted file]
libmemcached/memcached_delete.c [deleted file]
libmemcached/memcached_do.c [deleted file]
libmemcached/memcached_dump.c [deleted file]
libmemcached/memcached_fetch.c [deleted file]
libmemcached/memcached_flush.c [deleted file]
libmemcached/memcached_flush_buffers.c [deleted file]
libmemcached/memcached_get.c [deleted file]
libmemcached/memcached_get.h [deleted file]
libmemcached/memcached_hash.c [deleted file]
libmemcached/memcached_hosts.c [deleted file]
libmemcached/memcached_internal.h [deleted file]
libmemcached/memcached_io.c [deleted file]
libmemcached/memcached_io.h [deleted file]
libmemcached/memcached_key.c [deleted file]
libmemcached/memcached_parse.c [deleted file]
libmemcached/memcached_pool.h [deleted file]
libmemcached/memcached_purge.c [deleted file]
libmemcached/memcached_quit.c [deleted file]
libmemcached/memcached_response.c [deleted file]
libmemcached/memcached_result.c [deleted file]
libmemcached/memcached_result.h [deleted file]
libmemcached/memcached_server.c [deleted file]
libmemcached/memcached_server.h [deleted file]
libmemcached/memcached_stats.c [deleted file]
libmemcached/memcached_storage.c [deleted file]
libmemcached/memcached_storage.h [deleted file]
libmemcached/memcached_strerror.c [deleted file]
libmemcached/memcached_string.c [deleted file]
libmemcached/memcached_string.h [deleted file]
libmemcached/memcached_types.h [deleted file]
libmemcached/memcached_util.h
libmemcached/memcached_verbosity.c [deleted file]
libmemcached/memcached_version.c [deleted file]
libmemcached/memcached_watchpoint.h [deleted file]
libmemcached/parse.c [new file with mode: 0644]
libmemcached/protocol/common.h
libmemcached/protocol/libmemcachedprotocol.ver [deleted file]
libmemcached/protocol_handler.h
libmemcached/purge.c [new file with mode: 0644]
libmemcached/quit.c [new file with mode: 0644]
libmemcached/response.c [new file with mode: 0644]
libmemcached/response.h [new file with mode: 0644]
libmemcached/result.c [new file with mode: 0644]
libmemcached/result.h [new file with mode: 0644]
libmemcached/server.c [new file with mode: 0644]
libmemcached/server.h [new file with mode: 0644]
libmemcached/stats.c [new file with mode: 0644]
libmemcached/stats.h [new file with mode: 0644]
libmemcached/storage.c [new file with mode: 0644]
libmemcached/storage.h [new file with mode: 0644]
libmemcached/strerror.c [new file with mode: 0644]
libmemcached/string.c [new file with mode: 0644]
libmemcached/string.h [new file with mode: 0644]
libmemcached/types.h [new file with mode: 0644]
libmemcached/util/libmemcachedutil.ver [deleted file]
libmemcached/util/memcached_pool.c [deleted file]
libmemcached/util/pool.c [new file with mode: 0644]
libmemcached/util/pool.h [new file with mode: 0644]
libmemcached/verbosity.c [new file with mode: 0644]
libmemcached/version.c [new file with mode: 0644]
libmemcached/visibility.h
libmemcached/watchpoint.h [new file with mode: 0644]
m4/byteorder.m4
m4/pandora_canonical.m4
m4/pandora_check_cxx_standard.m4
m4/pandora_cinttypes.m4 [new file with mode: 0644]
m4/pandora_cstdint.m4 [new file with mode: 0644]
m4/pandora_cxx_demangle.m4 [new file with mode: 0644]
m4/pandora_drizzle_build.m4 [new file with mode: 0644]
m4/pandora_fdatasync.m4 [new file with mode: 0644]
m4/pandora_have_better_malloc.m4
m4/pandora_have_gcc_atomics.m4 [new file with mode: 0644]
m4/pandora_have_libavahi.m4 [new file with mode: 0644]
m4/pandora_have_libbdb.m4 [new file with mode: 0644]
m4/pandora_have_libdl.m4 [new file with mode: 0644]
m4/pandora_have_libevent.m4 [new file with mode: 0644]
m4/pandora_have_libgearman.m4
m4/pandora_have_libmemcached.m4
m4/pandora_have_libpcre.m4 [new file with mode: 0644]
m4/pandora_have_libreadline.m4 [new file with mode: 0644]
m4/pandora_have_libtokyocabinet.m4 [new file with mode: 0644]
m4/pandora_have_libuuid.m4 [new file with mode: 0644]
m4/pandora_have_libxml2.m4 [new file with mode: 0644]
m4/pandora_have_libz.m4 [new file with mode: 0644]
m4/pandora_header_assert.m4
m4/pandora_libtool.m4
m4/pandora_optimize.m4
m4/pandora_platform.m4
m4/pandora_plugins.m4
m4/pandora_print_callstack.m4 [new file with mode: 0644]
m4/pandora_pthread.m4
m4/pandora_run_cpplint.m4 [new file with mode: 0644]
m4/pandora_sasl.m4 [new file with mode: 0644]
m4/pandora_shared_ptr.m4
m4/pandora_stack_direction.m4 [new file with mode: 0644]
m4/pandora_stl_hash.m4 [new file with mode: 0644]
m4/pandora_vc_build.m4
m4/pandora_version.m4 [new file with mode: 0644]
m4/pandora_visibility.m4 [new file with mode: 0644]
m4/pandora_warnings.m4
m4/pandora_with_gettext.m4 [new file with mode: 0644]
m4/pandora_with_memcached.m4
m4/pandora_with_python.m4
m4/pandora_with_python3.m4
m4/podchecker.m4 [new file with mode: 0644]
m4/visibility.m4 [deleted file]
support/Makefile.am [deleted file]
support/include.am [new file with mode: 0644]
support/libmemcached.spec.in
tests/Makefile.am [deleted file]
tests/atomsmasher.c
tests/function.c [deleted file]
tests/hash_results.h [new file with mode: 0644]
tests/hashkit_functions.c [new file with mode: 0644]
tests/include.am [new file with mode: 0644]
tests/ketama_test_cases.h
tests/ketama_test_cases_spy.h
tests/libmemcached_world.h [new file with mode: 0644]
tests/mem_functions.c [new file with mode: 0644]
tests/output.res [deleted file]
tests/output2.res [deleted file]
tests/plus.cpp
tests/server.c
tests/server.h
tests/start.c
tests/test.c
tests/test.h
tests/udp.c [deleted file]

index 507ac4a16c1590267c322a1397fec425a5d9ae36..81f3b40263d749c5cc8304b7ddc82ae8af820153 100644 (file)
@@ -1,14 +1,15 @@
 *.lo
-*/.deps
-*/.libs
-*/.dirstamp
+*.pop
+*/*.l[oa]
+*/*/*.l[oa]
 */*/.deps
-*/*/.libs
 */*/.dirstamp
+*/*/.libs
+*/.deps
+*/.dirstamp
+*/.libs
 */Makefile
 */Makefile.in
-*/*.l[oa]
-*/*/*.l[oa]
 *TAGS
 INSTALL
 Makefile
@@ -39,15 +40,127 @@ config/missing
 config/plugin.ac
 configure
 docs/*.[13]
+docs/*.html
+docs/pod2htmd.tmp
+docs/pod2htmi.tmp
 example/memcached_light
+hashkit_clone.pop
+hashkit_crc32.pop
+hashkit_create.pop
+hashkit_fnv1_32.pop
+hashkit_fnv1_64.pop
+hashkit_fnv1a_32.pop
+hashkit_fnv1a_64.pop
+hashkit_free.pop
+hashkit_functions.pop
+hashkit_hsieh.pop
+hashkit_is_allocated.pop
+hashkit_jenkins.pop
+hashkit_md5.pop
+hashkit_murmur.pop
+hashkit_value.pop
 libmemcached-*.tar.gz
+libmemcached-0.30-1.src.rpm
+libmemcached-0.30-1.x86_64.rpm
+libmemcached-0.31-1.src.rpm
+libmemcached-0.31-1.x86_64.rpm
+libmemcached-?.??/
+libmemcached.pop
+libmemcached/configure.h
 libmemcached/memcached_configure.h
+libmemcached_examples.pop
+libmemcachedutil.pop
 libtool
 libtool.m4
 ltoptions.m4
 ltsugar.m4
 ltversion.m4
 lt~obsolete.m4
+memcached_add.pop
+memcached_add_by_key.pop
+memcached_analyze.pop
+memcached_append.pop
+memcached_append_by_key.pop
+memcached_behavior_get.pop
+memcached_behavior_set.pop
+memcached_callback_get.pop
+memcached_callback_set.pop
+memcached_cas.pop
+memcached_cas_by_key.pop
+memcached_clone.pop
+memcached_create.pop
+memcached_decrement.pop
+memcached_decrement_with_initial.pop
+memcached_delete.pop
+memcached_delete_by_key.pop
+memcached_dump.pop
+memcached_fetch.pop
+memcached_fetch_execute.pop
+memcached_fetch_result.pop
+memcached_flush.pop
+memcached_flush_buffers.pop
+memcached_free.pop
+memcached_generate_hash_value.pop
+memcached_get.pop
+memcached_get_by_key.pop
+memcached_get_memory_allocators.pop
+memcached_get_user_data.pop
+memcached_increment.pop
+memcached_increment_with_initial.pop
+memcached_lib_version.pop
+memcached_mget.pop
+memcached_mget_by_key.pop
+memcached_mget_execute.pop
+memcached_mget_execute_by_key.pop
+memcached_pool_behavior_get.pop
+memcached_pool_behavior_set.pop
+memcached_pool_create.pop
+memcached_pool_destroy.pop
+memcached_pool_pop.pop
+memcached_pool_push.pop
+memcached_prepend.pop
+memcached_prepend_by_key.pop
+memcached_quit.pop
+memcached_replace.pop
+memcached_replace_by_key.pop
+memcached_result_cas.pop
+memcached_result_create.pop
+memcached_result_flags.pop
+memcached_result_free.pop
+memcached_result_key_length.pop
+memcached_result_key_value.pop
+memcached_result_length.pop
+memcached_result_st.pop
+memcached_result_value.pop
+memcached_server_add.pop
+memcached_server_add_unix_socket.pop
+memcached_server_count.pop
+memcached_server_list.pop
+memcached_server_list_append.pop
+memcached_server_list_count.pop
+memcached_server_list_free.pop
+memcached_server_push.pop
+memcached_servers_parse.pop
+memcached_set.pop
+memcached_set_by_key.pop
+memcached_set_memory_allocators.pop
+memcached_set_user_data.pop
+memcached_stat.pop
+memcached_stat_get_keys.pop
+memcached_stat_get_value.pop
+memcached_stat_servername.pop
+memcached_strerror.pop
+memcached_verbosity.pop
+memcached_version.pop
+memcapable.pop
+memcat.pop
+memcp.pop
+memdump.pop
+memerror.pop
+memflush.pop
+memrm.pop
+memslap.pop
+memstat.pop
 stamp-h1
 support/Makefile
 support/Makefile.in
@@ -58,10 +171,6 @@ tests/atomsmasher
 tests/output.cmp
 tests/startservers
 tests/testapp
+tests/testhashkit
 tests/testplus
 tests/udptest
-libmemcached-0.30-1.src.rpm
-libmemcached-0.30-1.x86_64.rpm
-libmemcached-0.31-1.src.rpm
-libmemcached-0.31-1.x86_64.rpm
-libmemcached-?.??/
diff --git a/AUTHORS b/AUTHORS
index 24dbad1dfc11e0ea59c622306f480d1975ecb1aa..1bdae2fbc4a40a859f7b9f5985d8979dbb2d4a7f 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -3,8 +3,9 @@ Mark Atwood, -- Tools, Docs
 Patrick Galbraith, -- C++ Interface
 Padraig O'Sullivan, -- C++ Interface (current one)
 Tim Bunce, -- Docs
-Trond Norbye, trond.norbye@sun.com -- Binary protocol, Misc
+Trond Norbye, trond.norbye@gmail.com -- Binary protocol, Misc
 Yin Chen, -- Ketama Work
 Toru Maesaka, dev@torum.net -- Stats analysis
 Eric Lambert, -- UDP work
 Monty Taylor, -- Build Releated (Pandora)
+Mingqiang Zhuang, Schooner Information Technology, Inc. -- Rewrite of memslap
index cea8e72bb750923cf1a0d15cc0b1a6536f85d1e3..c324e485306256c1bc6ef5fde45794e4d9a11fde 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+0.38
+
+ * Added MEMCACHED_BEHAVIOR_CORK.
+ * memslap now creates a configuration file at ~/.memslap.cnf
+
+ * memcached_purge() now calls any callbacks registered during get
+   execution.
+
+0.37 Mon Jan 11 16:29:57 PST 2010
+ * Fixed build for libhashkit.
+ * Fixed install path regression.  
+ * Modified RPM to strict check install. 
+ * Added documentation for memcached_server_cursor();
+ * Added memcached_servers_reset().
+ * Modified memcached_st to remove dead cursor_server member.
+
+0.36 Wed Jan  6 18:23:50 PST 2010
+  * Merged in new memslap utility.
+  * All of constants.h has been updated to match style (all old identifiers
+    continue to work).
+  * Added first pass for libhashkit.
+  * Updated test Framework/extended tests.
+  * Random read support during replication added.
+  * Modified use_sort so that the option can be applied to any distribution type.
+  * We removed the MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE added in 0.35. Instead use
+    memcached_behavior_set_distribution().
+
 0.35 Mon Nov  9 11:18:33 PST 2009
   * Added support for by_key operations for inc/dec methods.
   * Added mget test to memslap.
index eeab710a4aad9c6588ec01b86f597461c911f021..d163202714941cb07d46fe389fe06246813091d4 100644 (file)
@@ -1,26 +1,39 @@
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = docs libmemcached support clients tests example
-EXTRA_dist = README.FIRST
+# includes append to these:
+SUFFIXES =
+PHONY =
+TESTS =
+CLEANFILES =
+bin_PROGRAMS =
+noinst_HEADERS =
+lib_LTLIBRARIES =
+noinst_LTLIBRARIES =
+noinst_PROGRAMS =
+include_HEADERS =
+nobase_include_HEADERS =
+EXTRA_HEADERS =
+BUILT_SOURCES=
+EXTRA_DIST = README.FIRST
+
+SUBDIRS = docs
+
+test-docs:
+       (cd docs && $(MAKE) test-docs)
+include libmemcached/include.am
+include clients/include.am
+include libhashkit/include.am
+include tests/include.am
+include example/include.am
+include support/include.am
 
 check-local: test-no-outputdiff
 
-test: all
-       @(cd tests; ${MAKE} test)
-
-test-extended: all
-       @(cd tests; ${MAKE} test-extended)
-
-valgrind:
-       @(cd tests; ${MAKE} valgrind)
-
-test-no-outputdiff:
-       @(cd tests; ${MAKE} test-no-outputdiff)
 
 fedora:
        rm -f ~/rpmbuild/RPMS/x86_64/libmemcached-$(VERSION)*.rpm
        rm -f ~/rpmbuild/SRPMS/libmemcached-$(VERSION)*.rpm
-       cp libmemcached-$(VERSION).tar.gz /home/brian/rpmbuild/SOURCES/
+       cp libmemcached-$(VERSION).tar.gz ~/rpmbuild/SOURCES/
        rpmbuild -ba support/libmemcached.spec
        cp ~/rpmbuild/RPMS/x86_64/libmemcached-$(VERSION)*.rpm .
        cp ~/rpmbuild/SRPMS/libmemcached-$(VERSION)*.rpm .
@@ -28,9 +41,16 @@ fedora:
 generic:
        rm -f ~/rpmbuild/RPMS/x86_64/libmemcached-$(VERSION)*.rpm
        rm -f ~/rpmbuild/SRPMS/libmemcached-$(VERSION)*.rpm
-       cp libmemcached-$(VERSION).tar.gz /home/brian/rpmbuild/SOURCES/
+       cp libmemcached-$(VERSION).tar.gz ~/rpmbuild/SOURCES/
        rpmbuild -ba support/libmemcached.spec
        cp ~/rpmbuild/RPMS/x86_64/libmemcached-$(VERSION)*.rpm .
        cp ~/rpmbuild/SRPMS/libmemcached-$(VERSION)*.rpm .
 
 rpm: all dist generic fedora
+
+merge-clean:
+       find ./ | $(GREP) \.orig | xargs rm -f
+       find ./ | $(GREP) \.rej | xargs rm -f
+       find ./ | $(GREP) \~$$ | xargs rm -f
+       bzr unknowns
+
diff --git a/clients/Makefile.am b/clients/Makefile.am
deleted file mode 100644 (file)
index e5a1f0c..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-LDADDS = libutilities.la $(top_builddir)/libmemcached/libmemcached.la
-
-bin_PROGRAMS = memcat memdump memcp memstat memrm memflush memslap memerror memcapable
-
-noinst_HEADERS = client_options.h \
-               utilities.h \
-               generator.h \
-               execute.h
-
-noinst_LTLIBRARIES= libutilities.la libgenexec.la
-
-libutilities_la_SOURCES= utilities.c
-libgenexec_la_SOURCES= generator.c execute.c
-
-memcat_SOURCES = memcat.c
-memcat_LDADD = $(LDADDS)
-
-memcp_SOURCES = memcp.c
-memcp_LDADD = $(LDADDS)
-
-memdump_SOURCES = memdump.c
-memdump_LDADD = $(LDADDS)
-
-memstat_SOURCES = memstat.c
-memstat_LDADD = $(LDADDS)
-
-memrm_SOURCES = memrm.c
-memrm_LDADD = $(LDADDS)
-
-memflush_SOURCES = memflush.c
-memflush_LDADD = $(LDADDS)
-
-memerror_SOURCES = memerror.c
-memerror_LDADD = $(LDADDS)
-
-memslap_SOURCES = memslap.c
-memslap_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS)
-memslap_LDADD = $(PTHREAD_LIBS) libgenexec.la $(LDADDS)
-
-memcapable_SOURCES = memcapable.c
-if BUILD_BYTEORDER
-memcapable_LDADD=$(top_builddir)/libmemcached/libbyteorder.la
-endif
-
-test-start-server:
-       memflush --servers=localhost
-       memcp --servers=localhost /etc/services
-       memcat --servers=localhost /etc/services
-       memrm --servers=localhost /etc/services
-       memstat --servers=localhost
-       memslap --servers=localhost
-       memslap --servers=localhost --concurrency=10
-       memslap --servers=localhost --concurrency=10 --initial-load=1000
-       memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10
-       memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=get
-       memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set
-       memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set --non-blocking
-
-valgrind:
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  memslap --servers=localhost
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  memslap --servers=localhost --concurrency=10
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  memslap --servers=localhost --concurrency=10 --initial-load=1000
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=get
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set --non-blocking
index a4f0f47fa29130cdd575f71c29d8b4da2be52e05..955bcd18ff8bb959e70d1a4b8bd32a0bca2d44b0 100644 (file)
@@ -1,3 +1,14 @@
+/* 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:
+ *
+ */
+
 #ifndef __CLIENT_OPTIONS_H__
 #define __CLIENT_OPTIONS_H__
 
index 30fb5f180cca0cf0d1983d665f87d3c6438881f9..130fef0b67919e1c7290ddb0fafff7d7d464023a 100644 (file)
@@ -1,3 +1,14 @@
+/* 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.
@@ -9,7 +20,7 @@
 
 unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of)
 {
-  memcached_return rc;
+  memcached_return_t rc;
   unsigned int x;
   unsigned int pairs_sent;
 
@@ -34,7 +45,7 @@ unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int numbe
 */
 unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int number_of)
 {
-  memcached_return rc;
+  memcached_return_t rc;
   unsigned int x;
   unsigned int retrieved;
 
@@ -66,7 +77,7 @@ unsigned int execute_get(memcached_st *memc, pairs_st *pairs, unsigned int numbe
 /**
  * Callback function to count the number of results
  */
-static memcached_return callback_counter(memcached_st *ptr,
+static memcached_return_t callback_counter(memcached_st *ptr,
                                          memcached_result_st *result,
                                          void *context)
 {
@@ -92,8 +103,8 @@ unsigned int execute_mget(memcached_st *memc,
                           unsigned int number_of)
 {
   unsigned int retrieved= 0;
-  memcached_execute_function callbacks[1]= { [0]= &callback_counter };
-  memcached_return rc;
+  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);
 
index 7a2c5511704b3e237ff0139edc6ad326560875c5..ba54d8d2947294eff86dfb2e79088ad4ee7dbb12 100644 (file)
@@ -1,3 +1,14 @@
+/* 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:
+ *
+ */
+
 #ifndef CLIENTS_EXECUTE_H
 #define CLIENTS_EXECUTE_H
 #include "libmemcached/memcached.h"
index 5bce0301ab6ae848f9315ea5b85c186210c8f30a..2af06010613e62a4ac50a09bca2dd5bf5464bb51 100644 (file)
@@ -1,3 +1,14 @@
+/* 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 "libmemcached/common.h"
 
 #include <stdio.h>
index 4897e943426746967243efd46cb7e3e679a17b89..196e71b2728c3d0cd867f00d059413948d5a9fb0 100644 (file)
@@ -1,3 +1,14 @@
+/* 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:
+ *
+ */
+
 /*
   Code to generate data to be pushed into memcached
 */
diff --git a/clients/include.am b/clients/include.am
new file mode 100644 (file)
index 0000000..cc734ca
--- /dev/null
@@ -0,0 +1,101 @@
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+
+CLIENTS_LDADDS = \
+       $(LIBM) \
+       clients/libutilities.la \
+       libmemcached/libmemcached.la
+
+bin_PROGRAMS+= \
+       clients/memcapable \
+       clients/memcat \
+       clients/memcp \
+       clients/memdump \
+       clients/memerror \
+       clients/memflush \
+       clients/memrm \
+       clients/memstat
+
+if HAVE_LIBEVENT
+  bin_PROGRAMS+= clients/memslap
+endif
+
+noinst_HEADERS+= \
+               clients/client_options.h \
+               clients/execute.h \
+               clients/generator.h \
+               clients/ms_atomic.h \
+               clients/ms_conn.h \
+               clients/ms_memslap.h \
+               clients/ms_setting.h \
+               clients/ms_sigsegv.h \
+               clients/ms_stats.h \
+               clients/ms_task.h \
+               clients/ms_thread.h \
+               clients/utilities.h
+
+noinst_LTLIBRARIES+= clients/libutilities.la
+clients_libutilities_la_SOURCES= clients/utilities.c
+
+noinst_LTLIBRARIES+= clients/libgenexec.la
+clients_libgenexec_la_SOURCES= clients/generator.c clients/execute.c
+
+clients_memcat_SOURCES= clients/memcat.c
+clients_memcat_LDADD= $(CLIENTS_LDADDS)
+
+clients_memcp_SOURCES= clients/memcp.c
+clients_memcp_LDADD= $(CLIENTS_LDADDS)
+
+clients_memdump_SOURCES= clients/memdump.c
+clients_memdump_LDADD= $(CLIENTS_LDADDS)
+
+clients_memstat_SOURCES= clients/memstat.c
+clients_memstat_LDADD= $(CLIENTS_LDADDS)
+
+clients_memrm_SOURCES= clients/memrm.c
+clients_memrm_LDADD= $(CLIENTS_LDADDS)
+
+clients_memflush_SOURCES= clients/memflush.c
+clients_memflush_LDADD= $(CLIENTS_LDADDS)
+
+clients_memerror_SOURCES= clients/memerror.c
+clients_memerror_LDADD= $(CLIENTS_LDADDS)
+
+clients_memslap_SOURCES= \
+               clients/memslap.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_memslap_LDADD= $(LTLIBEVENT) clients/libgenexec.la $(CLIENTS_LDADDS)
+
+clients_memcapable_SOURCES= clients/memcapable.c
+if BUILD_BYTEORDER
+clients_memcapable_LDADD= libmemcached/libbyteorder.la
+endif
+
+test-start-server:
+       clients/memflush --servers=localhost
+       clients/memcp --servers=localhost /etc/services
+       clients/memcat --servers=localhost /etc/services
+       clients/memrm --servers=localhost /etc/services
+       clients/memstat --servers=localhost
+       clients/memslap --servers=localhost
+       clients/memslap --servers=localhost --concurrency=10
+       clients/memslap --servers=localhost --concurrency=10 --initial-load=1000
+       clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10
+       clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=get
+       clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set
+       clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set --non-blocking
+
+client-valgrind:
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10 --initial-load=1000
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=get
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set
+       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  clients/memslap --servers=localhost --concurrency=10 --initial-load=1000 --execute-number=10 --test=set --non-blocking
index f1d7d6a4d7330f8b91e969fe951870b35a98dc38..36be2e55577ad6de9e04df4e51166dbfcf215f6f 100644 (file)
@@ -1,3 +1,14 @@
+/* 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"
@@ -207,7 +218,7 @@ static enum test_return ensure(bool val, const char *expression, const char *fil
   if (!val)
   {
     if (verbose)
-      fprintf(stderr, "\n%s:%u: %s", file, line, expression);
+      fprintf(stderr, "\n%s:%d: %s", file, line, expression);
 
     if (do_core)
       abort();
index 944afe721467a009da8ed1ce4343323f5c7e7641..f5f7f8f911d28b2bd5cf4dfeca5c4690e34af021 100644 (file)
@@ -1,3 +1,14 @@
+/* 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 "libmemcached/common.h"
 #include <stdio.h>
 #include <inttypes.h>
@@ -27,9 +38,11 @@ int main(int argc, char *argv[])
   char *string;
   size_t string_length;
   uint32_t flags;
-  memcached_return rc;
+  memcached_return_t rc;
   memcached_server_st *servers;
 
+  int return_code= 0;
+
   options_parse(argc, argv);
 
   if (!opt_servers)
@@ -83,6 +96,14 @@ int main(int argc, char *argv[])
       if (memc->cached_errno)
        fprintf(stderr, " system error %s", strerror(memc->cached_errno));
       fprintf(stderr, "\n");
+
+      return_code= -1;
+      break;
+    }
+    else // Unknown Issue
+    {
+      fprintf(stderr, "memcat: %s not found\n", argv[optind]);
+      return_code= -1;
     }
     optind++;
   }
@@ -94,7 +115,7 @@ int main(int argc, char *argv[])
   if (opt_hash)
     free(opt_hash);
 
-  return 0;
+  return return_code;
 }
 
 
index dcc142da8456d99a14a4a78f3002296a1c673bae..dd8aba9ac907e9001d6e823374e7cf498520af8f 100644 (file)
@@ -1,3 +1,14 @@
+/* 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 "libmemcached/common.h"
 #include <stdio.h>
 #include <stdlib.h>
@@ -21,7 +32,7 @@
 #define PROGRAM_DESCRIPTION "Copy a set of files to a memcached cluster."
 
 /* Prototypes */
-void options_parse(int argc, char *argv[]);
+static void options_parse(int argc, char *argv[]);
 
 static int opt_binary=0;
 static int opt_verbose= 0;
@@ -31,12 +42,41 @@ static int opt_method= OPT_SET;
 static uint32_t opt_flags= 0;
 static time_t opt_expires= 0;
 
+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 0;
+  }
+
+  if (endptr == nptr)
+  {
+    *error= true;
+    return 0;
+  }
+
+  *error= false;
+  return val;
+}
+
 int main(int argc, char *argv[])
 {
   memcached_st *memc;
-  memcached_return rc;
+  memcached_return_t rc;
   memcached_server_st *servers;
 
+  int return_code= 0;
+
   options_parse(argc, argv);
 
   memc= memcached_create(NULL);
@@ -47,7 +87,9 @@ int main(int argc, char *argv[])
     char *temp;
 
     if ((temp= getenv("MEMCACHED_SERVERS")))
+    {
       opt_servers= strdup(temp);
+    }
     else
     {
       fprintf(stderr, "No Servers provided\n");
@@ -65,7 +107,7 @@ int main(int argc, char *argv[])
   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
                          (uint64_t)opt_binary);
 
-  while (optind < argc) 
+  while (optind < argc)
   {
     struct stat sbuf;
     int fd;
@@ -89,7 +131,7 @@ int main(int argc, char *argv[])
     else
       ptr= argv[optind];
 
-    if (opt_verbose) 
+    if (opt_verbose)
     {
       static const char *opstr[] = { "set", "add", "replace" };
       printf("op: %s\nsource file: %s\nlength: %zu\n"
@@ -100,13 +142,13 @@ int main(int argc, char *argv[])
 
     if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL)
     {
-      fprintf(stderr, "malloc: %s\n", strerror(errno)); 
+      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)); 
+      fprintf(stderr, "read: %s\n", strerror(errno));
       exit(1);
     }
 
@@ -131,11 +173,13 @@ int main(int argc, char *argv[])
 
     if (rc != MEMCACHED_SUCCESS)
     {
-      fprintf(stderr, "memcp: %s: memcache error %s", 
+      fprintf(stderr, "memcp: %s: memcache error %s",
              ptr, memcached_strerror(memc, rc));
       if (memc->cached_errno)
        fprintf(stderr, " system error %s", strerror(memc->cached_errno));
       fprintf(stderr, "\n");
+
+      return_code= -1;
     }
 
     free(file_buffer_ptr);
@@ -150,10 +194,10 @@ int main(int argc, char *argv[])
   if (opt_hash)
     free(opt_hash);
 
-  return 0;
+  return return_code;
 }
 
-void options_parse(int argc, char *argv[])
+static void options_parse(int argc, char *argv[])
 {
   int option_index= 0;
   int option_rv;
@@ -180,7 +224,7 @@ void options_parse(int argc, char *argv[])
       {0, 0, 0, 0},
     };
 
-  while (1) 
+  while (1)
   {
     option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
 
@@ -209,11 +253,26 @@ void options_parse(int argc, char *argv[])
       opt_servers= strdup(optarg);
       break;
     case OPT_FLAG: /* --flag */
-      opt_flags= (uint32_t)strtol(optarg, (char **)NULL, 16);
-      break;
+      {
+        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 */
-      opt_expires= (time_t)strtoll(optarg, (char **)NULL, 10);
-      break;
+      {
+        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;
index 1a21ab64e9be365b34c599f416bf0db58d92896c..4329c1bdd099db1b7a53ccba9653d10dd633142f 100644 (file)
@@ -1,3 +1,14 @@
+/* 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 "libmemcached/common.h"
 #include <stdio.h>
 #include <stdlib.h>
@@ -21,7 +32,7 @@
 #define PROGRAM_DESCRIPTION "Dump all values from one or many servers."
 
 /* Prototypes */
-void options_parse(int argc, char *argv[]);
+static void options_parse(int argc, char *argv[]);
 
 static int opt_binary=0;
 static int opt_verbose= 0;
@@ -29,9 +40,9 @@ static char *opt_servers= NULL;
 static char *opt_hash= NULL;
 
 /* Print the keys and counter how many were found */
-static memcached_return key_printer(memcached_st *ptr __attribute__((unused)),  
-                                              const char *key, size_t key_length, 
-                                              void *context __attribute__((unused)))
+static memcached_return_t key_printer(memcached_st *ptr __attribute__((unused)),
+                                      const char *key, size_t key_length,
+                                      void *context __attribute__((unused)))
 {
   printf("%.*s\n", (uint32_t)key_length, key);
 
@@ -41,9 +52,9 @@ static memcached_return key_printer(memcached_st *ptr __attribute__((unused)),
 int main(int argc, char *argv[])
 {
   memcached_st *memc;
-  memcached_return rc;
+  memcached_return_t rc;
   memcached_server_st *servers;
-  memcached_dump_func callbacks[1];
+  memcached_dump_fn callbacks[1];
 
   callbacks[0]= &key_printer;
 
@@ -95,7 +106,7 @@ int main(int argc, char *argv[])
   return 0;
 }
 
-void options_parse(int argc, char *argv[])
+static void options_parse(int argc, char *argv[])
 {
   int option_index= 0;
   int option_rv;
@@ -112,7 +123,7 @@ void options_parse(int argc, char *argv[])
       {0, 0, 0, 0}
     };
 
-  while (1) 
+  while (1)
   {
     option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
 
index fbad55ba2f00245d2182bcbda522ee20c3428647..286ef0e142b6630193b6a96b88032268d8bc6ea9 100644 (file)
@@ -1,3 +1,14 @@
+/* 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 "libmemcached/common.h"
 #include <stdio.h>
 #include <inttypes.h>
@@ -20,12 +31,23 @@ static int opt_verbose= 0;
 
 int main(int argc, char *argv[])
 {
+  unsigned long value;
   options_parse(argc, argv);
 
   if (argc != 2)
     return 1;
 
-  printf("%s\n", memcached_strerror(NULL, atoi(argv[1])));
+  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 1;
+  }
 
   return 0;
 }
index 12034adba47e249619b65775b8d66d8ecf375150..885aa6c85089708dcabd6058c58ee20f90e1c9da 100644 (file)
@@ -1,3 +1,14 @@
+/* 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 "libmemcached/common.h"
 #include <stdio.h>
 #include <unistd.h>
@@ -21,7 +32,7 @@ void options_parse(int argc, char *argv[]);
 int main(int argc, char *argv[])
 {
   memcached_st *memc;
-  memcached_return rc;
+  memcached_return_t rc;
   memcached_server_st *servers;
 
   options_parse(argc, argv);
index 203146efae04ca2df288901ec19473429c9c6a9d..81c5f852bd21a992e718b86acb44e7c6203694c6 100644 (file)
@@ -1,3 +1,14 @@
+/* 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 "libmemcached/common.h"
 #include <stdio.h>
 #include <unistd.h>
@@ -17,14 +28,16 @@ static char *opt_hash= NULL;
 #define PROGRAM_DESCRIPTION "Erase a key or set of keys from a memcached cluster."
 
 /* Prototypes */
-void options_parse(int argc, char *argv[]);
+static void options_parse(int argc, char *argv[]);
 
 int main(int argc, char *argv[])
 {
   memcached_st *memc;
-  memcached_return rc;
+  memcached_return_t rc;
   memcached_server_st *servers;
 
+  int return_code= 0;
+
   options_parse(argc, argv);
 
   if (!opt_servers)
@@ -48,20 +61,22 @@ int main(int argc, char *argv[])
   memcached_server_list_free(servers);
   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
                          (uint64_t) opt_binary);
-  
-  while (optind < argc) 
+  while (optind < argc)
   {
-    if (opt_verbose) 
+    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) 
+    if (rc != MEMCACHED_SUCCESS)
     {
-      fprintf(stderr, "memrm: %s: memcache error %s", 
+      fprintf(stderr, "memrm: %s: memcache error %s",
              argv[optind], memcached_strerror(memc, rc));
       if (memc->cached_errno)
        fprintf(stderr, " system error %s", strerror(memc->cached_errno));
       fprintf(stderr, "\n");
+
+      return_code= -1;
     }
 
     optind++;
@@ -74,11 +89,11 @@ int main(int argc, char *argv[])
   if (opt_hash)
     free(opt_hash);
 
-  return 0;
+  return return_code;
 }
 
 
-void options_parse(int argc, char *argv[])
+static void options_parse(int argc, char *argv[])
 {
   memcached_programs_help_st help_options[]=
   {
@@ -100,7 +115,7 @@ void options_parse(int argc, char *argv[])
   int option_index= 0;
   int option_rv;
 
-  while (1) 
+  while (1)
   {
     option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
     if (option_rv == -1) break;
index aff2de1ba6b95bec7e0a8cafdada969e935e28a3..4b342e76f462f70303037c32a16fa4e8a76437c7 100644 (file)
-#include "libmemcached/common.h"
-#include <stdio.h>
+/*
+ *  memslap
+ *
+ *  (c) Copyright 2009, Schooner Information Technology, Inc.
+ *  All rights reserved.
+ *  http://www.schoonerinfotech.com/
+ *
+ *  Use and distribution licensed under the BSD license.  See
+ *  the COPYING file for full text.
+ *
+ *  Authors:
+ *      Brian Aker
+ *      Mingqiang Zhuang <mingqiangzhuang@hengtiansoft.com>
+ *
+ */
+#include "config.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;
-};
+#include <limits.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+
+#include "ms_sigsegv.h"
+#include "ms_setting.h"
+#include "ms_thread.h"
+
+#define PROGRAM_NAME    "memslap"
+#define PROGRAM_DESCRIPTION \
+                        "Generates workload against memcached servers."
+
+#ifdef __sun
+  /* For some odd reason the option struct on solaris defines the argument
+   * as char* and not const char*
+   */
+#define OPTIONSTRING char*
+#else
+#define OPTIONSTRING const char*
+#endif
 
-struct conclusions_st {
-  long int load_time;
-  long int read_time;
-  unsigned int rows_loaded;
-  unsigned int rows_read;
+/* options */
+static struct option long_options[]=
+{
+  { (OPTIONSTRING)"servers",        required_argument,            NULL,
+    OPT_SERVERS            },
+  { (OPTIONSTRING)"threads",        required_argument,            NULL,
+    OPT_THREAD_NUMBER      },
+  { (OPTIONSTRING)"concurrency",    required_argument,            NULL,
+    OPT_CONCURRENCY        },
+  { (OPTIONSTRING)"conn_sock",      required_argument,            NULL,
+    OPT_SOCK_PER_CONN      },
+  { (OPTIONSTRING)"execute_number", required_argument,            NULL,
+    OPT_EXECUTE_NUMBER     },
+  { (OPTIONSTRING)"time",           required_argument,            NULL,
+    OPT_TIME               },
+  { (OPTIONSTRING)"cfg_cmd",        required_argument,            NULL,
+    OPT_CONFIG_CMD         },
+  { (OPTIONSTRING)"win_size",       required_argument,            NULL,
+    OPT_WINDOW_SIZE        },
+  { (OPTIONSTRING)"fixed_size",     required_argument,            NULL,
+    OPT_FIXED_LTH          },
+  { (OPTIONSTRING)"verify",         required_argument,            NULL,
+    OPT_VERIFY             },
+  { (OPTIONSTRING)"division",       required_argument,            NULL,
+    OPT_GETS_DIVISION      },
+  { (OPTIONSTRING)"stat_freq",      required_argument,            NULL,
+    OPT_STAT_FREQ          },
+  { (OPTIONSTRING)"exp_verify",     required_argument,            NULL,
+    OPT_EXPIRE             },
+  { (OPTIONSTRING)"overwrite",      required_argument,            NULL,
+    OPT_OVERWRITE          },
+  { (OPTIONSTRING)"reconnect",      no_argument,                  NULL,
+    OPT_RECONNECT          },
+  { (OPTIONSTRING)"udp",            no_argument,                  NULL,
+    OPT_UDP                },
+  { (OPTIONSTRING)"facebook",       no_argument,                  NULL,
+    OPT_FACEBOOK_TEST      },
+  { (OPTIONSTRING)"binary",         no_argument,                  NULL,
+    OPT_BINARY_PROTOCOL    },
+  { (OPTIONSTRING)"tps",            required_argument,            NULL,
+    OPT_TPS                },
+  { (OPTIONSTRING)"rep_write",      required_argument,            NULL,
+    OPT_REP_WRITE_SRV      },
+  { (OPTIONSTRING)"verbose",        no_argument,                  NULL,
+    OPT_VERBOSE            },
+  { (OPTIONSTRING)"help",           no_argument,                  NULL,
+    OPT_HELP               },
+  { (OPTIONSTRING)"version",        no_argument,                  NULL,
+    OPT_VERSION            },
+  { 0, 0, 0, 0 },
 };
 
 /* 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;
+static void ms_sync_lock_init(void);
+static void ms_sync_lock_destroy(void);
+static void ms_global_struct_init(void);
+static void ms_global_struct_destroy(void);
+static void ms_version_command(const char *command_name);
+static const char *ms_lookup_help(ms_options_t option);
+static int64_t ms_parse_time(void);
+static int64_t ms_parse_size(void);
+static void ms_options_parse(int argc, char *argv[]);
+static int ms_check_para(void);
+static void ms_statistic_init(void);
+static void ms_stats_init(void);
+static void ms_print_statistics(int time);
+static void ms_print_memslap_stats(struct timeval *start_time,
+                                   struct timeval *end_time);
+static void ms_monitor_slap_mode(void);
+void ms_help_command(const char *command_name, const char *description);
+
+
+/* initialize the global locks */
+static void ms_sync_lock_init()
+{
+  ms_global.init_lock.count= 0;
+  pthread_mutex_init(&ms_global.init_lock.lock, NULL);
+  pthread_cond_init(&ms_global.init_lock.cond, NULL);
 
-int main(int argc, char *argv[])
+  ms_global.run_lock.count= 0;
+  pthread_mutex_init(&ms_global.run_lock.lock, NULL);
+  pthread_cond_init(&ms_global.run_lock.cond, NULL);
+
+  pthread_mutex_init(&ms_global.quit_mutex, NULL);
+  pthread_mutex_init(&ms_global.seq_mutex, NULL);
+} /* ms_sync_lock_init */
+
+
+/* destroy the global locks */
+static void ms_sync_lock_destroy()
 {
-  conclusions_st conclusion;
-  memcached_server_st *servers;
+  pthread_mutex_destroy(&ms_global.init_lock.lock);
+  pthread_cond_destroy(&ms_global.init_lock.cond);
 
-  memset(&conclusion, 0, sizeof(conclusions_st));
+  pthread_mutex_destroy(&ms_global.run_lock.lock);
+  pthread_cond_destroy(&ms_global.run_lock.cond);
 
-  srandom((unsigned int)time(NULL));
-  options_parse(argc, argv);
+  pthread_mutex_destroy(&ms_global.quit_mutex);
+  pthread_mutex_destroy(&ms_global.seq_mutex);
 
-  if (!opt_servers)
+  if (ms_setting.stat_freq > 0)
   {
-    char *temp;
-
-    if ((temp= getenv("MEMCACHED_SERVERS")))
-      opt_servers= strdup(temp);
-    else
-    {
-      fprintf(stderr, "No Servers provided\n");
-      exit(1);
-    }
+    pthread_mutex_destroy(&ms_statistic.stat_mutex);
   }
+} /* ms_sync_lock_destroy */
 
-  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);
+/* initialize the global structure */
+static void ms_global_struct_init()
+{
+  ms_sync_lock_init();
+  ms_global.finish_warmup= false;
+  ms_global.time_out= false;
+}
 
-  scheduler(servers, &conclusion);
 
-  free(opt_servers);
+/* destroy the global structure */
+static void ms_global_struct_destroy()
+{
+  ms_sync_lock_destroy();
+}
 
-  (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;
+/**
+ * output the version information
+ *
+ * @param command_name, the string of this process
+ */
+static void ms_version_command(const char *command_name)
+{
+  printf("%s v%u.%u\n", command_name, 1U, 0U);
+  exit(0);
 }
 
-void scheduler(memcached_server_st *servers, conclusions_st *conclusion)
+
+/**
+ * get the description of the option
+ *
+ * @param option, option of command line
+ *
+ * @return char*, description of the command option
+ */
+static const char *ms_lookup_help(ms_options_t option)
 {
-  unsigned int x;
-  unsigned int actual_loaded= 0; /* Fix warning */
-  memcached_st *memc;
+  switch (option)
+  {
+  case OPT_SERVERS:
+    return
+      "List one or more servers to connect. Servers count must be less than\n"
+      "        threads count. e.g.: --servers=localhost:1234,localhost:11211";
 
-  struct timeval start_time, end_time;
-  pthread_t mainthread;            /* Thread descriptor */
-  pthread_attr_t attr;          /* Thread attributes */
-  pairs_st *pairs= NULL;
+  case OPT_VERSION:
+    return "Display the version of the application and then exit.";
 
-  pthread_attr_init(&attr);
-  pthread_attr_setdetachstate(&attr,
-                              PTHREAD_CREATE_DETACHED);
+  case OPT_HELP:
+    return "Display this message and then exit.";
 
-  memc= memcached_create(NULL);
+  case OPT_EXECUTE_NUMBER:
+    return "Number of operations(get and set) to execute for the\n"
+           "        given test. Default 1000000.";
 
-  /* 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(x= 0; x < servers[0].count; x++ )
-      servers[x].type= MEMCACHED_CONNECTION_UDP;
-  }
-  memcached_server_push(memc, servers);
+  case OPT_THREAD_NUMBER:
+    return
+      "Number of threads to startup, better equal to CPU numbers. Default 8.";
+
+  case OPT_CONCURRENCY:
+    return "Number of concurrency to simulate with load. Default 128.";
+
+  case OPT_FIXED_LTH:
+    return "Fixed length of value.";
+
+  case OPT_VERIFY:
+    return "The proportion of date verification, e.g.: --verify=0.01";
+
+  case OPT_GETS_DIVISION:
+    return "Number of keys to multi-get once. Default 1, means single get.";
+
+  case OPT_TIME:
+    return
+      "How long the test to run, suffix: s-seconds, m-minutes, h-hours,\n"
+      "        d-days e.g.: --time=2h.";
+
+  case OPT_CONFIG_CMD:
+    return
+      "Load the configure file to get command,key and value distribution list.";
+
+  case OPT_WINDOW_SIZE:
+    return
+      "Task window size of each concurrency, suffix: K, M e.g.: --win_size=10k.\n"
+      "        Default 10k.";
+
+  case OPT_UDP:
+    return
+      "UDP support, default memslap uses TCP, TCP port and UDP port of\n"
+      "        server must be same.";
+
+  case OPT_EXPIRE:
+    return
+      "The proportion of objects with expire time, e.g.: --exp_verify=0.01.\n"
+      "        Default no object with expire time";
+
+  case OPT_OVERWRITE:
+    return
+      "The proportion of objects need overwrite, e.g.: --overwrite=0.01.\n"
+      "        Default never overwrite object.";
+
+  case OPT_STAT_FREQ:
+    return
+      "Frequency of dumping statistic information. suffix: s-seconds,\n"
+      "        m-minutes, e.g.: --resp_freq=10s.";
+
+  case OPT_SOCK_PER_CONN:
+    return "Number of TCP socks per concurrency. Default 1.";
 
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
-                         (uint64_t)opt_binary);
+  case OPT_RECONNECT:
+    return
+      "Reconnect support, when connection is closed it will be reconnected.";
 
-  if (opt_flush)
-    flush_all(memc);
-  if (opt_createial_load)
-    pairs= load_create_data(memc, opt_createial_load, &actual_loaded);
+  case OPT_VERBOSE:
+    return
+      "Whether it outputs detailed information when verification fails.";
 
-  char **keys= calloc(actual_loaded, sizeof(char*));
-  size_t *key_lengths= calloc(actual_loaded, sizeof(size_t));
+  case OPT_FACEBOOK_TEST:
+    return
+      "Whether it enables facebook test feature, set with TCP and multi-get with UDP.";
 
-  if (keys == NULL || key_lengths == NULL)
+  case OPT_BINARY_PROTOCOL:
+    return
+      "Whether it enables binary protocol. Default with ASCII protocol.";
+
+  case OPT_TPS:
+    return "Expected throughput, suffix: K, e.g.: --tps=10k.";
+
+  case OPT_REP_WRITE_SRV:
+    return "The first nth servers can write data, e.g.: --rep_write=2.";
+
+  default:
+    return "Forgot to document this option :)";
+  } /* switch */
+} /* ms_lookup_help */
+
+
+/**
+ * output the help information
+ *
+ * @param command_name, the string of this process
+ * @param description, description of this process
+ * @param long_options, global options array
+ */
+void ms_help_command(const char *command_name, const char *description)
+{
+  char *help_message= NULL;
+
+  printf("%s v%u.%u\n", command_name, 1U, 0U);
+  printf("    %s\n\n", description);
+  printf(
+    "Usage:\n"
+    "    memslap -hV | -s servers [-F config_file] [-t time | -x exe_num] [...]\n\n"
+    "Options:\n");
+
+  for (int x= 0; long_options[x].name; x++)
   {
-    free(keys);
-    free(key_lengths);
-    keys= NULL;
-    key_lengths= NULL;
-  } else {
-    for (x= 0; x < actual_loaded; ++x)
+    printf("    -%c, --%s%c\n", long_options[x].val, long_options[x].name,
+           long_options[x].has_arg ? '=' : ' ');
+
+    if ((help_message= (char *)ms_lookup_help(long_options[x].val)) != NULL)
     {
-      keys[x]= pairs[x].key;
-      key_lengths[x]= pairs[x].key_length;
+      printf("        %s\n", help_message);
     }
   }
 
-  /* 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);
-  }
+  printf(
+    "\nExamples:\n"
+    "    memslap -s 127.0.0.1:11211 -S 5s\n"
+    "    memslap -s 127.0.0.1:11211 -t 2m -v 0.2 -e 0.05 -b\n"
+    "    memslap -s 127.0.0.1:11211 -F config -t 2m -w 40k -S 20s -o 0.2\n"
+    "    memslap -s 127.0.0.1:11211 -F config -t 2m -T 4 -c 128 -d 20 -P 40k\n"
+    "    memslap -s 127.0.0.1:11211 -F config -t 2m -d 50 -a -n 40\n"
+    "    memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m\n"
+    "    memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m -p 2\n\n");
 
-  pthread_mutex_lock(&counter_mutex);
-  thread_counter= 0;
+  exit(0);
+} /* ms_help_command */
 
-  pthread_mutex_lock(&sleeper_mutex);
-  master_wakeup= 1;
-  pthread_mutex_unlock(&sleeper_mutex);
 
-  for (x= 0; x < opt_concurrency; x++)
+/* used to parse the time string  */
+static int64_t ms_parse_time()
+{
+  int64_t ret= 0;
+  char unit= optarg[strlen(optarg) - 1];
+
+  optarg[strlen(optarg) - 1]= '\0';
+  ret= atoi(optarg);
+
+  switch (unit)
   {
-    thread_context_st *context;
-    context= (thread_context_st *)calloc(1, sizeof(thread_context_st));
+  case 'd':
+  case 'D':
+    ret*= 24;
 
-    context->memc= memcached_clone(NULL, memc);
-    context->test= opt_test;
+  case 'h':
+  case 'H':
+    ret*= 60;
 
-    context->initial_pairs= pairs;
-    context->initial_number= actual_loaded;
-    context->keys= keys;
-    context->key_lengths= key_lengths;
+  case 'm':
+  case 'M':
+    ret*= 60;
 
-    if (opt_test == SET_TEST)
-    {
-      context->execute_pairs= pairs_generate(opt_execute_number, 400);
-      context->execute_number= opt_execute_number;
-    }
+  case 's':
+  case 'S':
+    break;
 
-    /* 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++;
-  }
+  default:
+    ret= -1;
+    break;
+  } /* switch */
 
-  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);
-}
+  return ret;
+} /* ms_parse_time */
 
-void options_parse(int argc, char *argv[])
+
+/* used to parse the size string */
+static int64_t ms_parse_size()
 {
-  memcached_programs_help_st help_options[]=
+  int64_t ret= -1;
+  char unit= optarg[strlen(optarg) - 1];
+
+  optarg[strlen(optarg) - 1]= '\0';
+  ret= strtoll(optarg, (char **)NULL, 10);
+
+  switch (unit)
   {
-    {0},
-  };
+  case 'k':
+  case 'K':
+    ret*= 1024;
+    break;
 
-  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},
-    };
+  case 'm':
+  case 'M':
+    ret*= 1024 * 1024;
+    break;
+
+  case 'g':
+  case 'G':
+    ret*= 1024 * 1024 * 1024;
+    break;
+
+  default:
+    ret= -1;
+    break;
+  } /* switch */
 
+  return ret;
+} /* ms_parse_size */
+
+
+/* used to parse the options of command line */
+static void ms_options_parse(int argc, char *argv[])
+{
   int option_index= 0;
   int option_rv;
 
-  while (1)
+  while ((option_rv= getopt_long(argc, argv, "VhURbaBs:x:T:c:X:v:d:"
+                                             "t:S:F:w:e:o:n:P:p:",
+                                 long_options, &option_index)) != -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)
+
+    case OPT_VERSION:     /* --version or -V */
+      ms_version_command(PROGRAM_NAME);
+      break;
+
+    case OPT_HELP:     /* --help or -h */
+      ms_help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION);
+      break;
+
+    case OPT_SERVERS:     /* --servers or -s */
+      ms_setting.srv_str= strdup(optarg);
+      break;
+
+    case OPT_CONCURRENCY:       /* --concurrency or -c */
+      ms_setting.nconns= (uint32_t)strtoul(optarg, (char **) NULL, 10);
+      if (ms_setting.nconns <= 0)
       {
-        fprintf(stderr, "You can not run a get test in UDP mode. UDP mode "
-                  "does not currently support get ops.\n");
+        fprintf(stderr, "Concurrency must be greater than 0.:-)\n");
         exit(1);
       }
-      opt_udp_io= 1;
       break;
-    case OPT_BINARY:
-      opt_binary = 1;
+
+    case OPT_EXECUTE_NUMBER:        /* --execute_number or -x */
+      ms_setting.exec_num= (int)strtol(optarg, (char **) NULL, 10);
+      if (ms_setting.exec_num <= 0)
+      {
+        fprintf(stderr, "Execute number must be greater than 0.:-)\n");
+        exit(1);
+      }
       break;
-    case OPT_VERBOSE: /* --verbose or -v */
-      opt_verbose = OPT_VERBOSE;
+
+    case OPT_THREAD_NUMBER:     /* --threads or -T */
+      ms_setting.nthreads= (int)strtol(optarg, (char **) NULL, 10);
+      if (ms_setting.nthreads <= 0)
+      {
+        fprintf(stderr, "Threads number must be greater than 0.:-)\n");
+        exit(1);
+      }
       break;
-    case OPT_DEBUG: /* --debug or -d */
-      opt_verbose = OPT_DEBUG;
+
+    case OPT_FIXED_LTH:         /* --fixed_size or -X */
+      ms_setting.fixed_value_size= (size_t)strtoull(optarg, (char **) NULL, 10);
+      if ((ms_setting.fixed_value_size <= 0)
+          || (ms_setting.fixed_value_size > MAX_VALUE_SIZE))
+      {
+        fprintf(stderr, "Value size must be between 0 and 1M.:-)\n");
+        exit(1);
+      }
       break;
-    case OPT_VERSION: /* --version or -V */
-      version_command(PROGRAM_NAME);
+
+    case OPT_VERIFY:        /* --verify or -v */
+      ms_setting.verify_percent= atof(optarg);
+      if ((ms_setting.verify_percent <= 0)
+          || (ms_setting.verify_percent > 1.0))
+      {
+        fprintf(stderr, "Data verification rate must be "
+                        "greater than 0 and less than 1.0. :-)\n");
+        exit(1);
+      }
       break;
-    case OPT_HELP: /* --help or -h */
-      help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
+
+    case OPT_GETS_DIVISION:         /* --division or -d */
+      ms_setting.mult_key_num= (int)strtol(optarg, (char **) NULL, 10);
+      if (ms_setting.mult_key_num <= 0)
+      {
+        fprintf(stderr, "Multi-get key number must be greater than 0.:-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_TIME:      /* --time or -t */
+      ms_setting.run_time= (int)ms_parse_time();
+      if (ms_setting.run_time == -1)
+      {
+        fprintf(stderr, "Please specify the run time. :-)\n"
+                        "'s' for second, 'm' for minute, 'h' for hour, "
+                        "'d' for day. e.g.: --time=24h (means 24 hours).\n");
+        exit(1);
+      }
+
+      if (ms_setting.run_time == 0)
+      {
+        fprintf(stderr, "Running time can not be 0. :-)\n");
+        exit(1);
+      }
       break;
-    case OPT_SERVERS: /* --servers or -s */
-      opt_servers= strdup(optarg);
+
+    case OPT_CONFIG_CMD:        /* --cfg_cmd or -F */
+      ms_setting.cfg_file= strdup(optarg);
       break;
-    case OPT_SLAP_TEST:
-      if (!strcmp(optarg, "get"))
+
+    case OPT_WINDOW_SIZE:       /* --win_size or -w */
+      ms_setting.win_size= (size_t)ms_parse_size();
+      if (ms_setting.win_size == (size_t)-1)
+      {
+        fprintf(
+          stderr,
+          "Please specify the item window size. :-)\n"
+          "e.g.: --win_size=10k (means 10k task window size).\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_UDP:       /* --udp or -U*/
+      ms_setting.udp= true;
+      break;
+
+    case OPT_EXPIRE:        /* --exp_verify or -e */
+      ms_setting.exp_ver_per= atof(optarg);
+      if ((ms_setting.exp_ver_per <= 0) || (ms_setting.exp_ver_per > 1.0))
+      {
+        fprintf(stderr, "Expire time verification rate must be "
+                        "greater than 0 and less than 1.0. :-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_OVERWRITE:         /* --overwrite or -o */
+      ms_setting.overwrite_percent= atof(optarg);
+      if ((ms_setting.overwrite_percent <= 0)
+          || (ms_setting.overwrite_percent > 1.0))
+      {
+        fprintf(stderr, "Objects overwrite rate must be "
+                        "greater than 0 and less than 1.0. :-)\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_STAT_FREQ:         /* --stat_freq or -S */
+      ms_setting.stat_freq= (int)ms_parse_time();
+      if (ms_setting.stat_freq == -1)
       {
-        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 ;
+        fprintf(stderr, "Please specify the frequency of dumping "
+                        "statistic information. :-)\n"
+                        "'s' for second, 'm' for minute, 'h' for hour, "
+                        "'d' for day. e.g.: --time=24h (means 24 hours).\n");
+        exit(1);
       }
-      else if (!strcmp(optarg, "set"))
-        opt_test= SET_TEST;
-      else if (!strcmp(optarg, "mget"))
+
+      if (ms_setting.stat_freq == 0)
       {
-        opt_test= MGET_TEST;
+        fprintf(stderr, "The frequency of dumping statistic information "
+                        "can not be 0. :-)\n");
+        exit(1);
       }
-      else
+      break;
+
+    case OPT_SOCK_PER_CONN:         /* --conn_sock or -n */
+      ms_setting.sock_per_conn= (int)strtol(optarg, (char **) NULL, 10);
+      if (ms_setting.sock_per_conn <= 0)
       {
-        fprintf(stderr, "Your test, %s, is not a known test\n", optarg);
+        fprintf(stderr, "Number of socks of each concurrency "
+                        "must be greater than 0.:-)\n");
         exit(1);
       }
       break;
-    case OPT_SLAP_CONCURRENCY:
-      opt_concurrency= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+
+    case OPT_RECONNECT:     /* --reconnect or -R */
+      ms_setting.reconnect= true;
       break;
-    case OPT_SLAP_EXECUTE_NUMBER:
-      opt_execute_number= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+
+    case OPT_VERBOSE:       /* --verbose or -b */
+      ms_setting.verbose= true;
       break;
-    case OPT_SLAP_INITIAL_LOAD:
-      opt_createial_load= (unsigned int)strtoul(optarg, (char **)NULL, 10);
+
+    case OPT_FACEBOOK_TEST:         /* --facebook or -a */
+      ms_setting.facebook_test= true;
       break;
+
+    case OPT_BINARY_PROTOCOL:       /* --binary or -B */
+      ms_setting.binary_prot= true;
+      break;
+
+    case OPT_TPS:       /* --tps or -P */
+      ms_setting.expected_tps= (int)ms_parse_size();
+      if (ms_setting.expected_tps == -1)
+      {
+        fprintf(stderr,
+                "Please specify the item expected throughput. :-)\n"
+                "e.g.: --tps=10k (means 10k throughput).\n");
+        exit(1);
+      }
+      break;
+
+    case OPT_REP_WRITE_SRV:         /* --rep_write or -p */
+      ms_setting.rep_write_srv= (int)strtol(optarg, (char **) NULL, 10);
+      if (ms_setting.rep_write_srv <= 0)
+      {
+        fprintf(stderr,
+                "Number of replication writing server must be greater "
+                "than 0.:-)\n");
+        exit(1);
+      }
+      break;
+
     case '?':
       /* getopt_long already printed an error message. */
       exit(1);
+
     default:
       abort();
+    } /* switch */
+  }
+} /* ms_options_parse */
+
+
+static int ms_check_para()
+{
+  if (ms_setting.srv_str == NULL)
+  {
+    char *temp;
+
+    if ((temp= getenv("MEMCACHED_SERVERS")))
+    {
+      ms_setting.srv_str= strdup(temp);
+    }
+    else
+    {
+      fprintf(stderr, "No Servers provided\n\n");
+      return -1;
     }
   }
 
-  if ((opt_test == GET_TEST || opt_test == MGET_TEST) && opt_createial_load == 0)
-    opt_createial_load= DEFAULT_INITIAL_LOAD;
+  if (ms_setting.nconns % (uint32_t)ms_setting.nthreads != 0)
+  {
+    fprintf(stderr, "Concurrency must be the multiples of threads count.\n");
+    return -1;
+  }
 
-  if (opt_execute_number == 0)
-    opt_execute_number= DEFAULT_EXECUTE_NUMBER;
+  if (ms_setting.win_size % UNIT_ITEMS_COUNT != 0)
+  {
+    fprintf(stderr, "Window size must be the multiples of 1024.\n\n");
+    return -1;
+  }
+
+  return 0;
+} /* ms_check_para */
 
-  if (opt_concurrency == 0)
-    opt_concurrency= DEFAULT_CONCURRENCY;
-}
 
-void conclusions_print(conclusions_st *conclusion)
+/* initialize the statistic structure */
+static void ms_statistic_init()
 {
-  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);
-}
+  pthread_mutex_init(&ms_statistic.stat_mutex, NULL);
+  ms_init_stats(&ms_statistic.get_stat, "Get");
+  ms_init_stats(&ms_statistic.set_stat, "Set");
+  ms_init_stats(&ms_statistic.total_stat, "Total");
+} /* ms_statistic_init */
+
 
-void *run_task(void *p)
+/* initialize the global state structure */
+static void ms_stats_init()
 {
-  thread_context_st *context= (thread_context_st *)p;
-  memcached_st *memc;
+  memset(&ms_stats, 0, sizeof(ms_stats_t));
+  if (ms_setting.stat_freq > 0)
+  {
+    ms_statistic_init();
+  }
+} /* ms_stats_init */
 
-  memc= context->memc;
 
-  pthread_mutex_lock(&sleeper_mutex);
-  while (master_wakeup)
+/* use to output the statistic */
+static void ms_print_statistics(int in_time)
+{
+  int obj_size= (int)(ms_setting.avg_key_size + ms_setting.avg_val_size);
+
+  printf("\033[1;1H\033[2J\n");
+  ms_dump_format_stats(&ms_statistic.get_stat, in_time,
+                       ms_setting.stat_freq, obj_size);
+  ms_dump_format_stats(&ms_statistic.set_stat, in_time,
+                       ms_setting.stat_freq, obj_size);
+  ms_dump_format_stats(&ms_statistic.total_stat, in_time,
+                       ms_setting.stat_freq, obj_size);
+} /* ms_print_statistics */
+
+
+/* used to print the states of memslap */
+static void ms_print_memslap_stats(struct timeval *start_time,
+                                   struct timeval *end_time)
+{
+  char buf[1024];
+  char *pos= buf;
+
+  pos+= sprintf(pos, "cmd_get: %zu\n",
+                ms_stats.cmd_get);
+  pos+= sprintf(pos, "cmd_set: %zu\n",
+                ms_stats.cmd_set);
+  pos+= sprintf(pos, "get_misses: %zu\n",
+                ms_stats.get_misses);
+
+  if (ms_setting.verify_percent > 0)
   {
-    pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
+    pos+= sprintf(pos, "verify_misses: %zu\n",
+                  ms_stats.vef_miss);
+    pos+= sprintf(pos, "verify_failed: %zu\n",
+                  ms_stats.vef_failed);
   }
-  pthread_mutex_unlock(&sleeper_mutex);
 
-  /* Do Stuff */
-  switch (context->test)
+  if (ms_setting.exp_ver_per > 0)
   {
-  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;
+    pos+= sprintf(pos, "expired_get: %zu\n",
+                  ms_stats.exp_get);
+    pos+= sprintf(pos, "unexpired_unget: %zu\n",
+                  ms_stats.unexp_unget);
   }
 
-  memcached_free(memc);
+  pos+= sprintf(pos,
+                "written_bytes: %zu\n",
+                ms_stats.bytes_written);
+  pos+= sprintf(pos, "read_bytes: %zu\n",
+                ms_stats.bytes_read);
+  pos+= sprintf(pos, "object_bytes: %zu\n",
+                ms_stats.obj_bytes);
 
-  if (context->execute_pairs)
-    pairs_free(context->execute_pairs);
+  if (ms_setting.udp || ms_setting.facebook_test)
+  {
+    pos+= sprintf(pos, "packet_disorder: %zu\n",
+                  ms_stats.pkt_disorder);
+    pos+= sprintf(pos, "packet_drop: %zu\n",
+                  ms_stats.pkt_drop);
+    pos+= sprintf(pos, "udp_timeout: %zu\n",
+                  ms_stats.udp_timeout);
+  }
 
-  free(context);
+  if (ms_setting.stat_freq > 0)
+  {
+    ms_dump_stats(&ms_statistic.get_stat);
+    ms_dump_stats(&ms_statistic.set_stat);
+    ms_dump_stats(&ms_statistic.total_stat);
+  }
 
-  pthread_mutex_lock(&counter_mutex);
-  thread_counter--;
-  pthread_cond_signal(&count_threshhold);
-  pthread_mutex_unlock(&counter_mutex);
+  int64_t time_diff= ms_time_diff(start_time, end_time);
+  pos+= sprintf(
+    pos,
+    "\nRun time: %.1fs Ops: %llu TPS: %.0Lf Net_rate: %.1fM/s\n",
+    (double)time_diff / 1000000,
+    (unsigned long long)(ms_stats.cmd_get + ms_stats.cmd_set),
+    (ms_stats.cmd_get
+                 + ms_stats.cmd_set) / ((long double)time_diff / 1000000),
+    (double)(
+      ms_stats.bytes_written
+      + ms_stats.bytes_read) / 1024 / 1024
+    / ((double)time_diff / 1000000));
+
+  fprintf(stdout, "%s", buf);
+  fflush(stdout);
+} /* ms_print_memslap_stats */
+
+
+/* the loop of the main thread, wait the work threads to complete */
+static void ms_monitor_slap_mode()
+{
+  int second= 0;
+  struct timeval start_time, end_time;
 
-  return NULL;
-}
+  /* only when there is no set operation it need warm up */
+  if (ms_setting.cmd_distr[CMD_SET].cmd_prop < PROP_ERROR)
+  {
+    /* Wait all the connects complete warm up. */
+    pthread_mutex_lock(&ms_global.init_lock.lock);
+    while (ms_global.init_lock.count < (int)ms_setting.nconns)
+    {
+      pthread_cond_wait(&ms_global.init_lock.cond,
+                        &ms_global.init_lock.lock);
+    }
+    pthread_mutex_unlock(&ms_global.init_lock.lock);
+  }
 
-void flush_all(memcached_st *memc)
-{
-  memcached_flush(memc, 0);
-}
+  ms_global.finish_warmup= true;
+
+  /* running in "run time" mode, user specify run time */
+  if (ms_setting.run_time > 0)
+  {
+    gettimeofday(&start_time, NULL);
+    while (1)
+    {
+      sleep(1);
+      second++;
 
-pairs_st *load_create_data(memcached_st *memc, unsigned int number_of,
-                           unsigned int *actual_loaded)
+      if ((ms_setting.stat_freq > 0) && (second % ms_setting.stat_freq == 0)
+          && (ms_stats.active_conns >= ms_setting.nconns)
+          && (ms_stats.active_conns <= INT_MAX))
+      {
+        ms_print_statistics(second);
+      }
+
+      if (ms_setting.run_time <= second)
+      {
+        ms_global.time_out= true;
+        break;
+      }
+
+      /* all connections disconnect */
+      if ((second > 5) && (ms_stats.active_conns == 0))
+      {
+        break;
+      }
+    }
+    gettimeofday(&end_time, NULL);
+    sleep(1);       /* wait all threads clean up */
+  }
+  else
+  {
+    /* running in "execute number" mode, user specify execute number */
+    gettimeofday(&start_time, NULL);
+
+    /*
+     * We loop until we know that all connects have cleaned up.
+     */
+    pthread_mutex_lock(&ms_global.run_lock.lock);
+    while (ms_global.run_lock.count < (int)ms_setting.nconns)
+    {
+      pthread_cond_wait(&ms_global.run_lock.cond, &ms_global.run_lock.lock);
+    }
+    pthread_mutex_unlock(&ms_global.run_lock.lock);
+
+    gettimeofday(&end_time, NULL);
+  }
+
+  ms_print_memslap_stats(&start_time, &end_time);
+} /* ms_monitor_slap_mode */
+
+
+/* the main function */
+int main(int argc, char *argv[])
 {
-  memcached_st *memc_clone;
-  pairs_st *pairs;
+  srandom((unsigned int)time(NULL));
+  ms_global_struct_init();
 
-  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);
+  /* initialization */
+  ms_setting_init_pre();
+  ms_options_parse(argc, argv);
+  if (ms_check_para())
+  {
+    ms_help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION);
+    exit(1);
+  }
+  ms_setting_init_post();
+  ms_stats_init();
+  ms_thread_init();
 
-  pairs= pairs_generate(number_of, 400);
-  *actual_loaded= execute_set(memc_clone, pairs, number_of);
+  /* waiting work thread complete its task */
+  ms_monitor_slap_mode();
 
-  memcached_free(memc_clone);
+  /* clean up */
+  ms_thread_cleanup();
+  ms_global_struct_destroy();
+  ms_setting_cleanup();
 
-  return pairs;
-}
+  return 0;
+} /* main */
index 847e7f0d0ee8eeb8763ca07158a34705ff67e57e..42503d551ac8ce4242f98475b0d8e90d8f9bff8a 100644 (file)
@@ -1,3 +1,17 @@
+/* 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 "libmemcached/common.h"
 #include <stdio.h>
 #include <sys/types.h>
@@ -47,7 +61,7 @@ static struct option long_options[]=
 
 int main(int argc, char *argv[])
 {
-  memcached_return rc;
+  memcached_return_t rc;
   memcached_st *memc;
   memcached_stat_st *memc_stat;
   memcached_server_st *servers;
@@ -102,7 +116,7 @@ int main(int argc, char *argv[])
 static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat,
                          memcached_server_st *server_list)
 {
-  memcached_return rc;
+  memcached_return_t rc;
 
   if (analyze_mode == NULL)
   {
@@ -219,7 +233,7 @@ static void print_server_listing(memcached_st *memc, memcached_stat_st *memc_sta
                                  memcached_server_st *server_list)
 {
   unsigned int x;
-  memcached_return rc;
+  memcached_return_t rc;
 
   printf("Listing %u Server\n\n", memcached_server_count(memc));
   for (x= 0; x < memcached_server_count(memc); x++)
@@ -230,7 +244,7 @@ static void print_server_listing(memcached_st *memc, memcached_stat_st *memc_sta
     list= memcached_stat_get_keys(memc, &memc_stat[x], &rc);
 
     printf("Server: %s (%u)\n", memcached_server_name(memc, server_list[x]),
-           memcached_server_port(memc, server_list[x]));
+           (uint32_t)memcached_server_port(memc, server_list[x]));
     for (ptr= list; *ptr; ptr++)
     {
       char *value= memcached_stat_get_value(memc, &memc_stat[x], *ptr, &rc);
@@ -252,7 +266,7 @@ static void print_analysis_report(memcached_st *memc,
 
   printf("Memcached Cluster Analysis Report\n\n");
 
-  printf("\tNumber of Servers Analyzed         : %d\n", server_count);
+  printf("\tNumber of Servers Analyzed         : %u\n", server_count);
   printf("\tAverage Item Size (incl/overhead)  : %u bytes\n",
          report->average_item_size);
 
@@ -265,15 +279,15 @@ static void print_analysis_report(memcached_st *memc,
   printf("\n");
   printf("\tNode with most memory consumption  : %s:%u (%llu bytes)\n",
          memcached_server_name(memc, server_list[report->most_consumed_server]),
-         memcached_server_port(memc, server_list[report->most_consumed_server]),
+         (uint32_t)memcached_server_port(memc, server_list[report->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(memc, server_list[report->least_free_server]),
-         memcached_server_port(memc, server_list[report->least_free_server]),
+         (uint32_t)memcached_server_port(memc, server_list[report->least_free_server]),
          (unsigned long long)report->least_remaining_bytes);
   printf("\tNode with longest uptime           : %s:%u (%us)\n",
          memcached_server_name(memc, server_list[report->oldest_server]),
-         memcached_server_port(memc, server_list[report->oldest_server]),
+         (uint32_t)memcached_server_port(memc, server_list[report->oldest_server]),
          report->longest_uptime);
   printf("\tPool-wide Hit Ratio                : %1.f%%\n", report->pool_hit_ratio);
   printf("\n");
diff --git a/clients/ms_atomic.h b/clients/ms_atomic.h
new file mode 100644 (file)
index 0000000..1860663
--- /dev/null
@@ -0,0 +1,50 @@
+/* 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:
+ *
+ */
+
+#ifndef CLIENTS_MS_ATOMIC_H
+#define CLIENTS_MS_ATOMIC_H
+
+#if defined(__SUNPRO_C)
+# define _KERNEL
+# include <atomic.h>
+# if SIZEOF_SIZE_T == 8
+#  define  atomic_add_size(X, Y) atomic_add_64((X), (Y))
+#  define  atomic_add_size_nv(X, Y) atomic_add_64((X), (Y))
+#  define  atomic_dec_size(X, Y) atomic_add_64((X), (Y))
+#  define  atomic_dec_size_nv(X, Y) atomic_add_64((X), (Y))
+# else
+#  define  atomic_add_size(X, Y) atomic_add_32((X), (Y))
+#  define  atomic_add_size_nv(X, Y) atomic_add_32((X), (Y))
+#  define  atomic_dec_size(X, Y) atomic_add_32((X), (Y))
+#  define  atomic_dec_size_nv(X, Y) atomic_add_32((X), (Y))
+# endif
+# undef _KERNEL
+#else
+# define atomic_add_8(X, Y)  __sync_fetch_and_add((X), (Y))
+# define atomic_add_16(X, Y) __sync_fetch_and_add((X), (Y))
+# define atomic_add_32(X, Y) __sync_fetch_and_add((X), (Y))
+# define atomic_add_size(X, Y) __sync_fetch_and_add((X), (Y))
+# define atomic_dec_8(X)  __sync_fetch_and_sub((X), 1)
+# define atomic_dec_16(X) __sync_fetch_and_sub((X), 1)
+# define atomic_dec_32(X) __sync_fetch_and_sub((X), 1)
+# define atomic_dec_size(X) __sync_fetch_and_sub((X), 1)
+/* The same as above, but these return the new value instead of void */
+# define atomic_add_8_nv(X, Y)  __sync_fetch_and_add((X), (Y))
+# define atomic_add_16_nv(X, Y) __sync_fetch_and_add((X), (Y))
+# define atomic_add_32_nv(X, Y) __sync_fetch_and_add((X), (Y))
+# define atomic_add_size_nv(X, Y) __sync_fetch_and_add((X), (Y))
+# define atomic_dec_8_nv(X)  __sync_fetch_and_sub((X), 1)
+# define atomic_dec_16_nv(X) __sync_fetch_and_sub((X), 1)
+# define atomic_dec_32_nv(X) __sync_fetch_and_sub((X), 1)
+# define atomic_dec_size_nv(X) __sync_fetch_and_sub((X), 1)
+#endif /* defined(__SUNPRO_C) */
+
+#endif /* CLIENTS_MS_ATOMIC_H */
diff --git a/clients/ms_conn.c b/clients/ms_conn.c
new file mode 100644 (file)
index 0000000..b488401
--- /dev/null
@@ -0,0 +1,3451 @@
+/*
+ * File:   ms_conn.c
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <sys/uio.h>
+#include <event.h>
+#include <fcntl.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include "ms_setting.h"
+#include "ms_thread.h"
+#include "ms_atomic.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
+#undef htons
+#undef htonl
+#endif
+
+/* for network write */
+#define TRANSMIT_COMPLETE      0
+#define TRANSMIT_INCOMPLETE    1
+#define TRANSMIT_SOFT_ERROR    2
+#define TRANSMIT_HARD_ERROR    3
+
+/* for generating key */
+#define KEY_PREFIX_BASE        0x1010101010101010 /* not include ' ' '\r' '\n' '\0' */
+#define KEY_PREFIX_MASK        0x1010101010101010
+
+/* For parse the value length return by server */
+#define KEY_TOKEN              1
+#define VALUELEN_TOKEN         3
+
+/* global increasing counter, to ensure the key prefix unique */
+static uint64_t key_prefix_seq= KEY_PREFIX_BASE;
+
+/* global increasing counter, generating request id for UDP */
+static volatile uint32_t udp_request_id= 0;
+
+extern pthread_key_t ms_thread_key;
+
+/* generate upd request id */
+static uint32_t ms_get_udp_request_id(void);
+
+
+/* connect initialize */
+static void ms_task_init(ms_conn_t *c);
+static int ms_conn_udp_init(ms_conn_t *c, const bool is_udp);
+static int ms_conn_sock_init(ms_conn_t *c);
+static int ms_conn_event_init(ms_conn_t *c);
+static int ms_conn_init(ms_conn_t *c,
+                        const int init_state,
+                        const int read_buffer_size,
+                        const bool is_udp);
+static void ms_warmup_num_init(ms_conn_t *c);
+static int ms_item_win_init(ms_conn_t *c);
+
+
+/* connection close */
+void ms_conn_free(ms_conn_t *c);
+static void ms_conn_close(ms_conn_t *c);
+
+
+/* create network connection */
+static int ms_new_socket(struct addrinfo *ai);
+static void ms_maximize_sndbuf(const int sfd);
+static int ms_network_connect(ms_conn_t *c,
+                              char *srv_host_name,
+                              const int srv_port,
+                              const bool is_udp,
+                              int *ret_sfd);
+static int ms_reconn(ms_conn_t *c);
+
+
+/* read and parse */
+static int ms_tokenize_command(char *command,
+                               token_t *tokens,
+                               const int max_tokens);
+static int ms_ascii_process_line(ms_conn_t *c, char *command);
+static int ms_try_read_line(ms_conn_t *c);
+static int ms_sort_udp_packet(ms_conn_t *c, char *buf, int rbytes);
+static int ms_udp_read(ms_conn_t *c, char *buf, int len);
+static int ms_try_read_network(ms_conn_t *c);
+static void ms_verify_value(ms_conn_t *c,
+                            ms_mlget_task_item_t *mlget_item,
+                            char *value,
+                            int vlen);
+static void ms_ascii_complete_nread(ms_conn_t *c);
+static void ms_bin_complete_nread(ms_conn_t *c);
+static void ms_complete_nread(ms_conn_t *c);
+
+
+/* send functions */
+static int ms_add_msghdr(ms_conn_t *c);
+static int ms_ensure_iov_space(ms_conn_t *c);
+static int ms_add_iov(ms_conn_t *c, const void *buf, int len);
+static int ms_build_udp_headers(ms_conn_t *c);
+static int ms_transmit(ms_conn_t *c);
+
+
+/* status adjustment */
+static void ms_conn_shrink(ms_conn_t *c);
+static void ms_conn_set_state(ms_conn_t *c, int state);
+static bool ms_update_event(ms_conn_t *c, const int new_flags);
+static int ms_get_rep_sock_index(ms_conn_t *c, int cmd);
+static int ms_get_next_sock_index(ms_conn_t *c);
+static int ms_update_conn_sock_event(ms_conn_t *c);
+static bool ms_need_yield(ms_conn_t *c);
+static void ms_update_start_time(ms_conn_t *c);
+
+
+/* main loop */
+static void ms_drive_machine(ms_conn_t *c);
+void ms_event_handler(const int fd, const short which, void *arg);
+
+
+/* ascii protocol */
+static int ms_build_ascii_write_buf_set(ms_conn_t *c, ms_task_item_t *item);
+static int ms_build_ascii_write_buf_get(ms_conn_t *c, ms_task_item_t *item);
+static int ms_build_ascii_write_buf_mlget(ms_conn_t *c);
+
+
+/* binary protocol */
+static int ms_bin_process_response(ms_conn_t *c);
+static void ms_add_bin_header(ms_conn_t *c,
+                              uint8_t opcode,
+                              uint8_t hdr_len,
+                              uint16_t key_len,
+                              uint32_t body_len);
+static void ms_add_key_to_iov(ms_conn_t *c, ms_task_item_t *item);
+static int ms_build_bin_write_buf_set(ms_conn_t *c, ms_task_item_t *item);
+static int ms_build_bin_write_buf_get(ms_conn_t *c, ms_task_item_t *item);
+static int ms_build_bin_write_buf_mlget(ms_conn_t *c);
+
+
+/**
+ * each key has two parts, prefix and suffix. The suffix is a
+ * string random get form the character table. The prefix is a
+ * uint64_t variable. And the prefix must be unique. we use the
+ * prefix to identify a key. And the prefix can't include
+ * character ' ' '\r' '\n' '\0'.
+ *
+ * @return uint64_t
+ */
+uint64_t ms_get_key_prefix(void)
+{
+  uint64_t key_prefix;
+
+  pthread_mutex_lock(&ms_global.seq_mutex);
+  key_prefix_seq|= KEY_PREFIX_MASK;
+  key_prefix= key_prefix_seq;
+  key_prefix_seq++;
+  pthread_mutex_unlock(&ms_global.seq_mutex);
+
+  return key_prefix;
+} /* ms_get_key_prefix */
+
+
+/**
+ * get an unique udp request id
+ *
+ * @return an unique UDP request id
+ */
+static uint32_t ms_get_udp_request_id(void)
+{
+  return atomic_add_32_nv(&udp_request_id, 1);
+}
+
+
+/**
+ * initialize current task structure
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_task_init(ms_conn_t *c)
+{
+  c->curr_task.cmd= CMD_NULL;
+  c->curr_task.item= 0;
+  c->curr_task.verify= false;
+  c->curr_task.finish_verify= true;
+  c->curr_task.get_miss= true;
+
+  c->curr_task.get_opt= 0;
+  c->curr_task.set_opt= 0;
+  c->curr_task.cycle_undo_get= 0;
+  c->curr_task.cycle_undo_set= 0;
+  c->curr_task.verified_get= 0;
+  c->curr_task.overwrite_set= 0;
+} /* ms_task_init */
+
+
+/**
+ * initialize udp for the connection structure
+ *
+ * @param c, pointer of the concurrency
+ * @param is_udp, whether it's udp
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_conn_udp_init(ms_conn_t *c, const bool is_udp)
+{
+  c->hdrbuf= 0;
+  c->rudpbuf= 0;
+  c->udppkt= 0;
+
+  c->rudpsize= UDP_DATA_BUFFER_SIZE;
+  c->hdrsize= 0;
+
+  c->rudpbytes= 0;
+  c->packets= 0;
+  c->recvpkt= 0;
+  c->pktcurr= 0;
+  c->ordcurr= 0;
+
+  c->udp= is_udp;
+
+  if (c->udp || (! c->udp && ms_setting.facebook_test))
+  {
+    c->rudpbuf= (char *)malloc((size_t)c->rudpsize);
+    c->udppkt= (ms_udppkt_t *)malloc(MAX_UDP_PACKET * sizeof(ms_udppkt_t));
+
+    if ((c->rudpbuf == NULL) || (c->udppkt == NULL))
+    {
+      if (c->rudpbuf != NULL)
+        free(c->rudpbuf);
+      if (c->udppkt != NULL)
+        free(c->udppkt);
+      fprintf(stderr, "malloc()\n");
+      return -1;
+    }
+    memset(c->udppkt, 0, MAX_UDP_PACKET * sizeof(ms_udppkt_t));
+  }
+
+  return 0;
+} /* ms_conn_udp_init */
+
+
+/**
+ * initialize the connection structure
+ *
+ * @param c, pointer of the concurrency
+ * @param init_state, (conn_read, conn_write, conn_closing)
+ * @param read_buffer_size
+ * @param is_udp, whether it's udp
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_conn_init(ms_conn_t *c,
+                        const int init_state,
+                        const int read_buffer_size,
+                        const bool is_udp)
+{
+  assert(c != NULL);
+
+  c->rbuf= c->wbuf= 0;
+  c->iov= 0;
+  c->msglist= 0;
+
+  c->rsize= read_buffer_size;
+  c->wsize= WRITE_BUFFER_SIZE;
+  c->iovsize= IOV_LIST_INITIAL;
+  c->msgsize= MSG_LIST_INITIAL;
+
+  /* for replication, each connection need connect all the server */
+  if (ms_setting.rep_write_srv > 0)
+  {
+    c->total_sfds= ms_setting.srv_cnt;
+  }
+  else
+  {
+    c->total_sfds= ms_setting.sock_per_conn;
+  }
+  c->alive_sfds= 0;
+
+  c->rbuf= (char *)malloc((size_t)c->rsize);
+  c->wbuf= (char *)malloc((size_t)c->wsize);
+  c->iov= (struct iovec *)malloc(sizeof(struct iovec) * (size_t)c->iovsize);
+  c->msglist= (struct msghdr *)malloc(
+    sizeof(struct msghdr) * (size_t)c->msgsize);
+  if (ms_setting.mult_key_num > 1)
+  {
+    c->mlget_task.mlget_item= (ms_mlget_task_item_t *)
+                              malloc(
+      sizeof(ms_mlget_task_item_t) * (size_t)ms_setting.mult_key_num);
+  }
+  c->tcpsfd= (int *)malloc((size_t)c->total_sfds * sizeof(int));
+
+  if ((c->rbuf == NULL) || (c->wbuf == NULL) || (c->iov == NULL)
+      || (c->msglist == NULL) || (c->tcpsfd == NULL)
+      || ((ms_setting.mult_key_num > 1)
+          && (c->mlget_task.mlget_item == NULL)))
+  {
+    if (c->rbuf != NULL)
+      free(c->rbuf);
+    if (c->wbuf != NULL)
+      free(c->wbuf);
+    if (c->iov != NULL)
+      free(c->iov);
+    if (c->msglist != NULL)
+      free(c->msglist);
+    if (c->mlget_task.mlget_item != NULL)
+      free(c->mlget_task.mlget_item);
+    if (c->tcpsfd != NULL)
+      free(c->tcpsfd);
+    fprintf(stderr, "malloc()\n");
+    return -1;
+  }
+
+  c->state= init_state;
+  c->rvbytes= 0;
+  c->rbytes= 0;
+  c->rcurr= c->rbuf;
+  c->wcurr= c->wbuf;
+  c->iovused= 0;
+  c->msgcurr= 0;
+  c->msgused= 0;
+  c->cur_idx= c->total_sfds;       /* default index is a invalid value */
+
+  c->ctnwrite= false;
+  c->readval= false;
+  c->change_sfd= false;
+
+  c->precmd.cmd= c->currcmd.cmd= CMD_NULL;
+  c->precmd.isfinish= true;         /* default the previous command finished */
+  c->currcmd.isfinish= false;
+  c->precmd.retstat= c->currcmd.retstat= MCD_FAILURE;
+  c->precmd.key_prefix= c->currcmd.key_prefix= 0;
+
+  c->mlget_task.mlget_num= 0;
+  c->mlget_task.value_index= -1;         /* default invalid value */
+
+  if (ms_setting.binary_prot)
+  {
+    c->protocol= binary_prot;
+  }
+  else if (is_udp)
+  {
+    c->protocol= ascii_udp_prot;
+  }
+  else
+  {
+    c->protocol= ascii_prot;
+  }
+
+  /* initialize udp */
+  if (ms_conn_udp_init(c, is_udp) != 0)
+  {
+    return -1;
+  }
+
+  /* initialize task */
+  ms_task_init(c);
+
+  if (! (ms_setting.facebook_test && is_udp))
+  {
+    atomic_add_32(&ms_stats.active_conns, 1);
+  }
+
+  return 0;
+} /* ms_conn_init */
+
+
+/**
+ * when doing 100% get operation, it could preset some objects
+ * to warmup the server. this function is used to initialize the
+ * number of the objects to preset.
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_warmup_num_init(ms_conn_t *c)
+{
+  /* no set operation, preset all the items in the window  */
+  if (ms_setting.cmd_distr[CMD_SET].cmd_prop < PROP_ERROR)
+  {
+    c->warmup_num= c->win_size;
+    c->remain_warmup_num= c->warmup_num;
+  }
+  else
+  {
+    c->warmup_num= 0;
+    c->remain_warmup_num= c->warmup_num;
+  }
+} /* ms_warmup_num_init */
+
+
+/**
+ * each connection has an item window, this function initialize
+ * the window. The window is used to generate task.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_item_win_init(ms_conn_t *c)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  int exp_cnt= 0;
+
+  c->win_size= (int)ms_setting.win_size;
+  c->set_cursor= 0;
+  c->exec_num= ms_thread->thread_ctx->exec_num_perconn;
+  c->remain_exec_num= c->exec_num;
+
+  c->item_win= (ms_task_item_t *)malloc(
+    sizeof(ms_task_item_t) * (size_t)c->win_size);
+  if (c->item_win == NULL)
+  {
+    fprintf(stderr, "Can't allocate task item array for conn.\n");
+    return -1;
+  }
+  memset(c->item_win, 0, sizeof(ms_task_item_t) * (size_t)c->win_size);
+
+  for (int i= 0; i < c->win_size; i++)
+  {
+    c->item_win[i].key_size= (int)ms_setting.distr[i].key_size;
+    c->item_win[i].key_prefix= ms_get_key_prefix();
+    c->item_win[i].key_suffix_offset= ms_setting.distr[i].key_offset;
+    c->item_win[i].value_size= (int)ms_setting.distr[i].value_size;
+    c->item_win[i].value_offset= INVALID_OFFSET;         /* default in invalid offset */
+    c->item_win[i].client_time= 0;
+
+    /* set expire time base on the proportion */
+    if (exp_cnt < ms_setting.exp_ver_per * i)
+    {
+      c->item_win[i].exp_time= FIXED_EXPIRE_TIME;
+      exp_cnt++;
+    }
+    else
+    {
+      c->item_win[i].exp_time= 0;
+    }
+  }
+
+  ms_warmup_num_init(c);
+
+  return 0;
+} /* ms_item_win_init */
+
+
+/**
+ * each connection structure can include one or more sock
+ * handlers. this function create these socks and connect the
+ * server(s).
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_conn_sock_init(ms_conn_t *c)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  int i;
+  int ret_sfd;
+  int srv_idx= 0;
+
+  assert(c != NULL);
+  assert(c->tcpsfd != NULL);
+
+  for (i= 0; i < c->total_sfds; i++)
+  {
+    ret_sfd= 0;
+    if (ms_setting.rep_write_srv > 0)
+    {
+      /* for replication, each connection need connect all the server */
+      srv_idx= i;
+    }
+    else
+    {
+      /* all the connections in a thread connects the same server */
+      srv_idx= ms_thread->thread_ctx->srv_idx;
+    }
+
+    if (ms_network_connect(c, ms_setting.servers[srv_idx].srv_host_name,
+                           ms_setting.servers[srv_idx].srv_port,
+                           ms_setting.udp, &ret_sfd) != 0)
+    {
+      break;
+    }
+
+    if (i == 0)
+    {
+      c->sfd= ret_sfd;
+    }
+
+    if (! ms_setting.udp)
+    {
+      c->tcpsfd[i]= ret_sfd;
+    }
+
+    c->alive_sfds++;
+  }
+
+  /* initialize udp sock handler if necessary */
+  if (ms_setting.facebook_test)
+  {
+    ret_sfd= 0;
+    if (ms_network_connect(c, ms_setting.servers[srv_idx].srv_host_name,
+                           ms_setting.servers[srv_idx].srv_port,
+                           true, &ret_sfd) != 0)
+    {
+      c->udpsfd= 0;
+    }
+    else
+    {
+      c->udpsfd= ret_sfd;
+    }
+  }
+
+  if ((i != c->total_sfds) || (ms_setting.facebook_test && (c->udpsfd == 0)))
+  {
+    if (ms_setting.udp)
+    {
+      close(c->sfd);
+    }
+    else
+    {
+      for (int j= 0; j < i; j++)
+      {
+        close(c->tcpsfd[j]);
+      }
+    }
+
+    if (c->udpsfd != 0)
+    {
+      close(c->udpsfd);
+    }
+
+    return -1;
+  }
+
+  return 0;
+} /* ms_conn_sock_init */
+
+
+/**
+ * each connection is managed by libevent, this function
+ * initialize the event of the connection structure.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_conn_event_init(ms_conn_t *c)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  /* default event timeout 10 seconds */
+  struct timeval t=
+  {
+    .tv_sec= EVENT_TIMEOUT, .tv_usec= 0
+  };
+  short event_flags= EV_WRITE | EV_PERSIST;
+
+  event_set(&c->event, c->sfd, event_flags, ms_event_handler, (void *)c);
+  event_base_set(ms_thread->base, &c->event);
+  c->ev_flags= event_flags;
+
+  if (c->total_sfds == 1)
+  {
+    if (event_add(&c->event, NULL) == -1)
+    {
+      return -1;
+    }
+  }
+  else
+  {
+    if (event_add(&c->event, &t) == -1)
+    {
+      return -1;
+    }
+  }
+
+  return 0;
+} /* ms_conn_event_init */
+
+
+/**
+ * setup a connection, each connection structure of each
+ * thread must call this function to initialize.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+int ms_setup_conn(ms_conn_t *c)
+{
+  if (ms_item_win_init(c) != 0)
+  {
+    return -1;
+  }
+
+  if (ms_conn_init(c, conn_write, DATA_BUFFER_SIZE, ms_setting.udp) != 0)
+  {
+    return -1;
+  }
+
+  if (ms_conn_sock_init(c) != 0)
+  {
+    return -1;
+  }
+
+  if (ms_conn_event_init(c) != 0)
+  {
+    return -1;
+  }
+
+  return 0;
+} /* ms_setup_conn */
+
+
+/**
+ * Frees a connection.
+ *
+ * @param c, pointer of the concurrency
+ */
+void ms_conn_free(ms_conn_t *c)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  if (c != NULL)
+  {
+    if (c->hdrbuf != NULL)
+      free(c->hdrbuf);
+    if (c->msglist != NULL)
+      free(c->msglist);
+    if (c->rbuf != NULL)
+      free(c->rbuf);
+    if (c->wbuf != NULL)
+      free(c->wbuf);
+    if (c->iov != NULL)
+      free(c->iov);
+    if (c->mlget_task.mlget_item != NULL)
+      free(c->mlget_task.mlget_item);
+    if (c->rudpbuf != NULL)
+      free(c->rudpbuf);
+    if (c->udppkt != NULL)
+      free(c->udppkt);
+    if (c->item_win != NULL)
+      free(c->item_win);
+    if (c->tcpsfd != NULL)
+      free(c->tcpsfd);
+
+    if (--ms_thread->nactive_conn == 0)
+    {
+      free(ms_thread->conn);
+    }
+  }
+} /* ms_conn_free */
+
+
+/**
+ * close a connection
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_conn_close(ms_conn_t *c)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  assert(c != NULL);
+
+  /* delete the event, the socket and the connection */
+  event_del(&c->event);
+
+  for (int i= 0; i < c->total_sfds; i++)
+  {
+    if (c->tcpsfd[i] > 0)
+    {
+      close(c->tcpsfd[i]);
+    }
+  }
+  c->sfd= 0;
+
+  if (ms_setting.facebook_test)
+  {
+    close(c->udpsfd);
+  }
+
+  atomic_dec_32(&ms_stats.active_conns);
+
+  ms_conn_free(c);
+
+  if (ms_setting.run_time == 0)
+  {
+    pthread_mutex_lock(&ms_global.run_lock.lock);
+    ms_global.run_lock.count++;
+    pthread_cond_signal(&ms_global.run_lock.cond);
+    pthread_mutex_unlock(&ms_global.run_lock.lock);
+  }
+
+  if (ms_thread->nactive_conn == 0)
+  {
+    pthread_exit(NULL);
+  }
+} /* ms_conn_close */
+
+
+/**
+ * create a new sock
+ *
+ * @param ai, server address information
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_new_socket(struct addrinfo *ai)
+{
+  int sfd;
+
+  if ((sfd= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1)
+  {
+    fprintf(stderr, "socket() error: %s.\n", strerror(errno));
+    return -1;
+  }
+
+  return sfd;
+} /* ms_new_socket */
+
+
+/**
+ * Sets a socket's send buffer size to the maximum allowed by the system.
+ *
+ * @param sfd, file descriptor of socket
+ */
+static void ms_maximize_sndbuf(const int sfd)
+{
+  socklen_t intsize= sizeof(int);
+  unsigned int last_good= 0;
+  unsigned int min, max, avg;
+  unsigned int old_size;
+
+  /* Start with the default size. */
+  if (getsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &old_size, &intsize) != 0)
+  {
+    fprintf(stderr, "getsockopt(SO_SNDBUF)\n");
+    return;
+  }
+
+  /* Binary-search for the real maximum. */
+  min= old_size;
+  max= MAX_SENDBUF_SIZE;
+
+  while (min <= max)
+  {
+    avg= ((unsigned int)(min + max)) / 2;
+    if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void *)&avg, intsize) == 0)
+    {
+      last_good= avg;
+      min= avg + 1;
+    }
+    else
+    {
+      max= avg - 1;
+    }
+  }
+} /* ms_maximize_sndbuf */
+
+
+/**
+ * socket connects the server
+ *
+ * @param c, pointer of the concurrency
+ * @param srv_host_name, the host name of the server
+ * @param srv_port, port of server
+ * @param is_udp, whether it's udp
+ * @param ret_sfd, the connected socket file descriptor
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_network_connect(ms_conn_t *c,
+                              char *srv_host_name,
+                              const int srv_port,
+                              const bool is_udp,
+                              int *ret_sfd)
+{
+  int sfd;
+  struct linger ling=
+  {
+    0, 0
+  };
+  struct addrinfo *ai;
+  struct addrinfo *next;
+  struct addrinfo hints;
+  char port_buf[NI_MAXSERV];
+  int  error;
+  int  success= 0;
+
+  int flags= 1;
+
+  /*
+   * the memset call clears nonstandard fields in some impementations
+   * that otherwise mess things up.
+   */
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_flags= AI_PASSIVE | AI_ADDRCONFIG;
+  if (is_udp)
+  {
+    hints.ai_protocol= IPPROTO_UDP;
+    hints.ai_socktype= SOCK_DGRAM;
+    hints.ai_family= AF_INET;      /* This left here because of issues with OSX 10.5 */
+  }
+  else
+  {
+    hints.ai_family= AF_UNSPEC;
+    hints.ai_protocol= IPPROTO_TCP;
+    hints.ai_socktype= SOCK_STREAM;
+  }
+
+  snprintf(port_buf, NI_MAXSERV, "%d", srv_port);
+  error= getaddrinfo(srv_host_name, port_buf, &hints, &ai);
+  if (error != 0)
+  {
+    if (error != EAI_SYSTEM)
+      fprintf(stderr, "getaddrinfo(): %s.\n", gai_strerror(error));
+    else
+      perror("getaddrinfo()\n");
+
+    return -1;
+  }
+
+  for (next= ai; next; next= next->ai_next)
+  {
+    if ((sfd= ms_new_socket(next)) == -1)
+    {
+      freeaddrinfo(ai);
+      return -1;
+    }
+
+    setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
+    if (is_udp)
+    {
+      ms_maximize_sndbuf(sfd);
+    }
+    else
+    {
+      setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags,
+                 sizeof(flags));
+      setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
+      setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags,
+                 sizeof(flags));
+    }
+
+    if (is_udp)
+    {
+      c->srv_recv_addr_size= sizeof(struct sockaddr);
+      memcpy(&c->srv_recv_addr, next->ai_addr, c->srv_recv_addr_size);
+    }
+    else
+    {
+      if (connect(sfd, next->ai_addr, next->ai_addrlen) == -1)
+      {
+        close(sfd);
+        freeaddrinfo(ai);
+        return -1;
+      }
+    }
+
+    if (((flags= fcntl(sfd, F_GETFL, 0)) < 0)
+        || (fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0))
+    {
+      fprintf(stderr, "setting O_NONBLOCK\n");
+      close(sfd);
+      freeaddrinfo(ai);
+      return -1;
+    }
+
+    if (ret_sfd != NULL)
+    {
+      *ret_sfd= sfd;
+    }
+
+    success++;
+  }
+
+  freeaddrinfo(ai);
+
+  /* Return zero if we detected no errors in starting up connections */
+  return success == 0;
+} /* ms_network_connect */
+
+
+/**
+ * reconnect a disconnected sock
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_reconn(ms_conn_t *c)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  int srv_idx= 0;
+  int32_t srv_conn_cnt= 0;
+
+  if (ms_setting.rep_write_srv > 0)
+  {
+    srv_idx= c->cur_idx;
+    srv_conn_cnt= (int)ms_setting.nconns;
+  }
+  else
+  {
+    srv_idx= ms_thread->thread_ctx->srv_idx;
+    srv_conn_cnt= (int32_t)((int)ms_setting.nconns / ms_setting.srv_cnt);
+  }
+
+  /* close the old socket handler */
+  close(c->sfd);
+  c->tcpsfd[c->cur_idx]= 0;
+
+  if (atomic_add_32_nv(&ms_setting.servers[srv_idx].disconn_cnt, 1)
+      % (uint32_t)srv_conn_cnt == 0)
+  {
+    gettimeofday(&ms_setting.servers[srv_idx].disconn_time, NULL);
+    fprintf(stderr, "Server %s:%d disconnect\n",
+            ms_setting.servers[srv_idx].srv_host_name,
+            ms_setting.servers[srv_idx].srv_port);
+  }
+
+  if (ms_setting.rep_write_srv > 0)
+  {
+    int i= 0;
+    for (i= 0; i < c->total_sfds; i++)
+    {
+      if (c->tcpsfd[i] != 0)
+      {
+        break;
+      }
+    }
+
+    /* all socks disconnect */
+    if (i == c->total_sfds)
+    {
+      return -1;
+    }
+  }
+  else
+  {
+    do
+    {
+      /* reconnect success, break the loop */
+      if (ms_network_connect(c, ms_setting.servers[srv_idx].srv_host_name,
+                             ms_setting.servers[srv_idx].srv_port,
+                             ms_setting.udp, &c->sfd) == 0)
+      {
+        c->tcpsfd[c->cur_idx]= c->sfd;
+        if (atomic_add_32_nv(&ms_setting.servers[srv_idx].reconn_cnt, 1)
+            % (uint32_t)srv_conn_cnt == 0)
+        {
+          gettimeofday(&ms_setting.servers[srv_idx].reconn_time, NULL);
+          int reconn_time=
+            (int)(ms_setting.servers[srv_idx].reconn_time.tv_sec
+                  - ms_setting.servers[srv_idx].disconn_time
+                     .tv_sec);
+          fprintf(stderr, "Server %s:%d reconnect after %ds\n",
+                  ms_setting.servers[srv_idx].srv_host_name,
+                  ms_setting.servers[srv_idx].srv_port, reconn_time);
+        }
+        break;
+      }
+
+      if (c->total_sfds == 1)
+      {
+        /* wait a second and reconnect */
+        sleep(1);
+      }
+    }
+    while (c->total_sfds == 1);
+  }
+
+  if ((c->total_sfds > 1) && (c->tcpsfd[c->cur_idx] == 0))
+  {
+    c->sfd= 0;
+    c->alive_sfds--;
+  }
+
+  return 0;
+} /* ms_reconn */
+
+
+/**
+ *  reconnect several disconnected socks in the connection
+ *  structure, the ever-1-second timer of the thread will check
+ *  whether some socks in the connections disconnect. if
+ *  disconnect, reconnect the sock.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+int ms_reconn_socks(ms_conn_t *c)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  int srv_idx= 0;
+  int ret_sfd= 0;
+  int srv_conn_cnt= 0;
+  struct timeval cur_time;
+
+  assert(c != NULL);
+
+  if ((c->total_sfds == 1) || (c->total_sfds == c->alive_sfds))
+  {
+    return 0;
+  }
+
+  for (int i= 0; i < c->total_sfds; i++)
+  {
+    if (c->tcpsfd[i] == 0)
+    {
+      gettimeofday(&cur_time, NULL);
+
+      /**
+       *  For failover test of replication, reconnect the socks after
+       *  it disconnects more than 5 seconds, Otherwise memslap will
+       *  block at connect() function and the work threads can't work
+       *  in this interval.
+       */
+      if (cur_time.tv_sec
+          - ms_setting.servers[srv_idx].disconn_time.tv_sec < 5)
+      {
+        break;
+      }
+
+      if (ms_setting.rep_write_srv > 0)
+      {
+        srv_idx= i;
+        srv_conn_cnt= (int)ms_setting.nconns;
+      }
+      else
+      {
+        srv_idx= ms_thread->thread_ctx->srv_idx;
+        srv_conn_cnt= (int)ms_setting.nconns / ms_setting.srv_cnt;
+      }
+
+      if (ms_network_connect(c, ms_setting.servers[srv_idx].srv_host_name,
+                             ms_setting.servers[srv_idx].srv_port,
+                             ms_setting.udp, &ret_sfd) == 0)
+      {
+        c->tcpsfd[i]= ret_sfd;
+        c->alive_sfds++;
+
+        if (atomic_add_32_nv(&ms_setting.servers[srv_idx].reconn_cnt, 1)
+            % (uint32_t)srv_conn_cnt == 0)
+        {
+          gettimeofday(&ms_setting.servers[srv_idx].reconn_time, NULL);
+          int reconn_time=
+            (int)(ms_setting.servers[srv_idx].reconn_time.tv_sec
+                  - ms_setting.servers[srv_idx].disconn_time
+                     .tv_sec);
+          fprintf(stderr, "Server %s:%d reconnect after %ds\n",
+                  ms_setting.servers[srv_idx].srv_host_name,
+                  ms_setting.servers[srv_idx].srv_port, reconn_time);
+        }
+      }
+    }
+  }
+
+  return 0;
+} /* ms_reconn_socks */
+
+
+/**
+ * Tokenize the command string by replacing whitespace with '\0' and update
+ * the token array tokens with pointer to start of each token and length.
+ * Returns total number of tokens.  The last valid token is the terminal
+ * token (value points to the first unprocessed character of the string and
+ * length zero).
+ *
+ * Usage example:
+ *
+ *  while(ms_tokenize_command(command, ncommand, tokens, max_tokens) > 0) {
+ *      for(int ix = 0; tokens[ix].length != 0; ix++) {
+ *          ...
+ *      }
+ *      ncommand = tokens[ix].value - command;
+ *      command  = tokens[ix].value;
+ *   }
+ *
+ * @param command, the command string to token
+ * @param tokens, array to store tokens
+ * @param max_tokens, maximum tokens number
+ *
+ * @return int, the number of tokens
+ */
+static int ms_tokenize_command(char *command,
+                               token_t *tokens,
+                               const int max_tokens)
+{
+  char *s, *e;
+  int  ntokens= 0;
+
+  assert(command != NULL && tokens != NULL && max_tokens > 1);
+
+  for (s= e= command; ntokens < max_tokens - 1; ++e)
+  {
+    if (*e == ' ')
+    {
+      if (s != e)
+      {
+        tokens[ntokens].value= s;
+        tokens[ntokens].length= (size_t)(e - s);
+        ntokens++;
+        *e= '\0';
+      }
+      s= e + 1;
+    }
+    else if (*e == '\0')
+    {
+      if (s != e)
+      {
+        tokens[ntokens].value= s;
+        tokens[ntokens].length= (size_t)(e - s);
+        ntokens++;
+      }
+
+      break;       /* string end */
+    }
+  }
+
+  return ntokens;
+} /* ms_tokenize_command */
+
+
+/**
+ * parse the response of server.
+ *
+ * @param c, pointer of the concurrency
+ * @param command, the string responded by server
+ *
+ * @return int, if the command completed return 0, else return
+ *         -1
+ */
+static int ms_ascii_process_line(ms_conn_t *c, char *command)
+{
+  int ret= 0;
+  int64_t value_len;
+  char *buffer= command;
+
+  assert(c != NULL);
+
+  /**
+   * for command get, we store the returned value into local buffer
+   * then continue in ms_complete_nread().
+   */
+
+  switch (buffer[0])
+  {
+  case 'V':                     /* VALUE || VERSION */
+    if (buffer[1] == 'A')       /* VALUE */
+    {
+      token_t tokens[MAX_TOKENS];
+      ms_tokenize_command(command, tokens, MAX_TOKENS);
+      value_len= strtol(tokens[VALUELEN_TOKEN].value, NULL, 10);
+      c->currcmd.key_prefix= *(uint64_t *)tokens[KEY_TOKEN].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.
+       */
+      c->rvbytes= (int)(value_len + 2);
+      c->readval= true;
+      ret= -1;
+    }
+
+    break;
+
+  case 'O':   /* OK */
+    c->currcmd.retstat= MCD_SUCCESS;
+
+  case 'S':                    /* STORED STATS SERVER_ERROR */
+    if (buffer[2] == 'A')      /* STORED STATS */
+    {       /* STATS*/
+      c->currcmd.retstat= MCD_STAT;
+    }
+    else if (buffer[1] == 'E')
+    {
+      /* SERVER_ERROR */
+      printf("<%d %s\n", c->sfd, buffer);
+
+      c->currcmd.retstat= MCD_SERVER_ERROR;
+    }
+    else if (buffer[1] == 'T')
+    {
+      /* STORED */
+      c->currcmd.retstat= MCD_STORED;
+    }
+    else
+    {
+      c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
+    }
+    break;
+
+  case 'D':   /* DELETED DATA */
+    if (buffer[1] == 'E')
+    {
+      c->currcmd.retstat= MCD_DELETED;
+    }
+    else
+    {
+      c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
+    }
+
+    break;
+
+  case 'N':   /* NOT_FOUND NOT_STORED*/
+    if (buffer[4] == 'F')
+    {
+      c->currcmd.retstat= MCD_NOTFOUND;
+    }
+    else if (buffer[4] == 'S')
+    {
+      printf("<%d %s\n", c->sfd, buffer);
+      c->currcmd.retstat= MCD_NOTSTORED;
+    }
+    else
+    {
+      c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
+    }
+    break;
+
+  case 'E':   /* PROTOCOL ERROR or END */
+    if (buffer[1] == 'N')
+    {
+      /* END */
+      c->currcmd.retstat= MCD_END;
+    }
+    else if (buffer[1] == 'R')
+    {
+      printf("<%d ERROR\n", c->sfd);
+      c->currcmd.retstat= MCD_PROTOCOL_ERROR;
+    }
+    else if (buffer[1] == 'X')
+    {
+      c->currcmd.retstat= MCD_DATA_EXISTS;
+      printf("<%d %s\n", c->sfd, buffer);
+    }
+    else
+    {
+      c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
+    }
+    break;
+
+  case 'C':   /* CLIENT ERROR */
+    printf("<%d %s\n", c->sfd, buffer);
+    c->currcmd.retstat= MCD_CLIENT_ERROR;
+    break;
+
+  default:
+    c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
+    break;
+  } /* switch */
+
+  return ret;
+} /* ms_ascii_process_line */
+
+
+/**
+ * after one operation completes, reset the concurrency
+ *
+ * @param c, pointer of the concurrency
+ * @param timeout, whether it's timeout
+ */
+void ms_reset_conn(ms_conn_t *c, bool timeout)
+{
+  assert(c != NULL);
+
+  if (c->udp)
+  {
+    if ((c->packets > 0) && (c->packets < MAX_UDP_PACKET))
+    {
+      memset(c->udppkt, 0, sizeof(ms_udppkt_t) * (size_t)c->packets);
+    }
+
+    c->packets= 0;
+    c->recvpkt= 0;
+    c->pktcurr= 0;
+    c->ordcurr= 0;
+    c->rudpbytes= 0;
+  }
+  c->currcmd.isfinish= true;
+  c->ctnwrite= false;
+  c->rbytes= 0;
+  c->rcurr= c->rbuf;
+  ms_conn_set_state(c, conn_write);
+  memcpy(&c->precmd, &c->currcmd, sizeof(ms_cmdstat_t));    /* replicate command state */
+
+  if (timeout)
+  {
+    ms_drive_machine(c);
+  }
+} /* ms_reset_conn */
+
+
+/**
+ * if we have a complete line in the buffer, process it.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_try_read_line(ms_conn_t *c)
+{
+  if (c->protocol == binary_prot)
+  {
+    /* Do we have the complete packet header? */
+    if ((uint64_t)c->rbytes < sizeof(c->binary_header))
+    {
+      /* need more data! */
+      return 0;
+    }
+    else
+    {
+#ifdef NEED_ALIGN
+      if (((long)(c->rcurr)) % 8 != 0)
+      {
+        /* must realign input buffer */
+        memmove(c->rbuf, c->rcurr, c->rbytes);
+        c->rcurr= c->rbuf;
+        if (settings.verbose)
+        {
+          fprintf(stderr, "%d: Realign input buffer.\n", c->sfd);
+        }
+      }
+#endif
+      protocol_binary_response_header *rsp;
+      rsp= (protocol_binary_response_header *)c->rcurr;
+
+      c->binary_header= *rsp;
+      c->binary_header.response.extlen= rsp->response.extlen;
+      c->binary_header.response.keylen= ntohs(rsp->response.keylen);
+      c->binary_header.response.bodylen= ntohl(rsp->response.bodylen);
+      c->binary_header.response.status= ntohs(rsp->response.status);
+
+      if (c->binary_header.response.magic != PROTOCOL_BINARY_RES)
+      {
+        fprintf(stderr, "Invalid magic:  %x\n",
+                c->binary_header.response.magic);
+        ms_conn_set_state(c, conn_closing);
+        return 0;
+      }
+
+      /* process this complete response */
+      if (ms_bin_process_response(c) == 0)
+      {
+        /* current operation completed */
+        ms_reset_conn(c, false);
+        return -1;
+      }
+      else
+      {
+        c->rbytes-= (int32_t)sizeof(c->binary_header);
+        c->rcurr+= sizeof(c->binary_header);
+      }
+    }
+  }
+  else
+  {
+    char *el, *cont;
+
+    assert(c != NULL);
+    assert(c->rcurr <= (c->rbuf + c->rsize));
+
+    if (c->rbytes == 0)
+      return 0;
+
+    el= memchr(c->rcurr, '\n', (size_t)c->rbytes);
+    if (! el)
+      return 0;
+
+    cont= el + 1;
+    if (((el - c->rcurr) > 1) && (*(el - 1) == '\r'))
+    {
+      el--;
+    }
+    *el= '\0';
+
+    assert(cont <= (c->rcurr + c->rbytes));
+
+    /* process this complete line */
+    if (ms_ascii_process_line(c, c->rcurr) == 0)
+    {
+      /* current operation completed */
+      ms_reset_conn(c, false);
+      return -1;
+    }
+    else
+    {
+      /* current operation didn't complete */
+      c->rbytes-= (int32_t)(cont - c->rcurr);
+      c->rcurr= cont;
+    }
+
+    assert(c->rcurr <= (c->rbuf + c->rsize));
+  }
+
+  return -1;
+} /* ms_try_read_line */
+
+
+/**
+ *  because the packet of UDP can't ensure the order, the
+ *  function is used to sort the received udp packet.
+ *
+ * @param c, pointer of the concurrency
+ * @param buf, the buffer to store the ordered packages data
+ * @param rbytes, the maximum capacity of the buffer
+ *
+ * @return int, if success, return the copy bytes, else return
+ *         -1
+ */
+static int ms_sort_udp_packet(ms_conn_t *c, char *buf, int rbytes)
+{
+  int len= 0;
+  int wbytes= 0;
+  uint16_t req_id= 0;
+  uint16_t seq_num= 0;
+  uint16_t packets= 0;
+  unsigned char *header= NULL;
+
+  /* no enough data */
+  assert(c != NULL);
+  assert(buf != NULL);
+  assert(c->rudpbytes >= UDP_HEADER_SIZE);
+
+  /* calculate received packets count */
+  if (c->rudpbytes % UDP_MAX_PAYLOAD_SIZE >= UDP_HEADER_SIZE)
+  {
+    /* the last packet has some data */
+    c->recvpkt= c->rudpbytes / UDP_MAX_PAYLOAD_SIZE + 1;
+  }
+  else
+  {
+    c->recvpkt= c->rudpbytes / UDP_MAX_PAYLOAD_SIZE;
+  }
+
+  /* get the total packets count if necessary */
+  if (c->packets == 0)
+  {
+    c->packets= HEADER_TO_PACKETS((unsigned char *)c->rudpbuf);
+  }
+
+  /* build the ordered packet array */
+  for (int i= c->pktcurr; i < c->recvpkt; i++)
+  {
+    header= (unsigned char *)c->rudpbuf + i * UDP_MAX_PAYLOAD_SIZE;
+    req_id= (uint16_t)HEADER_TO_REQID(header);
+    assert(req_id == c->request_id % (1 << 16));
+
+    packets= (uint16_t)HEADER_TO_PACKETS(header);
+    assert(c->packets == HEADER_TO_PACKETS(header));
+
+    seq_num= (uint16_t)HEADER_TO_SEQNUM(header);
+    c->udppkt[seq_num].header= header;
+    c->udppkt[seq_num].data= (char *)header + UDP_HEADER_SIZE;
+
+    if (i == c->recvpkt - 1)
+    {
+      /* last received packet */
+      if (c->rudpbytes % UDP_MAX_PAYLOAD_SIZE == 0)
+      {
+        c->udppkt[seq_num].rbytes= UDP_MAX_PAYLOAD_SIZE - UDP_HEADER_SIZE;
+        c->pktcurr++;
+      }
+      else
+      {
+        c->udppkt[seq_num].rbytes= c->rudpbytes % UDP_MAX_PAYLOAD_SIZE
+                                   - UDP_HEADER_SIZE;
+      }
+    }
+    else
+    {
+      c->udppkt[seq_num].rbytes= UDP_MAX_PAYLOAD_SIZE - UDP_HEADER_SIZE;
+      c->pktcurr++;
+    }
+  }
+
+  for (int i= c->ordcurr; i < c->recvpkt; i++)
+  {
+    /* there is some data to copy */
+    if ((c->udppkt[i].data != NULL)
+        && (c->udppkt[i].copybytes < c->udppkt[i].rbytes))
+    {
+      header= c->udppkt[i].header;
+      len= c->udppkt[i].rbytes - c->udppkt[i].copybytes;
+      if (len > rbytes - wbytes)
+      {
+        len= rbytes - wbytes;
+      }
+
+      assert(len <= rbytes - wbytes);
+      assert(i == HEADER_TO_SEQNUM(header));
+
+      memcpy(buf + wbytes, c->udppkt[i].data + c->udppkt[i].copybytes,
+             (size_t)len);
+      wbytes+= len;
+      c->udppkt[i].copybytes+= len;
+
+      if ((c->udppkt[i].copybytes == c->udppkt[i].rbytes)
+          && (c->udppkt[i].rbytes == UDP_MAX_PAYLOAD_SIZE - UDP_HEADER_SIZE))
+      {
+        /* finish copying all the data of this packet, next */
+        c->ordcurr++;
+      }
+
+      /* last received packet, and finish copying all the data */
+      if ((c->recvpkt == c->packets) && (i == c->recvpkt - 1)
+          && (c->udppkt[i].copybytes == c->udppkt[i].rbytes))
+      {
+        break;
+      }
+
+      /* no space to copy data */
+      if (wbytes >= rbytes)
+      {
+        break;
+      }
+
+      /* it doesn't finish reading all the data of the packet from network */
+      if ((i != c->recvpkt - 1)
+          && (c->udppkt[i].rbytes < UDP_MAX_PAYLOAD_SIZE - UDP_HEADER_SIZE))
+      {
+        break;
+      }
+    }
+    else
+    {
+      /* no data to copy */
+      break;
+    }
+  }
+
+  return wbytes == 0 ? -1 : wbytes;
+} /* ms_sort_udp_packet */
+
+
+/**
+ * encapsulate upd read like tcp read
+ *
+ * @param c, pointer of the concurrency
+ * @param buf, read buffer
+ * @param len, length to read
+ *
+ * @return int, if success, return the read bytes, else return
+ *         -1
+ */
+static int ms_udp_read(ms_conn_t *c, char *buf, int len)
+{
+  int res= 0;
+  int avail= 0;
+  int rbytes= 0;
+  int copybytes= 0;
+
+  assert(c->udp);
+
+  while (1)
+  {
+    if (c->rudpbytes + UDP_MAX_PAYLOAD_SIZE > c->rudpsize)
+    {
+      char *new_rbuf= realloc(c->rudpbuf, (size_t)c->rudpsize * 2);
+      if (! new_rbuf)
+      {
+        fprintf(stderr, "Couldn't realloc input buffer.\n");
+        c->rudpbytes= 0;          /* ignore what we read */
+        return -1;
+      }
+      c->rudpbuf= new_rbuf;
+      c->rudpsize*= 2;
+    }
+
+    avail= c->rudpsize - c->rudpbytes;
+    /* UDP each time read a packet, 1400 bytes */
+    res= (int)read(c->sfd, c->rudpbuf + c->rudpbytes, (size_t)avail);
+
+    if (res > 0)
+    {
+      atomic_add_size(&ms_stats.bytes_read, res);
+      c->rudpbytes+= res;
+      rbytes+= res;
+      if (res == avail)
+      {
+        continue;
+      }
+      else
+      {
+        break;
+      }
+    }
+
+    if (res == 0)
+    {
+      /* "connection" closed */
+      return res;
+    }
+
+    if (res == -1)
+    {
+      /* no data to read */
+      return res;
+    }
+  }
+
+  /* copy data to read buffer */
+  if (rbytes > 0)
+  {
+    copybytes= ms_sort_udp_packet(c, buf, len);
+  }
+
+  if (copybytes == -1)
+  {
+    atomic_add_size(&ms_stats.pkt_disorder, 1);
+  }
+
+  return copybytes;
+} /* ms_udp_read */
+
+
+/*
+ * read from network as much as we can, handle buffer overflow and connection
+ * close.
+ * before reading, move the remaining incomplete fragment of a command
+ * (if any) to the beginning of the buffer.
+ * return 0 if there's nothing to read on the first read.
+ */
+
+/**
+ * read from network as much as we can, handle buffer overflow and connection
+ * close. before reading, move the remaining incomplete fragment of a command
+ * (if any) to the beginning of the buffer.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int,
+ *         return 0 if there's nothing to read on the first read.
+ *         return 1 if get data
+ *         return -1 if error happens
+ */
+static int ms_try_read_network(ms_conn_t *c)
+{
+  int gotdata= 0;
+  int res;
+  int64_t avail;
+
+  assert(c != NULL);
+
+  if ((c->rcurr != c->rbuf)
+      && (! c->readval || (c->rvbytes > c->rsize - (c->rcurr - c->rbuf))
+          || (c->readval && (c->rcurr - c->rbuf > c->rbytes))))
+  {
+    if (c->rbytes != 0)     /* otherwise there's nothing to copy */
+      memmove(c->rbuf, c->rcurr, (size_t)c->rbytes);
+    c->rcurr= c->rbuf;
+  }
+
+  while (1)
+  {
+    if (c->rbytes >= c->rsize)
+    {
+      char *new_rbuf= realloc(c->rbuf, (size_t)c->rsize * 2);
+      if (! new_rbuf)
+      {
+        fprintf(stderr, "Couldn't realloc input buffer.\n");
+        c->rbytes= 0;          /* ignore what we read */
+        return -1;
+      }
+      c->rcurr= c->rbuf= new_rbuf;
+      c->rsize*= 2;
+    }
+
+    avail= c->rsize - c->rbytes - (c->rcurr - c->rbuf);
+    if (avail == 0)
+    {
+      break;
+    }
+
+    if (c->udp)
+    {
+      res= (int32_t)ms_udp_read(c, c->rcurr + c->rbytes, (int32_t)avail);
+    }
+    else
+    {
+      res= (int)read(c->sfd, c->rcurr + c->rbytes, (size_t)avail);
+    }
+
+    if (res > 0)
+    {
+      if (! c->udp)
+      {
+        atomic_add_size(&ms_stats.bytes_read, res);
+      }
+      gotdata= 1;
+      c->rbytes+= res;
+      if (res == avail)
+      {
+        continue;
+      }
+      else
+      {
+        break;
+      }
+    }
+    if (res == 0)
+    {
+      /* connection closed */
+      ms_conn_set_state(c, conn_closing);
+      return -1;
+    }
+    if (res == -1)
+    {
+      if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+        break;
+      /* Should close on unhandled errors. */
+      ms_conn_set_state(c, conn_closing);
+      return -1;
+    }
+  }
+
+  return gotdata;
+} /* ms_try_read_network */
+
+
+/**
+ * after get the object from server, verify the value if
+ * necessary.
+ *
+ * @param c, pointer of the concurrency
+ * @param mlget_item, pointer of mulit-get task item structure
+ * @param value, received value string
+ * @param vlen, received value string length
+ */
+static void ms_verify_value(ms_conn_t *c,
+                            ms_mlget_task_item_t *mlget_item,
+                            char *value,
+                            int vlen)
+{
+  if (c->curr_task.verify)
+  {
+    assert(c->curr_task.item->value_offset != INVALID_OFFSET);
+    char *orignval= &ms_setting.char_block[c->curr_task.item->value_offset];
+    char *orignkey=
+      &ms_setting.char_block[c->curr_task.item->key_suffix_offset];
+
+    /* verify expire time if necessary */
+    if (c->curr_task.item->exp_time > 0)
+    {
+      struct timeval curr_time;
+      gettimeofday(&curr_time, NULL);
+
+      /* object expired but get it now */
+      if (curr_time.tv_sec - c->curr_task.item->client_time
+          > c->curr_task.item->exp_time + EXPIRE_TIME_ERROR)
+      {
+        atomic_add_size(&ms_stats.exp_get, 1);
+
+        if (ms_setting.verbose)
+        {
+          char set_time[64];
+          char cur_time[64];
+          strftime(set_time, 64, "%Y-%m-%d %H:%M:%S",
+                   localtime(&c->curr_task.item->client_time));
+          strftime(cur_time, 64, "%Y-%m-%d %H:%M:%S",
+                   localtime(&curr_time.tv_sec));
+          fprintf(stderr,
+                  "\n<%d expire time verification failed, "
+                  "object expired but get it now\n"
+                  "\tkey len: %d\n"
+                  "\tkey: %" PRIx64 " %.*s\n"
+                  "\tset time: %s current time: %s "
+                  "diff time: %d expire time: %d\n"
+                  "\texpected data: \n"
+                  "\treceived data len: %d\n"
+                  "\treceived data: %.*s\n",
+                  c->sfd,
+                  c->curr_task.item->key_size,
+                  c->curr_task.item->key_prefix,
+                  c->curr_task.item->key_size - (int)KEY_PREFIX_SIZE,
+                  orignkey,
+                  set_time,
+                  cur_time,
+                  (int)(curr_time.tv_sec - c->curr_task.item->client_time),
+                  c->curr_task.item->exp_time,
+                  vlen,
+                  vlen,
+                  value);
+          fflush(stderr);
+        }
+      }
+    }
+    else
+    {
+      if ((c->curr_task.item->value_size != vlen)
+          || (memcmp(orignval, value, (size_t)vlen) != 0))
+      {
+        atomic_add_size(&ms_stats.vef_failed, 1);
+
+        if (ms_setting.verbose)
+        {
+          fprintf(stderr,
+                  "\n<%d data verification failed\n"
+                  "\tkey len: %d\n"
+                  "\tkey: %" PRIx64" %.*s\n"
+                  "\texpected data len: %d\n"
+                  "\texpected data: %.*s\n"
+                  "\treceived data len: %d\n"
+                  "\treceived data: %.*s\n",
+                  c->sfd,
+                  c->curr_task.item->key_size,
+                  c->curr_task.item->key_prefix,
+                  c->curr_task.item->key_size - (int)KEY_PREFIX_SIZE,
+                  orignkey,
+                  c->curr_task.item->value_size,
+                  c->curr_task.item->value_size,
+                  orignval,
+                  vlen,
+                  vlen,
+                  value);
+          fflush(stderr);
+        }
+      }
+    }
+
+    c->curr_task.finish_verify= true;
+
+    if (mlget_item != NULL)
+    {
+      mlget_item->finish_verify= true;
+    }
+  }
+} /* ms_verify_value */
+
+
+/**
+ * For ASCII protocol, after store the data into the local
+ * buffer, run this function to handle the data.
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_ascii_complete_nread(ms_conn_t *c)
+{
+  assert(c != NULL);
+  assert(c->rbytes >= c->rvbytes);
+  assert(c->protocol == ascii_udp_prot || c->protocol == ascii_prot);
+  if (c->rvbytes > 2)
+  {
+    assert(
+      c->rcurr[c->rvbytes - 1] == '\n' && c->rcurr[c->rvbytes - 2] == '\r');
+  }
+
+  /* multi-get */
+  ms_mlget_task_item_t *mlget_item= NULL;
+  if (((ms_setting.mult_key_num > 1)
+       && (c->mlget_task.mlget_num >= ms_setting.mult_key_num))
+      || ((c->remain_exec_num == 0) && (c->mlget_task.mlget_num > 0)))
+  {
+    c->mlget_task.value_index++;
+    mlget_item= &c->mlget_task.mlget_item[c->mlget_task.value_index];
+
+    if (mlget_item->item->key_prefix == c->currcmd.key_prefix)
+    {
+      c->curr_task.item= mlget_item->item;
+      c->curr_task.verify= mlget_item->verify;
+      c->curr_task.finish_verify= mlget_item->finish_verify;
+      mlget_item->get_miss= false;
+    }
+    else
+    {
+      /* Try to find the task item in multi-get task array */
+      for (int i= 0; i < c->mlget_task.mlget_num; i++)
+      {
+        mlget_item= &c->mlget_task.mlget_item[i];
+        if (mlget_item->item->key_prefix == c->currcmd.key_prefix)
+        {
+          c->curr_task.item= mlget_item->item;
+          c->curr_task.verify= mlget_item->verify;
+          c->curr_task.finish_verify= mlget_item->finish_verify;
+          mlget_item->get_miss= false;
+
+          break;
+        }
+      }
+    }
+  }
+
+  ms_verify_value(c, mlget_item, c->rcurr, c->rvbytes - 2);
+
+  c->curr_task.get_miss= false;
+  c->rbytes-= c->rvbytes;
+  c->rcurr= c->rcurr + c->rvbytes;
+  assert(c->rcurr <= (c->rbuf + c->rsize));
+  c->readval= false;
+  c->rvbytes= 0;
+} /* ms_ascii_complete_nread */
+
+
+/**
+ * For binary protocol, after store the data into the local
+ * buffer, run this function to handle the data.
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_bin_complete_nread(ms_conn_t *c)
+{
+  assert(c != NULL);
+  assert(c->rbytes >= c->rvbytes);
+  assert(c->protocol == binary_prot);
+
+  int extlen= c->binary_header.response.extlen;
+  int keylen= c->binary_header.response.keylen;
+  uint8_t opcode= c->binary_header.response.opcode;
+
+  /* not get command or not include value, just return */
+  if (((opcode != PROTOCOL_BINARY_CMD_GET)
+       && (opcode != PROTOCOL_BINARY_CMD_GETQ))
+      || (c->rvbytes <= extlen + keylen))
+  {
+    /* get miss */
+    if (c->binary_header.response.opcode == PROTOCOL_BINARY_CMD_GET)
+    {
+      c->currcmd.retstat= MCD_END;
+      c->curr_task.get_miss= true;
+    }
+
+    c->readval= false;
+    c->rvbytes= 0;
+    ms_reset_conn(c, false);
+    return;
+  }
+
+  /* multi-get */
+  ms_mlget_task_item_t *mlget_item= NULL;
+  if (((ms_setting.mult_key_num > 1)
+       && (c->mlget_task.mlget_num >= ms_setting.mult_key_num))
+      || ((c->remain_exec_num == 0) && (c->mlget_task.mlget_num > 0)))
+  {
+    c->mlget_task.value_index++;
+    mlget_item= &c->mlget_task.mlget_item[c->mlget_task.value_index];
+
+    c->curr_task.item= mlget_item->item;
+    c->curr_task.verify= mlget_item->verify;
+    c->curr_task.finish_verify= mlget_item->finish_verify;
+    mlget_item->get_miss= false;
+  }
+
+  ms_verify_value(c,
+                  mlget_item,
+                  c->rcurr + extlen + keylen,
+                  c->rvbytes - extlen - keylen);
+
+  c->currcmd.retstat= MCD_END;
+  c->curr_task.get_miss= false;
+  c->rbytes-= c->rvbytes;
+  c->rcurr= c->rcurr + c->rvbytes;
+  assert(c->rcurr <= (c->rbuf + c->rsize));
+  c->readval= false;
+  c->rvbytes= 0;
+
+  if (ms_setting.mult_key_num > 1)
+  {
+    /* multi-get have check all the item */
+    if (c->mlget_task.value_index == c->mlget_task.mlget_num - 1)
+    {
+      ms_reset_conn(c, false);
+    }
+  }
+  else
+  {
+    /* single get */
+    ms_reset_conn(c, false);
+  }
+} /* ms_bin_complete_nread */
+
+
+/**
+ * we get here after reading the value of get commands.
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_complete_nread(ms_conn_t *c)
+{
+  assert(c != NULL);
+  assert(c->rbytes >= c->rvbytes);
+  assert(c->protocol == ascii_udp_prot
+         || c->protocol == ascii_prot
+         || c->protocol == binary_prot);
+
+  if (c->protocol == binary_prot)
+  {
+    ms_bin_complete_nread(c);
+  }
+  else
+  {
+    ms_ascii_complete_nread(c);
+  }
+} /* ms_complete_nread */
+
+
+/**
+ * Adds a message header to a connection.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_add_msghdr(ms_conn_t *c)
+{
+  struct msghdr *msg;
+
+  assert(c != NULL);
+
+  if (c->msgsize == c->msgused)
+  {
+    msg=
+      realloc(c->msglist, (size_t)c->msgsize * 2 * sizeof(struct msghdr));
+    if (! msg)
+      return -1;
+
+    c->msglist= msg;
+    c->msgsize*= 2;
+  }
+
+  msg= c->msglist + c->msgused;
+
+  /**
+   *  this wipes msg_iovlen, msg_control, msg_controllen, and
+   *  msg_flags, the last 3 of which aren't defined on solaris:
+   */
+  memset(msg, 0, sizeof(struct msghdr));
+
+  msg->msg_iov= &c->iov[c->iovused];
+
+  if (c->udp && (c->srv_recv_addr_size > 0))
+  {
+    msg->msg_name= &c->srv_recv_addr;
+    msg->msg_namelen= c->srv_recv_addr_size;
+  }
+
+  c->msgbytes= 0;
+  c->msgused++;
+
+  if (c->udp)
+  {
+    /* Leave room for the UDP header, which we'll fill in later. */
+    return ms_add_iov(c, NULL, UDP_HEADER_SIZE);
+  }
+
+  return 0;
+} /* ms_add_msghdr */
+
+
+/**
+ * Ensures that there is room for another structure iovec in a connection's
+ * iov list.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_ensure_iov_space(ms_conn_t *c)
+{
+  assert(c != NULL);
+
+  if (c->iovused >= c->iovsize)
+  {
+    int i, iovnum;
+    struct iovec *new_iov= (struct iovec *)realloc(c->iov,
+                                                   ((size_t)c->iovsize
+                                                    * 2)
+                                                   * sizeof(struct iovec));
+    if (! new_iov)
+      return -1;
+
+    c->iov= new_iov;
+    c->iovsize*= 2;
+
+    /* Point all the msghdr structures at the new list. */
+    for (i= 0, iovnum= 0; i < c->msgused; i++)
+    {
+      c->msglist[i].msg_iov= &c->iov[iovnum];
+      iovnum+= (int)c->msglist[i].msg_iovlen;
+    }
+  }
+
+  return 0;
+} /* ms_ensure_iov_space */
+
+
+/**
+ * Adds data to the list of pending data that will be written out to a
+ * connection.
+ *
+ * @param c, pointer of the concurrency
+ * @param buf, the buffer includes data to send
+ * @param len, the data length in the buffer
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_add_iov(ms_conn_t *c, const void *buf, int len)
+{
+  struct msghdr *m;
+  int  leftover;
+  bool limit_to_mtu;
+
+  assert(c != NULL);
+
+  do
+  {
+    m= &c->msglist[c->msgused - 1];
+
+    /*
+     * Limit UDP packets, to UDP_MAX_PAYLOAD_SIZE bytes.
+     */
+    limit_to_mtu= c->udp;
+
+    /* We may need to start a new msghdr if this one is full. */
+    if ((m->msg_iovlen == IOV_MAX)
+        || (limit_to_mtu && (c->msgbytes >= UDP_MAX_SEND_PAYLOAD_SIZE)))
+    {
+      ms_add_msghdr(c);
+      m= &c->msglist[c->msgused - 1];
+    }
+
+    if (ms_ensure_iov_space(c) != 0)
+      return -1;
+
+    /* If the fragment is too big to fit in the datagram, split it up */
+    if (limit_to_mtu && (len + c->msgbytes > UDP_MAX_SEND_PAYLOAD_SIZE))
+    {
+      leftover= len + c->msgbytes - UDP_MAX_SEND_PAYLOAD_SIZE;
+      len-= leftover;
+    }
+    else
+    {
+      leftover= 0;
+    }
+
+    m= &c->msglist[c->msgused - 1];
+    m->msg_iov[m->msg_iovlen].iov_base= (void *)buf;
+    m->msg_iov[m->msg_iovlen].iov_len= (size_t)len;
+
+    c->msgbytes+= len;
+    c->iovused++;
+    m->msg_iovlen++;
+
+    buf= ((char *)buf) + len;
+    len= leftover;
+  }
+  while (leftover > 0);
+
+  return 0;
+} /* ms_add_iov */
+
+
+/**
+ * Constructs a set of UDP headers and attaches them to the outgoing messages.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_build_udp_headers(ms_conn_t *c)
+{
+  int i;
+  unsigned char *hdr;
+
+  assert(c != NULL);
+
+  c->request_id= ms_get_udp_request_id();
+
+  if (c->msgused > c->hdrsize)
+  {
+    void *new_hdrbuf;
+    if (c->hdrbuf)
+      new_hdrbuf= realloc(c->hdrbuf,
+                          (size_t)c->msgused * 2 * UDP_HEADER_SIZE);
+    else
+      new_hdrbuf= malloc((size_t)c->msgused * 2 * UDP_HEADER_SIZE);
+    if (! new_hdrbuf)
+      return -1;
+
+    c->hdrbuf= (unsigned char *)new_hdrbuf;
+    c->hdrsize= c->msgused * 2;
+  }
+
+  /* If this is a multi-packet request, drop it. */
+  if (c->udp && (c->msgused > 1))
+  {
+    fprintf(stderr, "multi-packet request for UDP not supported.\n");
+    return -1;
+  }
+
+  hdr= c->hdrbuf;
+  for (i= 0; i < c->msgused; i++)
+  {
+    c->msglist[i].msg_iov[0].iov_base= (void *)hdr;
+    c->msglist[i].msg_iov[0].iov_len= UDP_HEADER_SIZE;
+    *hdr++= (unsigned char)(c->request_id / 256);
+    *hdr++= (unsigned char)(c->request_id % 256);
+    *hdr++= (unsigned char)(i / 256);
+    *hdr++= (unsigned char)(i % 256);
+    *hdr++= (unsigned char)(c->msgused / 256);
+    *hdr++= (unsigned char)(c->msgused % 256);
+    *hdr++= (unsigned char)1;          /* support facebook memcached */
+    *hdr++= (unsigned char)0;
+    assert(hdr ==
+           ((unsigned char *)c->msglist[i].msg_iov[0].iov_base
+            + UDP_HEADER_SIZE));
+  }
+
+  return 0;
+} /* ms_build_udp_headers */
+
+
+/**
+ * Transmit the next chunk of data from our list of msgbuf structures.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return  TRANSMIT_COMPLETE   All done writing.
+ *          TRANSMIT_INCOMPLETE More data remaining to write.
+ *          TRANSMIT_SOFT_ERROR Can't write any more right now.
+ *          TRANSMIT_HARD_ERROR Can't write (c->state is set to conn_closing)
+ */
+static int ms_transmit(ms_conn_t *c)
+{
+  assert(c != NULL);
+
+  if ((c->msgcurr < c->msgused)
+      && (c->msglist[c->msgcurr].msg_iovlen == 0))
+  {
+    /* Finished writing the current msg; advance to the next. */
+    c->msgcurr++;
+  }
+
+  if (c->msgcurr < c->msgused)
+  {
+    ssize_t res;
+    struct msghdr *m= &c->msglist[c->msgcurr];
+
+    res= sendmsg(c->sfd, m, 0);
+    if (res > 0)
+    {
+      atomic_add_size(&ms_stats.bytes_written, res);
+
+      /* We've written some of the data. Remove the completed
+       *  iovec entries from the list of pending writes. */
+      while (m->msg_iovlen > 0 && res >= (ssize_t)m->msg_iov->iov_len)
+      {
+        res-= (ssize_t)m->msg_iov->iov_len;
+        m->msg_iovlen--;
+        m->msg_iov++;
+      }
+
+      /* Might have written just part of the last iovec entry;
+       *  adjust it so the next write will do the rest. */
+      if (res > 0)
+      {
+        m->msg_iov->iov_base= (void *)((unsigned char *)m->msg_iov->iov_base + res);
+        m->msg_iov->iov_len-= (size_t)res;
+      }
+      return TRANSMIT_INCOMPLETE;
+    }
+    if ((res == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
+    {
+      if (! ms_update_event(c, EV_WRITE | EV_PERSIST))
+      {
+        fprintf(stderr, "Couldn't update event.\n");
+        ms_conn_set_state(c, conn_closing);
+        return TRANSMIT_HARD_ERROR;
+      }
+      return TRANSMIT_SOFT_ERROR;
+    }
+
+    /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK,
+     *  we have a real error, on which we close the connection */
+    fprintf(stderr, "Failed to write, and not due to blocking.\n");
+
+    ms_conn_set_state(c, conn_closing);
+    return TRANSMIT_HARD_ERROR;
+  }
+  else
+  {
+    return TRANSMIT_COMPLETE;
+  }
+} /* ms_transmit */
+
+
+/**
+ * Shrinks a connection's buffers if they're too big.  This prevents
+ * periodic large "mget" response from server chewing lots of client
+ * memory.
+ *
+ * This should only be called in between requests since it can wipe output
+ * buffers!
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_conn_shrink(ms_conn_t *c)
+{
+  assert(c != NULL);
+
+  if (c->udp)
+    return;
+
+  if ((c->rsize > READ_BUFFER_HIGHWAT) && (c->rbytes < DATA_BUFFER_SIZE))
+  {
+    char *newbuf;
+
+    if (c->rcurr != c->rbuf)
+      memmove(c->rbuf, c->rcurr, (size_t)c->rbytes);
+
+    newbuf= (char *)realloc((void *)c->rbuf, DATA_BUFFER_SIZE);
+
+    if (newbuf)
+    {
+      c->rbuf= newbuf;
+      c->rsize= DATA_BUFFER_SIZE;
+    }
+    c->rcurr= c->rbuf;
+  }
+
+  if (c->udp && (c->rudpsize > UDP_DATA_BUFFER_HIGHWAT)
+      && (c->rudpbytes + UDP_MAX_PAYLOAD_SIZE < UDP_DATA_BUFFER_SIZE))
+  {
+    char *new_rbuf= (char *)realloc(c->rudpbuf, (size_t)c->rudpsize * 2);
+    if (! new_rbuf)
+    {
+      c->rudpbuf= new_rbuf;
+      c->rudpsize= UDP_DATA_BUFFER_SIZE;
+    }
+    /* TODO check error condition? */
+  }
+
+  if (c->msgsize > MSG_LIST_HIGHWAT)
+  {
+    struct msghdr *newbuf= (struct msghdr *)realloc(
+      (void *)c->msglist,
+      MSG_LIST_INITIAL
+      * sizeof(c->msglist[0]));
+    if (newbuf)
+    {
+      c->msglist= newbuf;
+      c->msgsize= MSG_LIST_INITIAL;
+    }
+    /* TODO check error condition? */
+  }
+
+  if (c->iovsize > IOV_LIST_HIGHWAT)
+  {
+    struct iovec *newbuf= (struct iovec *)realloc((void *)c->iov,
+                                                  IOV_LIST_INITIAL
+                                                  * sizeof(c->iov[0]));
+    if (newbuf)
+    {
+      c->iov= newbuf;
+      c->iovsize= IOV_LIST_INITIAL;
+    }
+    /* TODO check return value */
+  }
+} /* ms_conn_shrink */
+
+
+/**
+ * Sets a connection's current state in the state machine. Any special
+ * processing that needs to happen on certain state transitions can
+ * happen here.
+ *
+ * @param c, pointer of the concurrency
+ * @param state, connection state
+ */
+static void ms_conn_set_state(ms_conn_t *c, int state)
+{
+  assert(c != NULL);
+
+  if (state != c->state)
+  {
+    if (state == conn_read)
+    {
+      ms_conn_shrink(c);
+    }
+    c->state= state;
+  }
+} /* ms_conn_set_state */
+
+
+/**
+ * update the event if socks change state. for example: when
+ * change the listen scoket read event to sock write event, or
+ * change socket handler, we could call this function.
+ *
+ * @param c, pointer of the concurrency
+ * @param new_flags, new event flags
+ *
+ * @return bool, if success, return true, else return false
+ */
+static bool ms_update_event(ms_conn_t *c, const int new_flags)
+{
+  /* default event timeout 10 seconds */
+  struct timeval t=
+  {
+    .tv_sec= EVENT_TIMEOUT, .tv_usec= 0
+  };
+
+  assert(c != NULL);
+
+  struct event_base *base= c->event.ev_base;
+  if ((c->ev_flags == new_flags) && (ms_setting.rep_write_srv == 0)
+      && (! ms_setting.facebook_test || (c->total_sfds == 1)))
+  {
+    return true;
+  }
+
+  if (event_del(&c->event) == -1)
+  {
+    /* try to delete the event again */
+    if (event_del(&c->event) == -1)
+    {
+      return false;
+    }
+  }
+
+  event_set(&c->event,
+            c->sfd,
+            (short)new_flags,
+            ms_event_handler,
+            (void *)c);
+  event_base_set(base, &c->event);
+  c->ev_flags= (short)new_flags;
+
+  if (c->total_sfds == 1)
+  {
+    if (event_add(&c->event, NULL) == -1)
+    {
+      return false;
+    }
+  }
+  else
+  {
+    if (event_add(&c->event, &t) == -1)
+    {
+      return false;
+    }
+  }
+
+  return true;
+} /* ms_update_event */
+
+
+/**
+ * If user want to get the expected throughput, we could limit
+ * the performance of memslap. we could give up some work and
+ * just wait a short time. The function is used to check this
+ * case.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return bool, if success, return true, else return false
+ */
+static bool ms_need_yield(ms_conn_t *c)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  int64_t tps= 0;
+  int64_t time_diff= 0;
+  struct timeval curr_time;
+  ms_task_t *task= &c->curr_task;
+
+  if (ms_setting.expected_tps > 0)
+  {
+    gettimeofday(&curr_time, NULL);
+    time_diff= ms_time_diff(&ms_thread->startup_time, &curr_time);
+    tps=
+      (int64_t)((task->get_opt
+                 + task->set_opt) / ((uint64_t)time_diff / 1000000));
+
+    /* current throughput is greater than expected throughput */
+    if (tps > ms_thread->thread_ctx->tps_perconn)
+    {
+      return true;
+    }
+  }
+
+  return false;
+} /* ms_need_yield */
+
+
+/**
+ * used to update the start time of each operation
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_update_start_time(ms_conn_t *c)
+{
+  ms_task_item_t *item= c->curr_task.item;
+
+  if ((ms_setting.stat_freq > 0) || c->udp
+      || ((c->currcmd.cmd == CMD_SET) && (item->exp_time > 0)))
+  {
+    gettimeofday(&c->start_time, NULL);
+    if ((c->currcmd.cmd == CMD_SET) && (item->exp_time > 0))
+    {
+      /* record the current time */
+      item->client_time= c->start_time.tv_sec;
+    }
+  }
+} /* ms_update_start_time */
+
+
+/**
+ * run the state machine
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_drive_machine(ms_conn_t *c)
+{
+  bool stop= false;
+
+  assert(c != NULL);
+
+  while (! stop)
+  {
+    switch (c->state)
+    {
+    case conn_read:
+      if (c->readval)
+      {
+        if (c->rbytes >= c->rvbytes)
+        {
+          ms_complete_nread(c);
+          break;
+        }
+      }
+      else
+      {
+        if (ms_try_read_line(c) != 0)
+        {
+          break;
+        }
+      }
+
+      if (ms_try_read_network(c) != 0)
+      {
+        break;
+      }
+
+      /* doesn't read all the response data, wait event wake up */
+      if (! c->currcmd.isfinish)
+      {
+        if (! ms_update_event(c, EV_READ | EV_PERSIST))
+        {
+          fprintf(stderr, "Couldn't update event.\n");
+          ms_conn_set_state(c, conn_closing);
+          break;
+        }
+        stop= true;
+        break;
+      }
+
+      /* we have no command line and no data to read from network, next write */
+      ms_conn_set_state(c, conn_write);
+      memcpy(&c->precmd, &c->currcmd, sizeof(ms_cmdstat_t));        /* replicate command state */
+
+      break;
+
+    case conn_write:
+      if (! c->ctnwrite && ms_need_yield(c))
+      {
+        usleep(10);
+
+        if (! ms_update_event(c, EV_WRITE | EV_PERSIST))
+        {
+          fprintf(stderr, "Couldn't update event.\n");
+          ms_conn_set_state(c, conn_closing);
+          break;
+        }
+        stop= true;
+        break;
+      }
+
+      if (! c->ctnwrite && (ms_exec_task(c) != 0))
+      {
+        ms_conn_set_state(c, conn_closing);
+        break;
+      }
+
+      /* record the start time before starting to send data if necessary */
+      if (! c->ctnwrite || (c->change_sfd && c->ctnwrite))
+      {
+        if (c->change_sfd)
+        {
+          c->change_sfd= false;
+        }
+        ms_update_start_time(c);
+      }
+
+      /* change sfd if necessary */
+      if (c->change_sfd)
+      {
+        c->ctnwrite= true;
+        stop= true;
+        break;
+      }
+
+      /* execute task until nothing need be written to network */
+      if (! c->ctnwrite && (c->msgcurr == c->msgused))
+      {
+        if (! ms_update_event(c, EV_WRITE | EV_PERSIST))
+        {
+          fprintf(stderr, "Couldn't update event.\n");
+          ms_conn_set_state(c, conn_closing);
+          break;
+        }
+        stop= true;
+        break;
+      }
+
+      switch (ms_transmit(c))
+      {
+      case TRANSMIT_COMPLETE:
+        /* we have no data to write to network, next wait repose */
+        if (! ms_update_event(c, EV_READ | EV_PERSIST))
+        {
+          fprintf(stderr, "Couldn't update event.\n");
+          ms_conn_set_state(c, conn_closing);
+          c->ctnwrite= false;
+          break;
+        }
+        ms_conn_set_state(c, conn_read);
+        c->ctnwrite= false;
+        stop= true;
+        break;
+
+      case TRANSMIT_INCOMPLETE:
+        c->ctnwrite= true;
+        break;                           /* Continue in state machine. */
+
+      case TRANSMIT_HARD_ERROR:
+        c->ctnwrite= false;
+        break;
+
+      case TRANSMIT_SOFT_ERROR:
+        c->ctnwrite= true;
+        stop= true;
+        break;
+
+      default:
+        break;
+      } /* switch */
+
+      break;
+
+    case conn_closing:
+      /* recovery mode, need reconnect if connection close */
+      if (ms_setting.reconnect && (! ms_global.time_out
+                                   || ((ms_setting.run_time == 0)
+                                       && (c->remain_exec_num > 0))))
+      {
+        if (ms_reconn(c) != 0)
+        {
+          ms_conn_close(c);
+          stop= true;
+          break;
+        }
+
+        ms_reset_conn(c, false);
+
+        if (c->total_sfds == 1)
+        {
+          if (! ms_update_event(c, EV_WRITE | EV_PERSIST))
+          {
+            fprintf(stderr, "Couldn't update event.\n");
+            ms_conn_set_state(c, conn_closing);
+            break;
+          }
+        }
+
+        break;
+      }
+      else
+      {
+        ms_conn_close(c);
+        stop= true;
+        break;
+      }
+
+    default:
+      assert(0);
+    } /* switch */
+  }
+} /* ms_drive_machine */
+
+
+/**
+ * the event handler of each thread
+ *
+ * @param fd, the file descriptor of socket
+ * @param which, event flag
+ * @param arg, argument
+ */
+void ms_event_handler(const int fd, const short which, void *arg)
+{
+  ms_conn_t *c= (ms_conn_t *)arg;
+
+  assert(c != NULL);
+
+  c->which= which;
+
+  /* sanity */
+  if (fd != c->sfd)
+  {
+    fprintf(stderr,
+            "Catastrophic: event fd: %d doesn't match conn fd: %d\n",
+            fd,
+            c->sfd);
+    ms_conn_close(c);
+    exit(1);
+  }
+  assert(fd == c->sfd);
+
+  /* event timeout, close the current connection */
+  if (c->which == EV_TIMEOUT)
+  {
+    ms_conn_set_state(c, conn_closing);
+  }
+
+  ms_drive_machine(c);
+
+  /* wait for next event */
+} /* ms_event_handler */
+
+
+/**
+ * get the next socket descriptor index to run for replication
+ *
+ * @param c, pointer of the concurrency
+ * @param cmd, command(get or set )
+ *
+ * @return int, if success, return the index, else return 0
+ */
+static int ms_get_rep_sock_index(ms_conn_t *c, int cmd)
+{
+  int sock_index= -1;
+  int i= 0;
+
+  if (c->total_sfds == 1)
+  {
+    return 0;
+  }
+
+  if (ms_setting.rep_write_srv == 0)
+  {
+    return sock_index;
+  }
+
+  do
+  {
+    if (cmd == CMD_SET)
+    {
+      for (i= 0; i < ms_setting.rep_write_srv; i++)
+      {
+        if (c->tcpsfd[i] > 0)
+        {
+          break;
+        }
+      }
+
+      if (i == ms_setting.rep_write_srv)
+      {
+        /* random get one replication server to read */
+        sock_index= (int)(random() % c->total_sfds);
+      }
+      else
+      {
+        /* random get one replication writing server to write */
+        sock_index= (int)(random() % ms_setting.rep_write_srv);
+      }
+    }
+    else if (cmd == CMD_GET)
+    {
+      /* random get one replication server to read */
+      sock_index= (int)(random() % c->total_sfds);
+    }
+  }
+  while (c->tcpsfd[sock_index] == 0);
+
+  return sock_index;
+} /* ms_get_rep_sock_index */
+
+
+/**
+ * get the next socket descriptor index to run
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, return the index
+ */
+static int ms_get_next_sock_index(ms_conn_t *c)
+{
+  int sock_index= 0;
+
+  do
+  {
+    sock_index= (++c->cur_idx == c->total_sfds) ? 0 : c->cur_idx;
+  }
+  while (c->tcpsfd[sock_index] == 0);
+
+  return sock_index;
+} /* ms_get_next_sock_index */
+
+
+/**
+ * update socket event of the connections
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_update_conn_sock_event(ms_conn_t *c)
+{
+  assert(c != NULL);
+
+  switch (c->currcmd.cmd)
+  {
+  case CMD_SET:
+    if (ms_setting.facebook_test && c->udp)
+    {
+      c->sfd= c->tcpsfd[0];
+      c->udp= false;
+      c->change_sfd= true;
+    }
+    break;
+
+  case CMD_GET:
+    if (ms_setting.facebook_test && ! c->udp)
+    {
+      c->sfd= c->udpsfd;
+      c->udp= true;
+      c->change_sfd= true;
+    }
+    break;
+
+  default:
+    break;
+  } /* switch */
+
+  if (! c->udp && (c->total_sfds > 1))
+  {
+    if (c->cur_idx != c->total_sfds)
+    {
+      if (ms_setting.rep_write_srv == 0)
+      {
+        c->cur_idx= ms_get_next_sock_index(c);
+      }
+      else
+      {
+        c->cur_idx= ms_get_rep_sock_index(c, c->currcmd.cmd);
+      }
+    }
+    else
+    {
+      /* must select the first sock of the connection at the beginning */
+      c->cur_idx= 0;
+    }
+
+    c->sfd= c->tcpsfd[c->cur_idx];
+    assert(c->sfd != 0);
+    c->change_sfd= true;
+  }
+
+  if (c->change_sfd)
+  {
+    if (! ms_update_event(c, EV_WRITE | EV_PERSIST))
+    {
+      fprintf(stderr, "Couldn't update event.\n");
+      ms_conn_set_state(c, conn_closing);
+      return -1;
+    }
+  }
+
+  return 0;
+} /* ms_update_conn_sock_event */
+
+
+/**
+ * for ASCII protocol, this function build the set command
+ * string and send the command.
+ *
+ * @param c, pointer of the concurrency
+ * @param item, pointer of task item which includes the object
+ *            information
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_build_ascii_write_buf_set(ms_conn_t *c, ms_task_item_t *item)
+{
+  int value_offset;
+  int write_len;
+  char *buffer= c->wbuf;
+
+  write_len= sprintf(buffer,
+                     " %u %d %d\r\n",
+                     0,
+                     item->exp_time,
+                     item->value_size);
+
+  if (write_len > c->wsize)
+  {
+    /* ought to be always enough. just fail for simplicity */
+    fprintf(stderr, "output command line too long.\n");
+    return -1;
+  }
+
+  if (item->value_offset == INVALID_OFFSET)
+  {
+    value_offset= item->key_suffix_offset;
+  }
+  else
+  {
+    value_offset= item->value_offset;
+  }
+
+  if ((ms_add_iov(c, "set ", 4) != 0)
+      || (ms_add_iov(c, (char *)&item->key_prefix,
+                     (int)KEY_PREFIX_SIZE) != 0)
+      || (ms_add_iov(c, &ms_setting.char_block[item->key_suffix_offset],
+                     item->key_size - (int)KEY_PREFIX_SIZE) != 0)
+      || (ms_add_iov(c, buffer, write_len) != 0)
+      || (ms_add_iov(c, &ms_setting.char_block[value_offset],
+                     item->value_size) != 0)
+      || (ms_add_iov(c, "\r\n", 2) != 0)
+      || (c->udp && (ms_build_udp_headers(c) != 0)))
+  {
+    return -1;
+  }
+
+  return 0;
+} /* ms_build_ascii_write_buf_set */
+
+
+/**
+ * used to send set command to server
+ *
+ * @param c, pointer of the concurrency
+ * @param item, pointer of task item which includes the object
+ *            information
+ *
+ * @return int, if success, return 0, else return -1
+ */
+int ms_mcd_set(ms_conn_t *c, ms_task_item_t *item)
+{
+  assert(c != NULL);
+
+  c->currcmd.cmd= CMD_SET;
+  c->currcmd.isfinish= false;
+  c->currcmd.retstat= MCD_FAILURE;
+
+  if (ms_update_conn_sock_event(c) != 0)
+  {
+    return -1;
+  }
+
+  c->msgcurr= 0;
+  c->msgused= 0;
+  c->iovused= 0;
+  if (ms_add_msghdr(c) != 0)
+  {
+    fprintf(stderr, "Out of memory preparing request.");
+    return -1;
+  }
+
+  /* binary protocol */
+  if (c->protocol == binary_prot)
+  {
+    if (ms_build_bin_write_buf_set(c, item) != 0)
+    {
+      return -1;
+    }
+  }
+  else
+  {
+    if (ms_build_ascii_write_buf_set(c, item) != 0)
+    {
+      return -1;
+    }
+  }
+
+  atomic_add_size(&ms_stats.obj_bytes,
+                  item->key_size + item->value_size);
+  atomic_add_size(&ms_stats.cmd_set, 1);
+
+  return 0;
+} /* ms_mcd_set */
+
+
+/**
+ * for ASCII protocol, this function build the get command
+ * string and send the command.
+ *
+ * @param c, pointer of the concurrency
+ * @param item, pointer of task item which includes the object
+ *            information
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_build_ascii_write_buf_get(ms_conn_t *c, ms_task_item_t *item)
+{
+  if ((ms_add_iov(c, "get ", 4) != 0)
+      || (ms_add_iov(c, (char *)&item->key_prefix,
+                     (int)KEY_PREFIX_SIZE) != 0)
+      || (ms_add_iov(c, &ms_setting.char_block[item->key_suffix_offset],
+                     item->key_size - (int)KEY_PREFIX_SIZE) != 0)
+      || (ms_add_iov(c, "\r\n", 2) != 0)
+      || (c->udp && (ms_build_udp_headers(c) != 0)))
+  {
+    return -1;
+  }
+
+  return 0;
+} /* ms_build_ascii_write_buf_get */
+
+
+/**
+ * used to send the get command to server
+ *
+ * @param c, pointer of the concurrency
+ * @param item, pointer of task item which includes the object
+ *            information
+ * @param verify, whether do verification
+ *
+ * @return int, if success, return 0, else return -1
+ */
+int ms_mcd_get(ms_conn_t *c, ms_task_item_t *item, bool verify)
+{
+  /* verify not supported yet */
+  UNUSED_ARGUMENT(verify);
+
+  assert(c != NULL);
+
+  c->currcmd.cmd= CMD_GET;
+  c->currcmd.isfinish= false;
+  c->currcmd.retstat= MCD_FAILURE;
+
+  if (ms_update_conn_sock_event(c) != 0)
+  {
+    return -1;
+  }
+
+  c->msgcurr= 0;
+  c->msgused= 0;
+  c->iovused= 0;
+  if (ms_add_msghdr(c) != 0)
+  {
+    fprintf(stderr, "Out of memory preparing request.");
+    return -1;
+  }
+
+  /* binary protocol */
+  if (c->protocol == binary_prot)
+  {
+    if (ms_build_bin_write_buf_get(c, item) != 0)
+    {
+      return -1;
+    }
+  }
+  else
+  {
+    if (ms_build_ascii_write_buf_get(c, item) != 0)
+    {
+      return -1;
+    }
+  }
+
+  atomic_add_size(&ms_stats.cmd_get, 1);
+
+  return 0;
+} /* ms_mcd_get */
+
+
+/**
+ * for ASCII protocol, this function build the multi-get command
+ * string and send the command.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_build_ascii_write_buf_mlget(ms_conn_t *c)
+{
+  ms_task_item_t *item;
+
+  if (ms_add_iov(c, "get", 3) != 0)
+  {
+    return -1;
+  }
+
+  for (int i= 0; i < c->mlget_task.mlget_num; i++)
+  {
+    item= c->mlget_task.mlget_item[i].item;
+    assert(item != NULL);
+    if ((ms_add_iov(c, " ", 1) != 0)
+        || (ms_add_iov(c, (char *)&item->key_prefix,
+                       (int)KEY_PREFIX_SIZE) != 0)
+        || (ms_add_iov(c, &ms_setting.char_block[item->key_suffix_offset],
+                       item->key_size - (int)KEY_PREFIX_SIZE) != 0))
+    {
+      return -1;
+    }
+  }
+
+  if ((ms_add_iov(c, "\r\n", 2) != 0)
+      || (c->udp && (ms_build_udp_headers(c) != 0)))
+  {
+    return -1;
+  }
+
+  return 0;
+} /* ms_build_ascii_write_buf_mlget */
+
+
+/**
+ * used to send the multi-get command to server
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+int ms_mcd_mlget(ms_conn_t *c)
+{
+  ms_task_item_t *item;
+
+  assert(c != NULL);
+  assert(c->mlget_task.mlget_num >= 1);
+
+  c->currcmd.cmd= CMD_GET;
+  c->currcmd.isfinish= false;
+  c->currcmd.retstat= MCD_FAILURE;
+
+  if (ms_update_conn_sock_event(c) != 0)
+  {
+    return -1;
+  }
+
+  c->msgcurr= 0;
+  c->msgused= 0;
+  c->iovused= 0;
+  if (ms_add_msghdr(c) != 0)
+  {
+    fprintf(stderr, "Out of memory preparing request.");
+    return -1;
+  }
+
+  /* binary protocol */
+  if (c->protocol == binary_prot)
+  {
+    if (ms_build_bin_write_buf_mlget(c) != 0)
+    {
+      return -1;
+    }
+  }
+  else
+  {
+    if (ms_build_ascii_write_buf_mlget(c) != 0)
+    {
+      return -1;
+    }
+  }
+
+  /* decrease operation time of each item */
+  for (int i= 0; i < c->mlget_task.mlget_num; i++)
+  {
+    item= c->mlget_task.mlget_item[i].item;
+    atomic_add_size(&ms_stats.cmd_get, 1);
+  }
+
+  return 0;
+} /* ms_mcd_mlget */
+
+
+/**
+ * binary protocol support
+ */
+
+/**
+ * for binary protocol, parse the response of server
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_bin_process_response(ms_conn_t *c)
+{
+  const char *errstr= NULL;
+
+  assert(c != NULL);
+
+  uint32_t bodylen= c->binary_header.response.bodylen;
+  uint8_t  opcode= c->binary_header.response.opcode;
+  uint16_t status= c->binary_header.response.status;
+
+  if (bodylen > 0)
+  {
+    c->rvbytes= (int32_t)bodylen;
+    c->readval= true;
+    return 1;
+  }
+  else
+  {
+    switch (status)
+    {
+    case PROTOCOL_BINARY_RESPONSE_SUCCESS:
+      if (opcode == PROTOCOL_BINARY_CMD_SET)
+      {
+        c->currcmd.retstat= MCD_STORED;
+      }
+      else if (opcode == PROTOCOL_BINARY_CMD_DELETE)
+      {
+        c->currcmd.retstat= MCD_DELETED;
+      }
+      else if (opcode == PROTOCOL_BINARY_CMD_GET)
+      {
+        c->currcmd.retstat= MCD_END;
+      }
+      break;
+
+    case PROTOCOL_BINARY_RESPONSE_ENOMEM:
+      errstr= "Out of memory";
+      c->currcmd.retstat= MCD_SERVER_ERROR;
+      break;
+
+    case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
+      errstr= "Unknown command";
+      c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
+      break;
+
+    case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
+      errstr= "Not found";
+      c->currcmd.retstat= MCD_NOTFOUND;
+      break;
+
+    case PROTOCOL_BINARY_RESPONSE_EINVAL:
+      errstr= "Invalid arguments";
+      c->currcmd.retstat= MCD_PROTOCOL_ERROR;
+      break;
+
+    case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
+      errstr= "Data exists for key.";
+      break;
+
+    case PROTOCOL_BINARY_RESPONSE_E2BIG:
+      errstr= "Too large.";
+      c->currcmd.retstat= MCD_SERVER_ERROR;
+      break;
+
+    case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
+      errstr= "Not stored.";
+      c->currcmd.retstat= MCD_NOTSTORED;
+      break;
+
+    default:
+      errstr= "Unknown error";
+      c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
+      break;
+    } /* switch */
+
+    if (errstr != NULL)
+    {
+      fprintf(stderr, "%s\n", errstr);
+    }
+  }
+
+  return 0;
+} /* ms_bin_process_response */
+
+
+/* build binary header and add the header to the buffer to send */
+
+/**
+ * build binary header and add the header to the buffer to send
+ *
+ * @param c, pointer of the concurrency
+ * @param opcode, operation code
+ * @param hdr_len, length of header
+ * @param key_len, length of key
+ * @param body_len. length of body
+ */
+static void ms_add_bin_header(ms_conn_t *c,
+                              uint8_t opcode,
+                              uint8_t hdr_len,
+                              uint16_t key_len,
+                              uint32_t body_len)
+{
+  protocol_binary_request_header *header;
+
+  assert(c != NULL);
+
+  header= (protocol_binary_request_header *)c->wcurr;
+
+  header->request.magic= (uint8_t)PROTOCOL_BINARY_REQ;
+  header->request.opcode= (uint8_t)opcode;
+  header->request.keylen= htons(key_len);
+
+  header->request.extlen= (uint8_t)hdr_len;
+  header->request.datatype= (uint8_t)PROTOCOL_BINARY_RAW_BYTES;
+  header->request.reserved= 0;
+
+  header->request.bodylen= htonl(body_len);
+  header->request.opaque= 0;
+  header->request.cas= 0;
+
+  ms_add_iov(c, c->wcurr, sizeof(header->request));
+} /* ms_add_bin_header */
+
+
+/**
+ * add the key to the socket write buffer array
+ *
+ * @param c, pointer of the concurrency
+ * @param item, pointer of task item which includes the object
+ *            information
+ */
+static void ms_add_key_to_iov(ms_conn_t *c, ms_task_item_t *item)
+{
+  ms_add_iov(c, (char *)&item->key_prefix, (int)KEY_PREFIX_SIZE);
+  ms_add_iov(c, &ms_setting.char_block[item->key_suffix_offset],
+             item->key_size - (int)KEY_PREFIX_SIZE);
+}
+
+
+/**
+ * for binary protocol, this function build the set command
+ * and add the command to send buffer array.
+ *
+ * @param c, pointer of the concurrency
+ * @param item, pointer of task item which includes the object
+ *            information
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_build_bin_write_buf_set(ms_conn_t *c, ms_task_item_t *item)
+{
+  assert(c->wbuf == c->wcurr);
+
+  int value_offset;
+  protocol_binary_request_set *rep= (protocol_binary_request_set *)c->wcurr;
+  uint16_t keylen= (uint16_t)item->key_size;
+  uint32_t bodylen= (uint32_t)sizeof(rep->message.body)
+                    + (uint32_t)keylen + (uint32_t)item->value_size;
+
+  ms_add_bin_header(c,
+                    PROTOCOL_BINARY_CMD_SET,
+                    sizeof(rep->message.body),
+                    keylen,
+                    bodylen);
+  rep->message.body.flags= 0;
+  rep->message.body.expiration= htonl((uint32_t)item->exp_time);
+  ms_add_iov(c, &rep->message.body, sizeof(rep->message.body));
+  ms_add_key_to_iov(c, item);
+
+  if (item->value_offset == INVALID_OFFSET)
+  {
+    value_offset= item->key_suffix_offset;
+  }
+  else
+  {
+    value_offset= item->value_offset;
+  }
+  ms_add_iov(c, &ms_setting.char_block[value_offset], item->value_size);
+
+  return 0;
+} /* ms_build_bin_write_buf_set */
+
+
+/**
+ * for binary protocol, this function build the get command and
+ * add the command to send buffer array.
+ *
+ * @param c, pointer of the concurrency
+ * @param item, pointer of task item which includes the object
+ *            information
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_build_bin_write_buf_get(ms_conn_t *c, ms_task_item_t *item)
+{
+  assert(c->wbuf == c->wcurr);
+
+  ms_add_bin_header(c, PROTOCOL_BINARY_CMD_GET, 0, (uint16_t)item->key_size,
+                    (uint32_t)item->key_size);
+  ms_add_key_to_iov(c, item);
+
+  return 0;
+} /* ms_build_bin_write_buf_get */
+
+
+/**
+ * for binary protocol, this function build the multi-get
+ * command and add the command to send buffer array.
+ *
+ * @param c, pointer of the concurrency
+ * @param item, pointer of task item which includes the object
+ *            information
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_build_bin_write_buf_mlget(ms_conn_t *c)
+{
+  ms_task_item_t *item;
+
+  assert(c->wbuf == c->wcurr);
+
+  for (int i= 0; i < c->mlget_task.mlget_num; i++)
+  {
+    item= c->mlget_task.mlget_item[i].item;
+    assert(item != NULL);
+
+    ms_add_bin_header(c,
+                      PROTOCOL_BINARY_CMD_GET,
+                      0,
+                      (uint16_t)item->key_size,
+                      (uint32_t)item->key_size);
+    ms_add_key_to_iov(c, item);
+    c->wcurr+= sizeof(protocol_binary_request_get);
+  }
+
+  c->wcurr= c->wbuf;
+
+  return 0;
+} /* ms_build_bin_write_buf_mlget */
diff --git a/clients/ms_conn.h b/clients/ms_conn.h
new file mode 100644 (file)
index 0000000..d95191e
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * File:   ms_conn.h
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+#ifndef MS_CONN_H
+#define MS_CONN_H
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <event.h>
+#include <netdb.h>
+
+#include "ms_task.h"
+#include <libmemcached/memcached/protocol_binary.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DATA_BUFFER_SIZE             (1024 * 1024 + 2048) /* read buffer, 1M + 2k, enough for the max value(1M) */
+#define WRITE_BUFFER_SIZE            (32 * 1024)          /* write buffer, 32k */
+#define UDP_DATA_BUFFER_SIZE         (1 * 1024 * 1024)    /* read buffer for UDP, 1M */
+#define UDP_MAX_PAYLOAD_SIZE         1400                 /* server limit UDP payload size */
+#define UDP_MAX_SEND_PAYLOAD_SIZE    1400                 /* mtu size is 1500 */
+#define UDP_HEADER_SIZE              8                    /* UDP header size */
+#define MAX_SENDBUF_SIZE             (256 * 1024 * 1024)  /* Maximum socket buffer size */
+#define SOCK_WAIT_TIMEOUT            10                   /* maximum waiting time of UDP, 10s */
+#define EVENT_TIMEOUT                10                   /* maximum waiting time of event,10s */
+#define MAX_UDP_PACKET               (1 << 16)            /* maximum UDP packets, 65536 */
+
+/* Initial size of the sendmsg() scatter/gather array. */
+#define IOV_LIST_INITIAL             400
+
+/* Initial number of sendmsg() argument structures to allocate. */
+#define MSG_LIST_INITIAL             10
+
+/* High water marks for buffer shrinking */
+#define READ_BUFFER_HIGHWAT          (2 * DATA_BUFFER_SIZE)
+#define UDP_DATA_BUFFER_HIGHWAT      (4 * UDP_DATA_BUFFER_SIZE)
+#define IOV_LIST_HIGHWAT             600
+#define MSG_LIST_HIGHWAT             100
+
+/* parse udp header */
+#define HEADER_TO_REQID(ptr)      ((uint16_t)*ptr * 256 \
+                                   + (uint16_t)*(ptr + 1))
+#define HEADER_TO_SEQNUM(ptr)     ((uint16_t)*(ptr        \
+                                               + 2) * 256 \
+                                   + (uint16_t)*(ptr + 3))
+#define HEADER_TO_PACKETS(ptr)    ((uint16_t)*(ptr        \
+                                               + 4) * 256 \
+                                   + (uint16_t)*(ptr + 5))
+
+/* states of connection */
+enum conn_states
+{
+  conn_read,         /* reading in a command line */
+  conn_write,        /* writing out a simple response */
+  conn_closing,      /* closing this connection */
+};
+
+/* returned states of memcached command */
+enum mcd_ret
+{
+  MCD_SUCCESS,                      /* command success */
+  MCD_FAILURE,                      /* command failure */
+  MCD_UNKNOWN_READ_FAILURE,         /* unknown read failure */
+  MCD_PROTOCOL_ERROR,               /* protocol error */
+  MCD_CLIENT_ERROR,                 /* client error, wrong command */
+  MCD_SERVER_ERROR,                 /* server error, server run command failed */
+  MCD_DATA_EXISTS,                  /* object is existent in server */
+  MCD_NOTSTORED,                    /* server doesn't set the object successfully */
+  MCD_STORED,                       /* server set the object successfully */
+  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 */
+};
+
+/* used to store the current or previous running command state */
+typedef struct cmdstat
+{
+  int cmd;                  /* command name */
+  int retstat;              /* return state of this command */
+  bool isfinish;            /* if it read all the response data */
+  uint64_t key_prefix;      /* key prefix */
+} ms_cmdstat_t;
+
+/* udp packet structure */
+typedef struct udppkt
+{
+  uint8_t *header;          /* udp header of the packet */
+  char *data;               /* udp data of the packet */
+  int rbytes;               /* number of data in the packet */
+  int copybytes;            /* number of copied data in the packet */
+} ms_udppkt_t;
+
+/* three protocols supported */
+enum protocol
+{
+  ascii_prot = 3,           /* ASCII protocol */
+  ascii_udp_prot,           /* ASCII UDP protocol*/
+  binary_prot,              /* binary protocol */
+};
+
+/**
+ *  concurrency structure
+ *
+ *  Each thread has a libevent to manage the events of network.
+ *  Each thread has one or more self-governed concurrencies;
+ *  each concurrency has one or more socket connections. This
+ *  concurrency structure includes all the private variables of
+ *  the concurrency.
+ */
+typedef struct conn
+{
+  int conn_idx;             /* connection index in the thread */
+  int sfd;                  /* current tcp sock handler of the connection structure */
+  int udpsfd;               /* current udp sock handler of the connection structure*/
+  int state;                /* state of the connection */
+  struct event event;       /* event for libevent */
+  short ev_flags;           /* event flag for libevent */
+  short which;              /* which events were just triggered */
+  bool change_sfd;          /* whether change sfd */
+
+  int *tcpsfd;              /* TCP sock array */
+  int total_sfds;           /* how many socks in the tcpsfd array */
+  int alive_sfds;           /* alive socks */
+  int cur_idx;              /* current sock index in tcpsfd array */
+
+  ms_cmdstat_t precmd;      /* previous command state */
+  ms_cmdstat_t currcmd;     /* current command state */
+
+  char *rbuf;               /* buffer to read commands into */
+  char *rcurr;              /* but if we parsed some already, this is where we stopped */
+  int rsize;                /* total allocated size of rbuf */
+  int rbytes;               /* how much data, starting from rcur, do we have unparsed */
+
+  bool readval;             /* read value state, read known data size */
+  int rvbytes;              /* total value size need to read */
+
+  char *wbuf;               /* buffer to write commands out */
+  char *wcurr;              /* for multi-get, where we stopped */
+  int wsize;                /* total allocated size of wbuf */
+  bool ctnwrite;            /* continue to write */
+
+  /* data for the mwrite state */
+  struct iovec *iov;
+  int iovsize;              /* number of elements allocated in iov[] */
+  int iovused;              /* number of elements used in iov[] */
+
+  struct msghdr *msglist;
+  int msgsize;              /* number of elements allocated in msglist[] */
+  int msgused;              /* number of elements used in msglist[] */
+  int msgcurr;              /* element in msglist[] being transmitted now */
+  int msgbytes;             /* number of bytes in current msg */
+
+  /* data for UDP clients */
+  int udp;                          /* is this is a UDP "connection" */
+  uint32_t request_id;                   /* UDP request ID of current operation, if this is a UDP "connection" */
+  uint8_t *hdrbuf;                  /* udp packet headers */
+  int hdrsize;                      /* number of headers' worth of space is allocated */
+  struct  sockaddr srv_recv_addr;   /* Sent the most recent request to which server */
+  socklen_t srv_recv_addr_size;
+
+  /* udp read buffer */
+  char *rudpbuf;                    /* buffer to read commands into for udp */
+  int rudpsize;                     /* total allocated size of rudpbuf */
+  int rudpbytes;                    /* how much data, starting from rudpbuf */
+
+  /* order udp packet */
+  ms_udppkt_t *udppkt;              /* the offset of udp packet in rudpbuf */
+  int packets;                      /* number of total packets need to read */
+  int recvpkt;                      /* number of received packets */
+  int pktcurr;                      /* current packet in rudpbuf being ordered */
+  int ordcurr;                      /* current ordered packet */
+
+  ms_task_item_t *item_win;         /* task sequence */
+  int win_size;                     /* current task window size */
+  uint64_t set_cursor;              /* current set item index in the item window */
+  ms_task_t curr_task;              /* current running task */
+  ms_mlget_task_t mlget_task;       /* multi-get task */
+
+  int warmup_num;                   /* to run how many warm up operations*/
+  int remain_warmup_num;            /* left how many warm up operations to run */
+  int64_t exec_num;                 /* to run how many task operations */
+  int64_t remain_exec_num;          /* how many remained task operations to run */
+
+  /* response time statistic and time out control */
+  struct timeval start_time;        /* start time of current operation(s) */
+  struct timeval end_time;          /* end time of current operation(s) */
+
+  /* Binary protocol stuff */
+  protocol_binary_response_header binary_header;    /* local temporary binary header */
+  enum protocol protocol;                           /* which protocol this connection speaks */
+} ms_conn_t;
+
+/* used to generate the key prefix */
+uint64_t ms_get_key_prefix(void);
+
+
+/**
+ * setup a connection, each connection structure of each
+ * thread must call this function to initialize.
+ */
+int ms_setup_conn(ms_conn_t *c);
+
+
+/* after one operation completes, reset the connection */
+void ms_reset_conn(ms_conn_t *c, bool timeout);
+
+
+/**
+ *  reconnect several disconnected socks in the connection
+ *  structure, the ever-1-second timer of the thread will check
+ *  whether some socks in the connections disconnect. if
+ *  disconnect, reconnect the sock.
+ */
+int ms_reconn_socks(ms_conn_t *c);
+
+
+/* used to send set command to server */
+int ms_mcd_set(ms_conn_t *c, ms_task_item_t *item);
+
+
+/* used to send the get command to server */
+int ms_mcd_get(ms_conn_t *c, ms_task_item_t *item, bool verify);
+
+
+/* used to send the multi-get command to server */
+int ms_mcd_mlget(ms_conn_t *c);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of MS_CONN_H */
diff --git a/clients/ms_memslap.h b/clients/ms_memslap.h
new file mode 100644 (file)
index 0000000..87caca5
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * File:   ms_memslap.h
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+#ifndef MS_MEMSLAP_H
+#define MS_MEMSLAP_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <pthread.h>
+#if !defined(__cplusplus)
+# include <stdbool.h>
+#endif
+#include <math.h>
+
+#include "ms_stats.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* command line option  */
+typedef enum
+{
+  OPT_VERSION= 'V',
+  OPT_HELP= 'h',
+  OPT_UDP= 'U',
+  OPT_SERVERS= 's',
+  OPT_EXECUTE_NUMBER= 'x',
+  OPT_THREAD_NUMBER= 'T',
+  OPT_CONCURRENCY= 'c',
+  OPT_FIXED_LTH= 'X',
+  OPT_VERIFY= 'v',
+  OPT_GETS_DIVISION= 'd',
+  OPT_TIME= 't',
+  OPT_CONFIG_CMD= 'F',
+  OPT_WINDOW_SIZE= 'w',
+  OPT_EXPIRE= 'e',
+  OPT_STAT_FREQ= 'S',
+  OPT_RECONNECT= 'R',
+  OPT_VERBOSE= 'b',
+  OPT_FACEBOOK_TEST= 'a',
+  OPT_SOCK_PER_CONN= 'n',
+  OPT_BINARY_PROTOCOL= 'B',
+  OPT_OVERWRITE= 'o',
+  OPT_TPS= 'P',
+  OPT_REP_WRITE_SRV= 'p',
+} ms_options_t;
+
+/* global statistic of response time */
+typedef struct statistic
+{
+  pthread_mutex_t stat_mutex;       /* synchronize the following members */
+
+  ms_stat_t get_stat;               /* statistics of get command */
+  ms_stat_t set_stat;               /* statistics of set command */
+  ms_stat_t total_stat;             /* statistics of both get and set commands */
+} ms_statistic_t;
+
+/* global status statistic structure */
+typedef struct stats
+{
+  volatile uint32_t active_conns;   /* active connections */
+  size_t bytes_read;              /* read bytes */
+  size_t bytes_written;           /* written bytes */
+  size_t obj_bytes;               /* object bytes */
+  size_t pre_cmd_get;             /* previous total get command count */
+  size_t pre_cmd_set;             /* previous total set command count */
+  size_t cmd_get;                 /* current total get command count */
+  size_t cmd_set;                 /* current total set command count */
+  size_t get_misses;              /* total objects of get miss */
+  size_t vef_miss;                /* total objects of verification miss  */
+  size_t vef_failed;              /* total objects of verification failed  */
+  size_t unexp_unget;             /* total objects which is unexpired but not get */
+  size_t exp_get;                 /* total objects which is expired but get  */
+  volatile size_t pkt_disorder;            /* disorder packages of UDP */
+  size_t pkt_drop;                /* packages dropped of UDP */
+  size_t udp_timeout;             /* how many times timeout of UDP happens */
+} ms_stats_t;
+
+/* lock adapter */
+typedef struct sync_lock
+{
+  int count;
+  pthread_mutex_t lock;
+  pthread_cond_t cond;
+} ms_sync_lock_t;
+
+/* global variable structure */
+typedef struct global
+{
+  /* synchronize lock */
+  ms_sync_lock_t init_lock;
+  ms_sync_lock_t run_lock;
+
+  /* mutex for outputing error log synchronously when memslap crashes */
+  pthread_mutex_t quit_mutex;
+
+  /* mutex for generating key prefix */
+  pthread_mutex_t seq_mutex;
+
+  /* global synchronous flags for slap mode */
+  bool finish_warmup;
+  bool time_out;
+} ms_global_t;
+
+/* global structure */
+ms_global_t ms_global;
+
+/* global stats information structure */
+ms_stats_t ms_stats;
+
+/* global statistic structure */
+ms_statistic_t ms_statistic;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of MS_MEMSLAP_H */
diff --git a/clients/ms_setting.c b/clients/ms_setting.c
new file mode 100644 (file)
index 0000000..95af535
--- /dev/null
@@ -0,0 +1,1087 @@
+/*
+ * File:   ms_setting.c
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+
+#include "config.h"
+
+#include <libmemcached/memcached.h>
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <pwd.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+
+#include "ms_setting.h"
+#include "ms_conn.h"
+
+#define MAX_EXEC_NUM               0x4000000000000000      /* 1 << 62 */
+#define ADDR_ALIGN(addr)    ((addr + 15) & ~(16 - 1))      /* 16 bytes aligned */
+#define RAND_CHAR_SIZE             (10 * 1024 * 1024)      /* 10M character table */
+#define RESERVED_RAND_CHAR_SIZE    (2 * 1024 * 1024)       /* reserved 2M to avoid pointer sloping over */
+
+#define DEFAULT_CONFIG_NAME ".memslap.cnf"
+
+#define DEFAULT_THREADS_NUM        1                       /* default start one thread */
+#define DEFAULT_CONNS_NUM          16                      /* default each thread with 16 connections */
+#define DEFAULT_EXE_NUM            0                       /* default execute number is 0 */
+#define DEFAULT_VERIFY_RATE        0.0                     /* default it doesn't do data verification */
+#define DEFAULT_OVERWRITE_RATE     0.0                     /* default it doesn't do overwrite */
+#define DEFAULT_DIV                1                       /* default it runs single get */
+#define DEFAULT_RUN_TIME           600                     /* default run time 10 minutes */
+#define DEFAULT_WINDOW_SIZE        (10 * UNIT_ITEMS_COUNT) /* default window size is 10k */
+#define DEFAULT_SOCK_PER_CONN      1                       /* default socks per connection is 1 */
+
+/* Use this for string generation */
+#define CHAR_COUNT                 64 /* number of characters used to generate character table */
+const char ALPHANUMBERICS[]=
+  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-";
+
+ms_setting_st ms_setting;       /* store the settings specified by user */
+
+
+/* read setting from configuration file */
+static void ms_get_serverlist(char *str);
+static int ms_get_cpu_count(void);
+ms_conf_type_t ms_get_conf_type(char *line);
+static int ms_is_line_data(char *line);
+static int ms_read_is_data(char *line, ssize_t nread);
+static void ms_no_config_file(void);
+static void ms_parse_cfg_file(char *cfg_file);
+
+
+/* initialize setting structure */
+static void ms_init_random_block(void);
+static void ms_calc_avg_size(void);
+static int ms_shuffle_distr(ms_distr_t *distr, int length);
+static void ms_build_distr(void);
+static void ms_print_setting(void);
+static void ms_setting_slapmode_init_pre(void);
+static void ms_setting_slapmode_init_post(void);
+
+#if !defined(HAVE_GETLINE)
+#include <limits.h>
+static ssize_t getline (char **line, size_t *line_size, FILE *fp)
+{
+  char delim= '\n';
+  ssize_t result= 0;
+  size_t cur_len= 0;
+
+  if (line == NULL || line_size == NULL || fp == NULL)
+  {
+    errno = EINVAL;
+    return -1;
+  }
+
+  if (*line == NULL || *line_size == 0)
+  {
+    char *new_line;
+    *line_size = 120;
+    new_line= (char *) realloc (*line, *line_size);
+    if (new_line == NULL)
+    {
+      result= -1;
+      return result;
+    }
+    *line= new_line;
+  }
+
+  for (;;)
+  {
+    int i= getc(fp);
+    if (i == EOF)
+    {
+      result = -1;
+      break;
+    }
+
+    /* Make enough space for len+1 (for final NUL) bytes.  */
+    if (cur_len + 1 >= *line_size)
+    {
+      size_t needed_max=
+        SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
+      size_t needed= (2 * (*line_size)) + 1;
+      char *new_line;
+
+      if (needed_max < needed)
+        needed= needed_max;
+      if (cur_len + 1 >= needed)
+      {
+        result= -1;
+        errno= EOVERFLOW;
+        return result;
+      }
+
+      new_line= (char *)realloc(*line, needed);
+      if (new_line == NULL)
+      {
+        result= -1;
+        return result;
+      }
+
+      *line= new_line;
+      *line_size= needed;
+    }
+
+    (*line)[cur_len]= (char)i;
+    cur_len++;
+
+    if (i == delim)
+      break;
+  }
+  (*line)[cur_len] = '\0';
+  if (cur_len != 0)
+    return (ssize_t)cur_len;
+  return result;
+}
+#endif
+
+/**
+ * parse the server list string, and build the servers
+ * information structure array. this function is used to parse
+ * the command line options specified by user.
+ *
+ * @param str, the string of server list
+ */
+static void ms_get_serverlist(char *str)
+{
+  ms_mcd_server_t *srvs= NULL;
+
+  /**
+   * Servers list format is like this. For example:
+   * "localhost:11108, localhost:11109"
+   */
+  memcached_server_st *server_pool;
+  server_pool = memcached_servers_parse(str);
+
+  for (uint32_t loop= 0; loop < memcached_server_list_count(server_pool); loop++)
+  {
+    assert(ms_setting.srv_cnt < ms_setting.total_srv_cnt);
+    strcpy(ms_setting.servers[ms_setting.srv_cnt].srv_host_name, server_pool[loop].hostname);
+    ms_setting.servers[ms_setting.srv_cnt].srv_port= server_pool[loop].port;
+    ms_setting.servers[ms_setting.srv_cnt].disconn_cnt= 0;
+    ms_setting.servers[ms_setting.srv_cnt].reconn_cnt= 0;
+    ms_setting.srv_cnt++;
+
+    if (ms_setting.srv_cnt >= ms_setting.total_srv_cnt)
+    {
+      srvs= (ms_mcd_server_t *)realloc( ms_setting.servers,
+                                        (size_t)ms_setting.total_srv_cnt * sizeof(ms_mcd_server_t) * 2);
+      if (srvs == NULL)
+      {
+        fprintf(stderr, "Can't reallocate servers structure.\n");
+        exit(1);
+      }
+      ms_setting.servers= srvs;
+      ms_setting.total_srv_cnt*= 2;
+    }
+  }
+
+  memcached_server_free(server_pool);
+} /* ms_get_serverlist */
+
+
+/**
+ * used to get the CPU count of the current system
+ *
+ * @return return the cpu count if get, else return 1
+ */
+static int ms_get_cpu_count()
+{
+#ifdef HAVE__SC_NPROCESSORS_ONLN
+  return sysconf(_SC_NPROCESSORS_CONF);
+
+#else
+# ifdef HAVE_CPU_SET_T
+  int cpu_count= 0;
+  cpu_set_t cpu_set;
+
+  sched_getaffinity(0, sizeof(cpu_set_t), &cpu_set);
+
+  for (int i= 0; i < (sizeof(cpu_set_t) * 8); i++)
+  {
+    if (CPU_ISSET(i, &cpu_set))
+    {
+      cpu_count++;
+    }
+  }
+
+  return cpu_count;
+
+# endif
+#endif
+
+  /* the system with one cpu at least */
+  return 1;
+} /* ms_get_cpu_count */
+
+
+/**
+ * used to get the configure type based on the type string read
+ * from the configuration file.
+ *
+ * @param line, string of one line
+ *
+ * @return ms_conf_type_t
+ */
+ms_conf_type_t ms_get_conf_type(char *line)
+{
+  if (! memcmp(line, "key", strlen("key")))
+  {
+    return CONF_KEY;
+  }
+  else if (! memcmp(line, "value", strlen("value")))
+  {
+    return CONF_VALUE;
+  }
+  else if (! memcmp(line, "cmd", strlen("cmd")))
+  {
+    return CONF_CMD;
+  }
+  else
+  {
+    return CONF_NULL;
+  }
+} /* ms_get_conf_type */
+
+
+/**
+ * judge whether the line is a line with useful data. used to
+ * parse the configuration file.
+ *
+ * @param line, string of one line
+ *
+ * @return if success, return 1, else return 0
+ */
+static int ms_is_line_data(char *line)
+{
+  assert(line != NULL);
+
+  char *begin_ptr= line;
+
+  while (isspace(*begin_ptr))
+  {
+    begin_ptr++;
+  }
+  if ((begin_ptr[0] == '\0') || (begin_ptr[0] == '#'))
+    return 0;
+
+  return 1;
+} /* ms_is_line_data */
+
+
+/**
+ * function to bypass blank line and comments
+ *
+ * @param line, string of one line
+ * @param nread, length of the line
+ *
+ * @return if it's EOF or not line data, return 0, else return 1
+ */
+static int ms_read_is_data(char *line, ssize_t nread)
+{
+  if ((nread == EOF) || ! ms_is_line_data(line))
+    return 0;
+
+  return 1;
+} /* ms_read_is_data */
+
+
+/**
+ *  if no configuration file, use this function to create the default
+ *  configuration file.
+ */
+static void ms_no_config_file()
+{
+  char userpath[PATH_MAX];
+  struct passwd *usr= NULL;
+  FILE *fd;
+
+  usr= getpwuid(getuid());
+
+  snprintf(userpath, PATH_MAX, "%s/%s", usr->pw_dir, DEFAULT_CONFIG_NAME);
+
+  if (access (userpath, F_OK | R_OK) == 0)
+    goto exit;
+
+  fd= fopen(userpath, "w+");
+
+  if (fd == NULL)
+  {
+    fprintf(stderr, "Could not create default configure file %s\n", userpath);
+    perror(strerror(errno));
+    exit(1);
+  }
+  fprintf(fd, "%s", DEFAULT_CONGIF_STR);
+  fclose(fd);
+
+exit:
+  ms_setting.cfg_file= strdup(userpath);
+} /* ms_no_config_file */
+
+
+/**
+ * parse the configuration file
+ *
+ * @param cfg_file, the configuration file name
+ */
+static void ms_parse_cfg_file(char *cfg_file)
+{
+  FILE *f;
+  size_t start_len, end_len;
+  double proportion;
+  size_t frequence;
+  char *line= NULL;
+  size_t  read_len;
+  ssize_t nread;
+  int cmd_type;
+  ms_conf_type_t conf_type;
+  int end_of_file= 0;
+  ms_key_distr_t *key_distr= NULL;
+  ms_value_distr_t *val_distr= NULL;
+
+  if (cfg_file == NULL)
+  {
+    ms_no_config_file();
+    cfg_file= ms_setting.cfg_file;
+  }
+
+  /*read key value configure file*/
+  if ((f= fopen(cfg_file, "r")) == NULL)
+  {
+    fprintf(stderr, "Can not open file: '%s'.\n", cfg_file);
+    exit(1);
+  }
+
+  while (1)
+  {
+    if ((((nread= getline(&line, &read_len, f)) == 1)
+         || ! ms_read_is_data(line, nread)) && (nread != EOF)) /* bypass blank line */
+      continue;
+
+    if (nread == EOF)
+    {
+      fprintf(stderr, "Bad configuration file, no configuration find.\n");
+      exit(1);
+    }
+    conf_type= ms_get_conf_type(line);
+    break;
+  }
+
+  while (! end_of_file)
+  {
+    switch (conf_type)
+    {
+    case CONF_KEY:
+      while (1)
+      {
+        if ((((nread= getline(&line, &read_len, f)) == 1)
+             || ! ms_read_is_data(line, nread)) && (nread != EOF))     /* bypass blank line */
+          continue;
+
+        if (nread != EOF)
+        {
+          if (sscanf(line, "%zu %zu %lf ", &start_len,
+                     &end_len, &proportion) != 3)
+          {
+            conf_type= ms_get_conf_type(line);
+            break;
+          }
+          ms_setting.key_distr[ms_setting.key_rng_cnt].start_len= start_len;
+          ms_setting.key_distr[ms_setting.key_rng_cnt].end_len= end_len;
+          ms_setting.key_distr[ms_setting.key_rng_cnt].key_prop= proportion;
+          ms_setting.key_rng_cnt++;
+
+          if (ms_setting.key_rng_cnt >= ms_setting.total_key_rng_cnt)
+          {
+            key_distr= (ms_key_distr_t *)realloc(
+              ms_setting.key_distr,
+              (size_t)ms_setting.
+                 total_key_rng_cnt * sizeof(ms_key_distr_t) * 2);
+            if (key_distr == NULL)
+            {
+              fprintf(stderr,
+                      "Can't reallocate key distribution structure.\n");
+              exit(1);
+            }
+            ms_setting.key_distr= key_distr;
+            ms_setting.total_key_rng_cnt*= 2;
+          }
+          continue;
+        }
+        end_of_file= 1;
+        break;
+      }
+      break;
+
+    case CONF_VALUE:
+      while (1)
+      {
+        if ((((nread= getline(&line, &read_len, f)) == 1)
+             || ! ms_read_is_data(line, nread)) && (nread != EOF))     /* bypass blank line */
+          continue;
+
+        if (nread != EOF)
+        {
+          if (sscanf(line, "%zu %zu %lf %zu", &start_len, &end_len,
+                     &proportion, &frequence) != 3)
+          {
+            conf_type= ms_get_conf_type(line);
+            break;
+          }
+          ms_setting.value_distr[ms_setting.val_rng_cnt].start_len=
+            start_len;
+          ms_setting.value_distr[ms_setting.val_rng_cnt].end_len= end_len;
+          ms_setting.value_distr[ms_setting.val_rng_cnt].value_prop=
+            proportion;
+          ms_setting.val_rng_cnt++;
+
+          if (ms_setting.val_rng_cnt >= ms_setting.total_val_rng_cnt)
+          {
+            val_distr= (ms_value_distr_t *)realloc(
+              ms_setting.value_distr,
+              (size_t)ms_setting.
+                 total_val_rng_cnt * sizeof(ms_value_distr_t) * 2);
+            if (val_distr == NULL)
+            {
+              fprintf(stderr,
+                      "Can't reallocate key distribution structure.\n");
+              exit(1);
+            }
+            ms_setting.value_distr= val_distr;
+            ms_setting.total_val_rng_cnt*= 2;
+          }
+          continue;
+        }
+        end_of_file= 1;
+        break;
+      }
+      break;
+
+    case CONF_CMD:
+      while (1)
+      {
+        if ((((nread= getline(&line, &read_len, f)) == 1)
+             || ! ms_read_is_data(line, nread)) && (nread != EOF))     /* bypass blank line */
+          continue;
+
+        if (nread != EOF)
+        {
+          if (sscanf(line, "%d %lf\n", &cmd_type, &proportion) != 2)
+          {
+            conf_type= ms_get_conf_type(line);
+            break;
+          }
+          ms_setting.cmd_distr[ms_setting.cmd_used_count].cmd_type=
+            cmd_type;
+          ms_setting.cmd_distr[ms_setting.cmd_used_count].cmd_prop=
+            proportion;
+          ms_setting.cmd_used_count++;
+          continue;
+        }
+        end_of_file= 1;
+        break;
+      }
+
+    case CONF_NULL:
+      while (1)
+      {
+        if ((((nread= getline(&line, &read_len, f)) == 1)
+             || ! ms_read_is_data(line, nread)) && (nread != EOF))     /* bypass blank line */
+          continue;
+
+        if (nread != EOF)
+        {
+          if ((conf_type= ms_get_conf_type(line)) != CONF_NULL)
+          {
+            break;
+          }
+          continue;
+        }
+        end_of_file= 1;
+        break;
+      }
+      break;
+
+    default:
+      assert(0);
+      break;
+    } /* switch */
+  }
+
+  fclose(f);
+
+  if (line != NULL)
+  {
+    free(line);
+  }
+} /* ms_parse_cfg_file */
+
+
+/* calculate the average size of key and value */
+static void ms_calc_avg_size()
+{
+  double avg_val_size= 0.0;
+  double avg_key_size= 0.0;
+  double val_pro= 0.0;
+  double key_pro= 0.0;
+  double averge_len= 0.0;
+  size_t start_len= 0;
+  size_t end_len= 0;
+
+  for (int j= 0; j < ms_setting.val_rng_cnt; j++)
+  {
+    val_pro= ms_setting.value_distr[j].value_prop;
+    start_len= ms_setting.value_distr[j].start_len;
+    end_len= ms_setting.value_distr[j].end_len;
+
+    averge_len= val_pro * ((double)(start_len + end_len)) / 2;
+    avg_val_size+= averge_len;
+  }
+
+  for (int j= 0; j < ms_setting.key_rng_cnt; j++)
+  {
+    key_pro= ms_setting.key_distr[j].key_prop;
+    start_len= ms_setting.key_distr[j].start_len;
+    end_len= ms_setting.key_distr[j].end_len;
+
+    averge_len= key_pro * ((double)(start_len + end_len)) / 2;
+    avg_key_size+= averge_len;
+  }
+
+  ms_setting.avg_val_size= (size_t)avg_val_size;
+  ms_setting.avg_key_size= (size_t)avg_key_size;
+} /* ms_calc_avg_size */
+
+
+/**
+ * used to shuffle key and value distribution array to ensure
+ * (key, value) pair with different set.
+ *
+ * @param distr, pointer of distribution structure array
+ * @param length, length of the array
+ *
+ * @return always return 0
+ */
+static int ms_shuffle_distr(ms_distr_t *distr, int length)
+{
+  int i, j;
+  int tmp_offset;
+  size_t  tmp_size;
+  int64_t rnd;
+
+  for (i= 0; i < length; i++)
+  {
+    rnd= random();
+    j= (int)(rnd % (length - i)) + i;
+
+    switch (rnd % 3)
+    {
+    case 0:
+      tmp_size= distr[j].key_size;
+      distr[j].key_size= distr[i].key_size;
+      distr[i].key_size= tmp_size;
+      break;
+
+    case 1:
+      tmp_offset= distr[j].key_offset;
+      distr[j].key_offset= distr[i].key_offset;
+      distr[i].key_offset= tmp_offset;
+      break;
+
+    case 2:
+      tmp_size= distr[j].value_size;
+      distr[j].value_size= distr[i].value_size;
+      distr[i].value_size= tmp_size;
+      break;
+
+    default:
+      break;
+    } /* switch */
+  }
+
+  return 0;
+} /* ms_shuffle_distr */
+
+
+/**
+ * according to the key and value distribution, to build the
+ * (key, value) pair distribution. the (key, value) pair
+ * distribution array is global, each connection set or get
+ * object keeping this distribution, for the final result, we
+ * can reach the expected key and value distribution.
+ */
+static void ms_build_distr()
+{
+  int offset= 0;
+  int end= 0;
+  int key_cnt= 0;
+  int value_cnt= 0;
+  size_t average_len= 0;
+  size_t diff_len= 0;
+  size_t start_len= 0;
+  size_t end_len= 0;
+  int rnd= 0;
+  ms_distr_t *distr= NULL;
+  int units= (int)ms_setting.win_size / UNIT_ITEMS_COUNT;
+
+  /* calculate average value size and key size */
+  ms_calc_avg_size();
+
+  ms_setting.char_blk_size= RAND_CHAR_SIZE;
+  int key_scope_size=
+    (int)((ms_setting.char_blk_size - RESERVED_RAND_CHAR_SIZE)
+          / UNIT_ITEMS_COUNT);
+
+  ms_setting.distr= (ms_distr_t *)malloc(
+    sizeof(ms_distr_t) * ms_setting.win_size);
+  if (ms_setting.distr == NULL)
+  {
+    fprintf(stderr, "Can't allocate distribution array.");
+    exit(1);
+  }
+
+  /**
+   *  character block is divided by how many different key
+   *  size, each different key size has the same size character
+   *  range.
+   */
+  for (int m= 0; m < units; m++)
+  {
+    for (int i= 0; i < UNIT_ITEMS_COUNT; i++)
+    {
+      ms_setting.distr[m * UNIT_ITEMS_COUNT + i].key_offset=
+        ADDR_ALIGN(key_scope_size * i);
+    }
+  }
+
+  /* initialize key size distribution */
+  for (int m= 0; m < units; m++)
+  {
+    for (int j= 0; j < ms_setting.key_rng_cnt; j++)
+    {
+      key_cnt= (int)(UNIT_ITEMS_COUNT * ms_setting.key_distr[j].key_prop);
+      start_len= ms_setting.key_distr[j].start_len;
+      end_len= ms_setting.key_distr[j].end_len;
+      if ((start_len < MIN_KEY_SIZE) || (end_len < MIN_KEY_SIZE))
+      {
+        fprintf(stderr, "key length must be greater than 16 bytes.\n");
+        exit(1);
+      }
+
+      if (! ms_setting.binary_prot
+          && ((start_len > MAX_KEY_SIZE) || (end_len > MAX_KEY_SIZE)))
+      {
+        fprintf(stderr, "key length must be less than 250 bytes.\n");
+        exit(1);
+      }
+
+      average_len= (start_len + end_len) / 2;
+      diff_len= (end_len - start_len) / 2;
+      for (int k= 0; k < key_cnt; k++)
+      {
+        if (offset >= (m + 1) * UNIT_ITEMS_COUNT)
+        {
+          break;
+        }
+        rnd= (int)random();
+        if (k % 2 == 0)
+        {
+          ms_setting.distr[offset].key_size=
+            (diff_len == 0) ? average_len :
+            average_len + (size_t)rnd
+            % diff_len;
+        }
+        else
+        {
+          ms_setting.distr[offset].key_size=
+            (diff_len == 0) ? average_len :
+            average_len - (size_t)rnd
+            % diff_len;
+        }
+        offset++;
+      }
+    }
+
+    if (offset < (m + 1) * UNIT_ITEMS_COUNT)
+    {
+      end= (m + 1) * UNIT_ITEMS_COUNT - offset;
+      for (int i= 0; i < end; i++)
+      {
+        ms_setting.distr[offset].key_size= ms_setting.avg_key_size;
+        offset++;
+      }
+    }
+  }
+  offset= 0;
+
+  /* initialize value distribution */
+  if (ms_setting.fixed_value_size != 0)
+  {
+    for (int i= 0; i < units * UNIT_ITEMS_COUNT; i++)
+    {
+      ms_setting.distr[i].value_size= ms_setting.fixed_value_size;
+    }
+  }
+  else
+  {
+    for (int m= 0; m < units; m++)
+    {
+      for (int j= 0; j < ms_setting.val_rng_cnt; j++)
+      {
+        value_cnt=
+          (int)(UNIT_ITEMS_COUNT * ms_setting.value_distr[j].value_prop);
+        start_len= ms_setting.value_distr[j].start_len;
+        end_len= ms_setting.value_distr[j].end_len;
+        if ((start_len <= 0) || (end_len <= 0))
+        {
+          fprintf(stderr, "value length must be greater than 0 bytes.\n");
+          exit(1);
+        }
+
+        if ((start_len > MAX_VALUE_SIZE) || (end_len > MAX_VALUE_SIZE))
+        {
+          fprintf(stderr, "key length must be less than or equal to 1M.\n");
+          exit(1);
+        }
+
+        average_len= (start_len + end_len) / 2;
+        diff_len= (end_len - start_len) / 2;
+        for (int k= 0; k < value_cnt; k++)
+        {
+          if (offset >= (m + 1) * UNIT_ITEMS_COUNT)
+          {
+            break;
+          }
+          rnd= (int)random();
+          if (k % 2 == 0)
+          {
+            ms_setting.distr[offset].value_size=
+              (diff_len == 0) ? average_len :
+              average_len
+              + (size_t)rnd % diff_len;
+          }
+          else
+          {
+            ms_setting.distr[offset].value_size=
+              (diff_len == 0) ? average_len :
+              average_len
+              - (size_t)rnd % diff_len;
+          }
+          offset++;
+        }
+      }
+
+      if (offset < (m + 1) * UNIT_ITEMS_COUNT)
+      {
+        end= (m + 1) * UNIT_ITEMS_COUNT - offset;
+        for (int i= 0; i < end; i++)
+        {
+          ms_setting.distr[offset++].value_size= ms_setting.avg_val_size;
+        }
+      }
+    }
+  }
+
+  /* shuffle distribution */
+  for (int i= 0; i < units; i++)
+  {
+    distr= &ms_setting.distr[i * UNIT_ITEMS_COUNT];
+    for (int j= 0; j < 4; j++)
+    {
+      ms_shuffle_distr(distr, UNIT_ITEMS_COUNT);
+    }
+  }
+} /* ms_build_distr */
+
+
+/**
+ * used to initialize the global character block. The character
+ * block is used to generate the suffix of the key and value. we
+ * only store a pointer in the character block for each key
+ * suffix or value string. It can save much memory to store key
+ * or value string.
+ */
+static void ms_init_random_block()
+{
+  char *ptr= NULL;
+
+  assert(ms_setting.char_blk_size > 0);
+
+  ms_setting.char_block= (char *)malloc(ms_setting.char_blk_size);
+  if (ms_setting.char_block == NULL)
+  {
+    fprintf(stderr, "Can't allocate global char block.");
+    exit(1);
+  }
+  ptr= ms_setting.char_block;
+
+  for (int i= 0; (size_t)i < ms_setting.char_blk_size; i++)
+  {
+    *(ptr++)= ALPHANUMBERICS[random() % CHAR_COUNT];
+  }
+} /* ms_init_random_block */
+
+
+/**
+ * after initialization, call this function to output the main
+ * configuration user specified.
+ */
+static void ms_print_setting()
+{
+  fprintf(stdout, "servers : %s\n", ms_setting.srv_str);
+  fprintf(stdout, "threads count: %d\n", ms_setting.nthreads);
+  fprintf(stdout, "concurrency: %d\n", ms_setting.nconns);
+  if (ms_setting.run_time > 0)
+  {
+    fprintf(stdout, "run time: %ds\n", ms_setting.run_time);
+  }
+  else
+  {
+    fprintf(stdout, "execute number: %" PRId64 "\n", ms_setting.exec_num);
+  }
+  fprintf(stdout, "windows size: %" PRId64 "k\n",
+          (int64_t)(ms_setting.win_size / 1024));
+  fprintf(stdout, "set proportion: set_prop=%.2f\n",
+          ms_setting.cmd_distr[CMD_SET].cmd_prop);
+  fprintf(stdout, "get proportion: get_prop=%.2f\n",
+          ms_setting.cmd_distr[CMD_GET].cmd_prop);
+  fflush(stdout);
+} /* ms_print_setting */
+
+
+/**
+ * previous part of slap mode initialization of setting structure
+ */
+static void ms_setting_slapmode_init_pre()
+{
+  ms_setting.exec_num= DEFAULT_EXE_NUM;
+  ms_setting.verify_percent= DEFAULT_VERIFY_RATE;
+  ms_setting.exp_ver_per= DEFAULT_VERIFY_RATE;
+  ms_setting.overwrite_percent= DEFAULT_OVERWRITE_RATE;
+  ms_setting.mult_key_num= DEFAULT_DIV;
+  ms_setting.fixed_value_size= 0;
+  ms_setting.win_size= DEFAULT_WINDOW_SIZE;
+  ms_setting.udp= false;
+  ms_setting.reconnect= false;
+  ms_setting.verbose= false;
+  ms_setting.facebook_test= false;
+  ms_setting.binary_prot= false;
+  ms_setting.stat_freq= 0;
+  ms_setting.srv_str= NULL;
+  ms_setting.cfg_file= NULL;
+  ms_setting.sock_per_conn= DEFAULT_SOCK_PER_CONN;
+  ms_setting.expected_tps= 0;
+  ms_setting.rep_write_srv= 0;
+} /* ms_setting_slapmode_init_pre */
+
+
+/**
+ * previous part of initialization of setting structure
+ */
+void ms_setting_init_pre()
+{
+  memset(&ms_setting, 0, sizeof(ms_setting));
+
+  /* common initialize */
+  ms_setting.ncpu= ms_get_cpu_count();
+  ms_setting.nthreads= DEFAULT_THREADS_NUM;
+  ms_setting.nconns= DEFAULT_CONNS_NUM;
+  ms_setting.run_time= DEFAULT_RUN_TIME;
+  ms_setting.total_srv_cnt= MCD_SRVS_NUM_INIT;
+  ms_setting.servers= (ms_mcd_server_t *)malloc(
+    (size_t)ms_setting.total_srv_cnt
+    * sizeof(ms_mcd_server_t));
+  if (ms_setting.servers == NULL)
+  {
+    fprintf(stderr, "Can't allocate servers structure.\n");
+    exit(1);
+  }
+
+  ms_setting_slapmode_init_pre();
+} /* ms_setting_init_pre */
+
+
+/**
+ * post part of slap mode initialization of setting structure
+ */
+static void ms_setting_slapmode_init_post()
+{
+  ms_setting.total_key_rng_cnt= KEY_RANGE_COUNT_INIT;
+  ms_setting.key_distr= 
+    (ms_key_distr_t *)malloc((size_t)ms_setting.total_key_rng_cnt * sizeof(ms_key_distr_t));
+
+  if (ms_setting.key_distr == NULL)
+  {
+    fprintf(stderr, "Can't allocate key distribution structure.\n");
+    exit(1);
+  }
+
+  ms_setting.total_val_rng_cnt= VALUE_RANGE_COUNT_INIT;
+
+  ms_setting.value_distr= 
+    (ms_value_distr_t *)malloc((size_t)ms_setting.total_val_rng_cnt * sizeof( ms_value_distr_t));
+
+  if (ms_setting.value_distr == NULL)
+  {
+    fprintf(stderr, "Can't allocate value distribution structure.\n");
+    exit(1);
+  }
+
+  ms_parse_cfg_file(ms_setting.cfg_file);
+
+  /* run time mode */
+  if ((ms_setting.exec_num == 0) && (ms_setting.run_time != 0))
+  {
+    ms_setting.exec_num= (int64_t)MAX_EXEC_NUM;
+  }
+  else
+  {
+    /* execute number mode */
+    ms_setting.run_time= 0;
+  }
+
+  if (ms_setting.rep_write_srv > 0)
+  {
+    /* for replication test, need enable reconnect feature */
+    ms_setting.reconnect= true;
+  }
+
+  if (ms_setting.facebook_test && (ms_setting.mult_key_num < 2))
+  {
+    fprintf(stderr, "facebook test must work with multi-get, "
+                    "please specify multi-get key number "
+                    "with '--division' option.\n");
+    exit(1);
+  }
+
+  if (ms_setting.facebook_test && ms_setting.udp)
+  {
+    fprintf(stderr, "facebook test couldn't work with UDP.\n");
+    exit(1);
+  }
+
+  if (ms_setting.udp && (ms_setting.sock_per_conn > 1))
+  {
+    fprintf(stderr, "UDP doesn't support multi-socks "
+                    "in one connection structure.\n");
+    exit(1);
+  }
+
+  if ((ms_setting.udp
+       || ms_setting.facebook_test) && ms_setting.binary_prot)
+  {
+    fprintf(stderr, "Binary protocol doesn't support UDP now.\n");
+    exit(1);
+  }
+
+  if ((ms_setting.rep_write_srv > 0) && (ms_setting.srv_cnt < 2))
+  {
+    fprintf(stderr, "Please specify 2 servers at least for replication\n");
+    exit(1);
+  }
+
+  if ((ms_setting.rep_write_srv > 0)
+      && (ms_setting.srv_cnt < ms_setting.rep_write_srv))
+  {
+    fprintf(stderr, "Servers to do replication writing "
+                    "is larger than the total servers\n");
+    exit(1);
+  }
+
+  if (ms_setting.udp && (ms_setting.rep_write_srv > 0))
+  {
+    fprintf(stderr, "UDP doesn't support replication.\n");
+    exit(1);
+  }
+
+  if ((ms_setting.rep_write_srv > 0) && (ms_setting.sock_per_conn > 1))
+  {
+    fprintf(stderr, "Replication doesn't support multi-socks "
+                    "in one connection structure.\n");
+    exit(1);
+  }
+
+  if (ms_setting.facebook_test && (ms_setting.rep_write_srv > 0))
+  {
+    fprintf(stderr, "facebook test couldn't work with replication.\n");
+    exit(1);
+  }
+
+  if (ms_setting.reconnect && (ms_setting.sock_per_conn > 1))
+  {
+    fprintf(stderr, "Reconnection doesn't support multi-socks "
+                    "in one connection structure.\n");
+    exit(1);
+  }
+
+  ms_build_distr();
+
+  /* initialize global character block */
+  ms_init_random_block();
+  ms_print_setting();
+} /* ms_setting_slapmode_init_post */
+
+
+/**
+ * post part of initialization of setting structure
+ */
+void ms_setting_init_post()
+{
+  ms_get_serverlist(ms_setting.srv_str);
+  ms_setting_slapmode_init_post();
+}
+
+
+/**
+ * clean up the global setting structure
+ */
+void ms_setting_cleanup()
+{
+  if (ms_setting.distr != NULL)
+  {
+    free(ms_setting.distr);
+  }
+
+  if (ms_setting.char_block != NULL)
+  {
+    free(ms_setting.char_block);
+  }
+
+  if (ms_setting.srv_str != NULL)
+  {
+    free(ms_setting.srv_str);
+  }
+
+  if (ms_setting.cfg_file != NULL)
+  {
+    free(ms_setting.cfg_file);
+  }
+
+  if (ms_setting.servers != NULL)
+  {
+    free(ms_setting.servers);
+  }
+
+  if (ms_setting.key_distr != NULL)
+  {
+    free(ms_setting.key_distr);
+  }
+
+  if (ms_setting.value_distr != NULL)
+  {
+    free(ms_setting.value_distr);
+  }
+} /* ms_setting_cleanup */
diff --git a/clients/ms_setting.h b/clients/ms_setting.h
new file mode 100644 (file)
index 0000000..f558dd3
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * File:   ms_setting.h
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+#ifndef MS_SETTING_H
+#define MS_SETTING_H
+
+#include "ms_memslap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MCD_SRVS_NUM_INIT         8
+#define MCD_HOST_LENGTH           64
+#define KEY_RANGE_COUNT_INIT      8
+#define VALUE_RANGE_COUNT_INIT    8
+#define PROP_ERROR                0.001
+
+#define MIN_KEY_SIZE              16
+#define MAX_KEY_SIZE              250
+#define MAX_VALUE_SIZE            (1024 * 1024)
+
+/* the content of the configuration file for memslap running without configuration file */
+#define DEFAULT_CONGIF_STR \
+  "key\n"                  \
+  "64 64 1\n"              \
+  "value\n"                \
+  "1024 1024 1\n"          \
+  "cmd\n"                  \
+  "0 0.1\n"                \
+  "1 0.9"
+
+/* Used to parse the value length return by server and path string */
+typedef struct token_s
+{
+  char *value;
+  size_t length;
+} token_t;
+
+#define MAX_TOKENS    10
+
+/* server information */
+typedef struct mcd_sever
+{
+  char srv_host_name[MCD_HOST_LENGTH];              /* host name of server */
+  int srv_port;                                     /* server port */
+
+  /* for calculating how long the server disconnects */
+  volatile uint32_t disconn_cnt;                    /* number of disconnections count */
+  volatile uint32_t reconn_cnt;                     /* number of reconnections count */
+  struct timeval disconn_time;                      /* start time of disconnection */
+  struct timeval reconn_time;                       /* end time of reconnection */
+} ms_mcd_server_t;
+
+/* information of an item distribution including key and value */
+typedef struct distr
+{
+  size_t key_size;                  /* size of key */
+  int key_offset;                   /* offset of one key in character block */
+  size_t value_size;                /* size of value */
+} ms_distr_t;
+
+/* information of key distribution */
+typedef struct key_distr
+{
+  size_t start_len;                 /* start of the key length range */
+  size_t end_len;                   /* end of the key length range */
+  double key_prop;                  /* key proportion */
+} ms_key_distr_t;
+
+/* information of value distribution */
+typedef struct value_distr
+{
+  size_t start_len;                 /* start of the value length range */
+  size_t end_len;                   /* end of the value length range */
+  double value_prop;                /* value proportion */
+} ms_value_distr_t;
+
+/* memcached command types */
+typedef enum cmd_type
+{
+  CMD_SET,
+  CMD_GET,
+  CMD_NULL,
+} ms_cmd_type_t;
+
+/* types in the configuration file */
+typedef enum conf_type
+{
+  CONF_KEY,
+  CONF_VALUE,
+  CONF_CMD,
+  CONF_NULL,
+} ms_conf_type_t;
+
+/* information of command distribution */
+typedef struct cmd_distr
+{
+  ms_cmd_type_t cmd_type;               /* command type */
+  double cmd_prop;                      /* proportion of the command */
+} ms_cmd_distr_t;
+
+/* global setting structure */
+typedef struct setting
+{
+  int ncpu;                             /* cpu count of this system */
+  int nthreads;                         /* total thread count, must equal or less than cpu cores */
+  uint32_t nconns;                      /* total conn count, must multiply by total thread count */
+  int64_t exec_num;                     /* total execute number */
+  int run_time;                         /* total run time */
+
+  uint32_t char_blk_size;               /* global character block size */
+  char *char_block;                     /* global character block with random character */
+  ms_distr_t *distr;                    /* distribution from configure file */
+
+  char *srv_str;                        /* string includes servers information */
+  char *cfg_file;                       /* configure file name */
+
+  ms_mcd_server_t *servers;             /* servers array */
+  int total_srv_cnt;                    /* total servers count of the servers array */
+  int srv_cnt;                          /* servers count */
+
+  ms_key_distr_t *key_distr;            /* array of key distribution */
+  int total_key_rng_cnt;                /* total key range count of the array */
+  int key_rng_cnt;                      /* actual key range count */
+
+  ms_value_distr_t *value_distr;        /* array of value distribution */
+  int total_val_rng_cnt;                /* total value range count of the array */
+  int val_rng_cnt;                      /* actual value range count */
+
+  ms_cmd_distr_t cmd_distr[CMD_NULL];   /* total we have CMD_NULL commands */
+  int cmd_used_count;                   /* supported command count */
+
+  size_t fixed_value_size;              /* fixed value size */
+  size_t avg_val_size;                  /* average value size */
+  size_t avg_key_size;                  /* average value size */
+
+  double verify_percent;                /* percent of data verification */
+  double exp_ver_per;                   /* percent of data verification with expire time */
+  double overwrite_percent;             /* percent of overwrite */
+  int mult_key_num;                     /* number of keys used by multi-get once */
+  size_t win_size;                      /* item window size per connection */
+  bool udp;                             /* whether or not use UDP */
+  int stat_freq;                        /* statistic frequency second */
+  bool reconnect;                       /* whether it reconnect when connection close */
+  bool verbose;                         /* whether it outputs detailed information when verification */
+  bool facebook_test;                   /* facebook test, TCP set and multi-get with UDP */
+  int sock_per_conn;                    /* number of socks per connection structure */
+  bool binary_prot;                     /* whether it use binary protocol */
+  int expected_tps;                     /* expected throughput */
+  int rep_write_srv;                    /* which servers are used to do replication writing */
+} ms_setting_st;
+
+extern ms_setting_st ms_setting;
+
+/* previous part of initialization of setting structure */
+void ms_setting_init_pre(void);
+
+
+/* post part of initialization of setting structure */
+void ms_setting_init_post(void);
+
+
+/* clean up the global setting structure */
+void ms_setting_cleanup(void);
+
+
+#define UNUSED_ARGUMENT(x)    (void)x
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of MS_SETTING_H */
diff --git a/clients/ms_sigsegv.c b/clients/ms_sigsegv.c
new file mode 100644 (file)
index 0000000..33029b4
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * File:   ms_sigsegv.c
+ * Author: Mingqiang Zhuang
+ *
+ * Created on March 15, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ * Rewrite of stack dump:
+ *  Copyright (C) 2009 Sun Microsystems
+ *  Author Trond Norbye
+ */
+
+#include "config.h"
+
+#include <memory.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <pthread.h>
+
+#include "ms_memslap.h"
+#include "ms_setting.h"
+
+/* prototypes */
+int ms_setup_sigsegv(void);
+int ms_setup_sigpipe(void);
+int ms_setup_sigint(void);
+
+
+/* signal seg reaches, this function will run */
+static void ms_signal_segv(int signum, siginfo_t *info, void *ptr)
+{
+  UNUSED_ARGUMENT(signum);
+  UNUSED_ARGUMENT(info);
+  UNUSED_ARGUMENT(ptr);
+
+  pthread_mutex_lock(&ms_global.quit_mutex);
+  fprintf(stderr, "Segmentation fault occurred.\nStack trace:\n");
+  pandora_print_callstack(stderr);
+  fprintf(stderr, "End of stack trace\n");
+  pthread_mutex_unlock(&ms_global.quit_mutex);
+  abort();
+}
+
+/* signal pipe reaches, this function will run */
+static void ms_signal_pipe(int signum, siginfo_t *info, void *ptr)
+{
+  UNUSED_ARGUMENT(signum);
+  UNUSED_ARGUMENT(info);
+  UNUSED_ARGUMENT(ptr);
+
+  pthread_mutex_lock(&ms_global.quit_mutex);
+  fprintf(stderr, "\tMemslap encountered a server error. Quitting...\n");
+  fprintf(stderr, "\tError info: SIGPIPE captured (from write?)\n");
+  fprintf(stderr,
+          "\tProbably a socket I/O error when the server is down.\n");
+  pthread_mutex_unlock(&ms_global.quit_mutex);
+  exit(1);
+} /* ms_signal_pipe */
+
+
+/* signal int reaches, this function will run */
+static void ms_signal_int(int signum, siginfo_t *info, void *ptr)
+{
+  UNUSED_ARGUMENT(signum);
+  UNUSED_ARGUMENT(info);
+  UNUSED_ARGUMENT(ptr);
+
+  pthread_mutex_lock(&ms_global.quit_mutex);
+  fprintf(stderr, "SIGINT handled.\n");
+  pthread_mutex_unlock(&ms_global.quit_mutex);
+  exit(1);
+} /* ms_signal_int */
+
+
+/**
+ * redirect signal seg
+ *
+ * @return if success, return 0, else return -1
+ */
+int ms_setup_sigsegv(void)
+{
+  struct sigaction action;
+
+  memset(&action, 0, sizeof(action));
+  action.sa_sigaction= ms_signal_segv;
+  action.sa_flags= SA_SIGINFO;
+  if (sigaction(SIGSEGV, &action, NULL) < 0)
+  {
+    perror("sigaction");
+    return 0;
+  }
+
+  return -1;
+} /* ms_setup_sigsegv */
+
+
+/**
+ * redirect signal pipe
+ *
+ * @return if success, return 0, else return -1
+ */
+int ms_setup_sigpipe(void)
+{
+  struct sigaction action_2;
+
+  memset(&action_2, 0, sizeof(action_2));
+  action_2.sa_sigaction= ms_signal_pipe;
+  action_2.sa_flags= SA_SIGINFO;
+  if (sigaction(SIGPIPE, &action_2, NULL) < 0)
+  {
+    perror("sigaction");
+    return 0;
+  }
+
+  return -1;
+} /* ms_setup_sigpipe */
+
+
+/**
+ * redirect signal int
+ *
+ * @return if success, return 0, else return -1
+ */
+int ms_setup_sigint(void)
+{
+  struct sigaction action_3;
+
+  memset(&action_3, 0, sizeof(action_3));
+  action_3.sa_sigaction= ms_signal_int;
+  action_3.sa_flags= SA_SIGINFO;
+  if (sigaction(SIGINT, &action_3, NULL) < 0)
+  {
+    perror("sigaction");
+    return 0;
+  }
+
+  return -1;
+} /* ms_setup_sigint */
+
+
+#ifndef SIGSEGV_NO_AUTO_INIT
+static void __attribute((constructor)) ms_init(void)
+{
+  ms_setup_sigsegv();
+  ms_setup_sigpipe();
+  ms_setup_sigint();
+}
+#endif
diff --git a/clients/ms_sigsegv.h b/clients/ms_sigsegv.h
new file mode 100644 (file)
index 0000000..7990ff6
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * File:   ms_sigsegv.h
+ * Author: Mingqiang Zhuang
+ *
+ * Created on March 15, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+#ifndef MS_SIGSEGV_H
+#define MS_SIGSEGV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* redirect signal seg */
+int ms_setup_sigsegv(void);
+
+
+/* redirect signal pipe */
+int ms_setup_sigpipe(void);
+
+
+/* redirect signal int */
+int ms_setup_sigint(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of MS_SIGSEGV_H */
diff --git a/clients/ms_stats.c b/clients/ms_stats.c
new file mode 100644 (file)
index 0000000..49a5ab6
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * File:   ms_stats.h
+ * Author: Mingqiang Zhuang
+ *
+ * Created on March 25, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+
+#include "config.h"
+
+#include <inttypes.h>
+#include "ms_stats.h"
+
+#define array_size(x)    (sizeof(x) / sizeof((x)[0]))
+
+static int ms_local_log2(uint64_t value);
+static uint64_t ms_get_events(ms_stat_t *stat);
+
+
+/**
+ * get the index of local log2 array
+ *
+ * @param value
+ *
+ * @return return the index of local log2 array
+ */
+static int ms_local_log2(uint64_t value)
+{
+  int result= 0;
+
+  while (result <= 63 && ((uint64_t)1 << result) < value)
+  {
+    result++;
+  }
+
+  return result;
+} /* ms_local_log2 */
+
+
+/**
+ * initialize statistic structure
+ *
+ * @param stat, pointer of the statistic structure
+ * @param name, name of the statistic
+ */
+void ms_init_stats(ms_stat_t *stat, const char *name)
+{
+  memset(stat, 0, sizeof(*stat));
+
+  stat->name= (char *)name;
+  stat->min_time= (uint64_t)-1;
+  stat->max_time= 0;
+  stat->period_min_time= (uint64_t)-1;
+  stat->period_max_time= 0;
+  stat->log_product= 0;
+  stat->total_time= 0;
+  stat->pre_total_time= 0;
+  stat->squares= 0;
+  stat->pre_squares= 0;
+  stat->pre_events= 0;
+  stat->pre_log_product= 0;
+  stat->get_miss= 0;
+  stat->pre_get_miss= 0;
+} /* ms_init_stats */
+
+
+/**
+ * record one event
+ *
+ * @param stat, pointer of the statistic structure
+ * @param total_time, response time of the command
+ * @param get_miss, whether it gets miss
+ */
+void ms_record_event(ms_stat_t *stat, uint64_t total_time, int get_miss)
+{
+  stat->total_time+= total_time;
+
+  if (total_time < stat->min_time)
+  {
+    stat->min_time= total_time;
+  }
+
+  if (total_time > stat->max_time)
+  {
+    stat->max_time= total_time;
+  }
+
+  if (total_time < stat->period_min_time)
+  {
+    stat->period_min_time= total_time;
+  }
+
+  if (total_time > stat->period_max_time)
+  {
+    stat->period_max_time= total_time;
+  }
+
+  if (get_miss)
+  {
+    stat->get_miss++;
+  }
+
+  stat->dist[ms_local_log2(total_time)]++;
+  stat->squares+= (double)(total_time * total_time);
+
+  if (total_time != 0)
+  {
+    stat->log_product+= log((double)total_time);
+  }
+} /* ms_record_event */
+
+
+/**
+ * get the events count
+ *
+ * @param stat, pointer of the statistic structure
+ *
+ * @return total events recorded
+ */
+static uint64_t ms_get_events(ms_stat_t *stat)
+{
+  uint64_t events= 0;
+
+  for (uint32_t i= 0; i < array_size(stat->dist); i++)
+  {
+    events+= stat->dist[i];
+  }
+
+  return events;
+} /* ms_get_events */
+
+
+/**
+ * dump the statistics
+ *
+ * @param stat, pointer of the statistic structure
+ */
+void ms_dump_stats(ms_stat_t *stat)
+{
+  uint64_t events= 0;
+  int max_non_zero= 0;
+  int min_non_zero= 0;
+  double average= 0;
+
+  for (uint32_t i= 0; i < array_size(stat->dist); i++)
+  {
+    events+= stat->dist[i];
+    if (stat->dist[i] != 0)
+    {
+      max_non_zero= (int)i;
+    }
+  }
+
+  if (events == 0)
+  {
+    return;
+  }
+  average= (double)(stat->total_time / events);
+
+  printf("%s Statistics (%lld events)\n", stat->name, (long long)events);
+  printf("   Min:  %8lld\n", (long long)stat->min_time);
+  printf("   Max:  %8lld\n", (long long)stat->max_time);
+  printf("   Avg:  %8lld\n", (long long)(stat->total_time / events));
+  printf("   Geo:  %8.2lf\n", exp(stat->log_product / (double)events));
+
+  if (events > 1)
+  {
+    printf("   Std:  %8.2lf\n",
+           sqrt((stat->squares - (double)events * average
+                 * average) / ((double)events - 1)));
+  }
+  printf("   Log2 Dist:");
+
+  for (int i= 0; i <= max_non_zero - 4; i+= 4)
+  {
+    if ((stat->dist[i + 0] != 0)
+        || (stat->dist[i + 1] != 0)
+        || (stat->dist[i + 2] != 0)
+        || (stat->dist[i + 3] != 0))
+    {
+      min_non_zero= i;
+      break;
+    }
+  }
+
+  for (int i= min_non_zero; i <= max_non_zero; i++)
+  {
+    if ((i % 4) == 0)
+    {
+      printf("\n      %2d:", (int)i);
+    }
+    printf("   %6" PRIu64 , stat->dist[i]);
+  }
+
+  printf("\n\n");
+} /* ms_dump_stats */
+
+
+/**
+ * dump the format statistics
+ *
+ * @param stat, pointer of the statistic structure
+ * @param run_time, the total run time
+ * @param freq, statistic frequency
+ * @param obj_size, average object size
+ */
+void ms_dump_format_stats(ms_stat_t *stat,
+                          int run_time,
+                          int freq,
+                          int obj_size)
+{
+  uint64_t events= 0;
+  double global_average= 0;
+  uint64_t global_tps= 0;
+  double global_rate= 0;
+  double global_std= 0;
+  double global_log= 0;
+
+  uint64_t diff_time= 0;
+  uint64_t diff_events= 0;
+  double diff_squares= 0;
+  double diff_log_product= 0;
+  double period_average= 0;
+  uint64_t period_tps= 0;
+  double period_rate= 0;
+  double period_std= 0;
+  double period_log= 0;
+
+  if ((events= ms_get_events(stat)) == 0)
+  {
+    return;
+  }
+
+  global_average= (double)(stat->total_time / events);
+  global_tps= events / (uint64_t)run_time;
+  global_rate= (double)events * obj_size / 1024 / 1024 / run_time;
+  global_std= sqrt((stat->squares - (double)events * global_average
+                    * global_average) / (double)(events - 1));
+  global_log= exp(stat->log_product / (double)events);
+
+  diff_time= stat->total_time - stat->pre_total_time;
+  diff_events= events - stat->pre_events;
+  if (diff_events >= 1)
+  {
+    period_average= (double)(diff_time / diff_events);
+    period_tps= diff_events / (uint64_t)freq;
+    period_rate= (double)diff_events * obj_size / 1024 / 1024 / freq;
+    diff_squares= (double)stat->squares - (double)stat->pre_squares;
+    period_std= sqrt((diff_squares - (double)diff_events * period_average
+                      * period_average) / (double)(diff_events - 1));
+    diff_log_product= stat->log_product - stat->pre_log_product;
+    period_log= exp(diff_log_product / (double)diff_events);
+  }
+
+  printf("%s Statistics\n", stat->name);
+  printf("%-8s %-8s %-12s %-12s %-10s %-10s %-8s %-10s %-10s %-10s %-10s\n",
+         "Type",
+         "Time(s)",
+         "Ops",
+         "TPS(ops/s)",
+         "Net(M/s)",
+         "Get_miss",
+         "Min(us)",
+         "Max(us)",
+         "Avg(us)",
+         "Std_dev",
+         "Geo_dist");
+
+  printf(
+    "%-8s %-8d %-12llu %-12lld %-10.1f %-10lld %-8lld %-10lld %-10lld %-10.2f %.2f\n",
+    "Period",
+    freq,
+    (long long)diff_events,
+    (long long)period_tps,
+    global_rate,
+    (long long)(stat->get_miss - stat->pre_get_miss),
+    (long long)stat->period_min_time,
+    (long long)stat->period_max_time,
+    (long long)period_average,
+    period_std,
+    period_log);
+
+  printf(
+    "%-8s %-8d %-12llu %-12lld %-10.1f %-10lld %-8lld %-10lld %-10lld %-10.2f %.2f\n\n",
+    "Global",
+    run_time,
+    (long long)events,
+    (long long)global_tps,
+    period_rate,
+    (long long)stat->get_miss,
+    (long long)stat->min_time,
+    (long long)stat->max_time,
+    (long long)global_average,
+    global_std,
+    global_log);
+
+  stat->pre_events= events;
+  stat->pre_squares= (uint64_t)stat->squares;
+  stat->pre_total_time= stat->total_time;
+  stat->pre_log_product= stat->log_product;
+  stat->period_min_time= (uint64_t)-1;
+  stat->period_max_time= 0;
+  stat->pre_get_miss= stat->get_miss;
+} /* ms_dump_format_stats */
diff --git a/clients/ms_stats.h b/clients/ms_stats.h
new file mode 100644 (file)
index 0000000..5ac88b3
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * File:   ms_stats.h
+ * Author: Mingqiang Zhuang
+ *
+ * Created on March 25, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+#ifndef MS_STAT_H
+#define MS_STAT_H
+
+#include <math.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* statistic structure of response time */
+typedef struct
+{
+  char *name;
+  uint64_t total_time;
+  uint64_t min_time;
+  uint64_t max_time;
+  uint64_t get_miss;
+  uint64_t dist[65];
+  double squares;
+  double log_product;
+
+  uint64_t period_min_time;
+  uint64_t period_max_time;
+  uint64_t pre_get_miss;
+  uint64_t pre_events;
+  uint64_t pre_total_time;
+  uint64_t pre_squares;
+  double pre_log_product;
+} ms_stat_t;
+
+/* initialize statistic */
+void ms_init_stats(ms_stat_t *stat, const char *name);
+
+
+/* record one event */
+void ms_record_event(ms_stat_t *stat, uint64_t time, int get_miss);
+
+
+/* dump the statistics */
+void ms_dump_stats(ms_stat_t *stat);
+
+
+/* dump the format statistics */
+void ms_dump_format_stats(ms_stat_t *stat,
+                          int run_time,
+                          int freq,
+                          int obj_size);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* MS_STAT_H */
diff --git a/clients/ms_task.c b/clients/ms_task.c
new file mode 100644 (file)
index 0000000..5fbd7d1
--- /dev/null
@@ -0,0 +1,1116 @@
+/*
+ * File:   ms_task.c
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+
+#include "config.h"
+
+#include <inttypes.h>
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "ms_thread.h"
+#include "ms_setting.h"
+#include "ms_atomic.h"
+
+/* command distribution adjustment cycle */
+#define CMD_DISTR_ADJUST_CYCLE    1000
+#define DISADJUST_FACTOR          0.03 /**
+                                 * In one adjustment cycle, if undo set or get
+                                 * operations proportion is more than 3% , means
+                                 * there are too many new item or need more new
+                                 * item in the window. This factor shows it.
+                                 */
+
+/* get item from task window */
+static ms_task_item_t *ms_get_cur_opt_item(ms_conn_t *c);
+static ms_task_item_t *ms_get_next_get_item(ms_conn_t *c);
+static ms_task_item_t *ms_get_next_set_item(ms_conn_t *c);
+static ms_task_item_t *ms_get_pre_set_item(ms_conn_t *c);
+
+
+/* select next operation to do */
+static void ms_select_opt(ms_conn_t *c, ms_task_t *task);
+
+
+/* set and get speed estimate for controlling and adjustment */
+static bool ms_is_set_too_fast(ms_task_t *task);
+static bool ms_is_get_too_fast(ms_task_t *task);
+static void ms_kick_out_item(ms_task_item_t *item);
+
+
+/* miss rate adjustment */
+static bool ms_need_overwirte_item(ms_task_t *task);
+static bool ms_adjust_opt(ms_conn_t *c, ms_task_t *task);
+
+
+/* deal with data verification initialization */
+static void ms_task_data_verify_init(ms_task_t *task);
+static void ms_task_expire_verify_init(ms_task_t *task);
+
+
+/* select a new task to do */
+static ms_task_t *ms_get_task(ms_conn_t *c, bool warmup);
+
+
+/* run the selected task */
+static void ms_update_set_result(ms_conn_t *c, ms_task_item_t *item);
+static void ms_update_stat_result(ms_conn_t *c);
+static void ms_update_multi_get_result(ms_conn_t *c);
+static void ms_update_single_get_result(ms_conn_t *c, ms_task_item_t *item);
+static void ms_update_task_result(ms_conn_t *c);
+static void ms_single_getset_task_sch(ms_conn_t *c);
+static void ms_multi_getset_task_sch(ms_conn_t *c);
+static void ms_send_signal(ms_sync_lock_t *sync_lock);
+static void ms_warmup_server(ms_conn_t *c);
+static int ms_run_getset_task(ms_conn_t *c);
+
+
+/**
+ * used to get the current operation item(object)
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return ms_task_item_t*, current operating item
+ */
+static ms_task_item_t *ms_get_cur_opt_item(ms_conn_t *c)
+{
+  return c->curr_task.item;
+}
+
+
+/**
+ * used to get the next item to do get operation
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return ms_task_item_t*, the pointer of the next item to do
+ *         get operation
+ */
+static ms_task_item_t *ms_get_next_get_item(ms_conn_t *c)
+{
+  ms_task_item_t *item= NULL;
+
+  if (c->set_cursor <= 0)
+  {
+    /* the first item in the window */
+    item= &c->item_win[0];
+  }
+  else if (c->set_cursor > 0 && c->set_cursor < (uint32_t)c->win_size)
+  {
+    /* random get one item set before */
+    item= &c->item_win[random() % (int64_t)c->set_cursor];
+  }
+  else
+  {
+    /* random get one item from the window */
+    item= &c->item_win[random() % c->win_size];
+  }
+
+  return item;
+} /* ms_get_next_get_item */
+
+
+/**
+ * used to get the next item to do set operation
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return ms_task_item_t*, the pointer of the next item to do
+ *         set operation
+ */
+static ms_task_item_t *ms_get_next_set_item(ms_conn_t *c)
+{
+  /**
+   *  when a set command successes, the cursor will plus 1. If set
+   *  fails, the cursor doesn't change. it isn't necessary to
+   *  increase the cursor here.
+   */
+  return &c->item_win[(int64_t)c->set_cursor % c->win_size];
+}
+
+
+/**
+ * If we need do overwrite, we could select a item set before.
+ * This function is used to get a item set before to do
+ * overwrite.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return ms_task_item_t*, the pointer of the previous item of
+ *         set operation
+ */
+static ms_task_item_t *ms_get_pre_set_item(ms_conn_t *c)
+{
+  if (c->set_cursor <= 0)
+  {
+    return &c->item_win[0];
+  }
+  else
+  {
+    return &c->item_win[(int64_t)-- c->set_cursor % c->win_size];
+  }
+} /* ms_get_pre_set_item */
+
+
+/**
+ * According to the proportion of operations(get or set), select
+ * an operation to do.
+ *
+ * @param c, pointer of the concurrency
+ * @param task, pointer of current task in the concurrency
+ */
+static void ms_select_opt(ms_conn_t *c, ms_task_t *task)
+{
+  double get_prop= ms_setting.cmd_distr[CMD_GET].cmd_prop;
+  double set_prop= ms_setting.cmd_distr[CMD_SET].cmd_prop;
+
+  /* update cycle operation number if necessary */
+  if ((task->cycle_undo_get == 0) || (task->cycle_undo_set == 0))
+  {
+    task->cycle_undo_get+= (int)(CMD_DISTR_ADJUST_CYCLE * get_prop);
+    task->cycle_undo_set+= (int)(CMD_DISTR_ADJUST_CYCLE * set_prop);
+  }
+
+  /**
+   *  According to operation distribution to choose doing which
+   *  operation. If it can't set new object to sever, just change
+   *  to do get operation.
+   */
+  if ((set_prop > PROP_ERROR)
+      && ((double)task->get_opt * set_prop >= (double)task->set_opt
+          * get_prop))
+  {
+    task->cmd= CMD_SET;
+    task->item= ms_get_next_set_item(c);
+  }
+  else
+  {
+    task->cmd= CMD_GET;
+    task->item= ms_get_next_get_item(c);
+  }
+} /* ms_select_opt */
+
+
+/**
+ * used to judge whether the number of get operations done is
+ * more than expected number of get operations to do right now.
+ *
+ * @param task, pointer of current task in the concurrency
+ *
+ * @return bool, if get too fast, return true, else return false
+ */
+static bool ms_is_get_too_fast(ms_task_t *task)
+{
+  double get_prop= ms_setting.cmd_distr[CMD_GET].cmd_prop;
+  double set_prop= ms_setting.cmd_distr[CMD_SET].cmd_prop;
+
+  /* no get operation */
+  if (get_prop < PROP_ERROR)
+  {
+    return false;
+  }
+
+  int max_undo_set= (int)(set_prop / get_prop * (1.0 + DISADJUST_FACTOR))
+                    * task->cycle_undo_get;
+
+  if (((double)task->get_opt * set_prop > (double)task->set_opt * get_prop)
+      && (task->cycle_undo_set > max_undo_set))
+  {
+    return true;
+  }
+
+  return false;
+} /* ms_is_get_too_fast */
+
+
+/**
+ * used to judge whether the number of set operations done is
+ * more than expected number of set operations to do right now.
+ *
+ * @param task, pointer of current task in the concurrency
+ *
+ * @return bool, if set too fast, return true, else return false
+ */
+static bool ms_is_set_too_fast(ms_task_t *task)
+{
+  double get_prop= ms_setting.cmd_distr[CMD_GET].cmd_prop;
+  double set_prop= ms_setting.cmd_distr[CMD_SET].cmd_prop;
+
+  /* no set operation */
+  if (set_prop < PROP_ERROR)
+  {
+    return false;
+  }
+
+  /* If it does set operation too fast, skip some */
+  int max_undo_get= (int)((get_prop / set_prop * (1.0 + DISADJUST_FACTOR))
+                          * (double)task->cycle_undo_set);
+
+  if (((double)task->get_opt * set_prop < (double)task->set_opt * get_prop)
+      && (task->cycle_undo_get > max_undo_get))
+  {
+    return true;
+  }
+
+  return false;
+} /* ms_is_set_too_fast */
+
+
+/**
+ * kick out the old item in the window, and add a new item to
+ * overwrite the old item. When we don't want to do overwrite
+ * object, and the current item to do set operation is an old
+ * item, we could kick out the old item and add a new item. Then
+ * we can ensure we set new object every time.
+ *
+ * @param item, pointer of task item which includes the object
+ *            information
+ */
+static void ms_kick_out_item(ms_task_item_t *item)
+{
+  /* allocate a new item */
+  item->key_prefix= ms_get_key_prefix();
+
+  item->key_suffix_offset++;
+  item->value_offset= INVALID_OFFSET;       /* new item use invalid value offset */
+  item->client_time= 0;
+} /* ms_kick_out_item */
+
+
+/**
+ *  used to judge whether we need overwrite object based on the
+ *  options user specified
+ *
+ * @param task, pointer of current task in the concurrency
+ *
+ * @return bool, if need overwrite, return true, else return
+ *         false
+ */
+static bool ms_need_overwirte_item(ms_task_t *task)
+{
+  ms_task_item_t *item= task->item;
+
+  assert(item != NULL);
+  assert(task->cmd == CMD_SET);
+
+  /**
+   *  according to data overwrite percent to determine if do data
+   *  overwrite.
+   */
+  if (task->overwrite_set < (double)task->set_opt
+      * ms_setting.overwrite_percent)
+  {
+    return true;
+  }
+
+  return false;
+} /* ms_need_overwirte_item */
+
+
+/**
+ * used to adjust operation. the function must be called after
+ * select operation. the function change get operation to set
+ * operation, or set operation to get operation based on the
+ * current case.
+ *
+ * @param c, pointer of the concurrency
+ * @param task, pointer of current task in the concurrency
+ *
+ * @return bool, if success, return true, else return false
+ */
+static bool ms_adjust_opt(ms_conn_t *c, ms_task_t *task)
+{
+  ms_task_item_t *item= task->item;
+
+  assert(item != NULL);
+
+  if (task->cmd == CMD_SET)
+  {
+    /* If did set operation too fast, skip some */
+    if (ms_is_set_too_fast(task))
+    {
+      /* get the item instead */
+      if (item->value_offset != INVALID_OFFSET)
+      {
+        task->cmd= CMD_GET;
+        return true;
+      }
+    }
+
+    /* If the current item is not a new item, kick it out */
+    if (item->value_offset != INVALID_OFFSET)
+    {
+      if (ms_need_overwirte_item(task))
+      {
+        /* overwrite */
+        task->overwrite_set++;
+      }
+      else
+      {
+        /* kick out the current item to do set operation */
+        ms_kick_out_item(item);
+      }
+    }
+    else            /* it's a new item */
+    {
+      /* need overwrite */
+      if (ms_need_overwirte_item(task))
+      {
+        item= ms_get_pre_set_item(c);
+        if (item->value_offset != INVALID_OFFSET)
+        {
+          task->item= item;
+          task->overwrite_set++;
+        }
+        else                /* previous set item is a new item */
+        {
+          /* select the previous item to run, and cancel overwrite */
+          task->item= item;
+        }
+      }
+    }
+    task->cmd= CMD_SET;
+    return true;
+  }
+  else
+  {
+    if (item->value_offset == INVALID_OFFSET)
+    {
+      task->cmd= CMD_SET;
+      return true;
+    }
+
+    /**
+     *  If It does get operation too fast, it will change the
+     *  operation to set.
+     */
+    if (ms_is_get_too_fast(task))
+    {
+      /* don't kick out the first item in the window */
+      if (! ms_is_set_too_fast(task))
+      {
+        ms_kick_out_item(item);
+        task->cmd= CMD_SET;
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+
+    assert(item->value_offset != INVALID_OFFSET);
+
+    task->cmd= CMD_GET;
+    return true;
+  }
+} /* ms_adjust_opt */
+
+
+/**
+ * used to initialize the task which need verify data.
+ *
+ * @param task, pointer of current task in the concurrency
+ */
+static void ms_task_data_verify_init(ms_task_t *task)
+{
+  ms_task_item_t *item= task->item;
+
+  assert(item != NULL);
+  assert(task->cmd == CMD_GET);
+
+  /**
+   *  according to data verification percent to determine if do
+   *  data verification.
+   */
+  if (task->verified_get < (double)task->get_opt
+      * ms_setting.verify_percent)
+  {
+    /**
+     *  currently it doesn't do verify, just increase the counter,
+     *  and do verification next proper get command
+     */
+    if ((task->item->value_offset != INVALID_OFFSET)
+        && (item->exp_time == 0))
+    {
+      task->verify= true;
+      task->finish_verify= false;
+      task->verified_get++;
+    }
+  }
+} /* ms_task_data_verify_init */
+
+
+/**
+ * used to initialize the task which need verify expire time.
+ *
+ * @param task, pointer of current task in the concurrency
+ */
+static void ms_task_expire_verify_init(ms_task_t *task)
+{
+  ms_task_item_t *item= task->item;
+
+  assert(item != NULL);
+  assert(task->cmd == CMD_GET);
+  assert(item->exp_time > 0);
+
+  task->verify= true;
+  task->finish_verify= false;
+} /* ms_task_expire_verify_init */
+
+
+/**
+ * used to get one task, the function initializes the task
+ * structure.
+ *
+ * @param c, pointer of the concurrency
+ * @param warmup, whether it need warmup
+ *
+ * @return ms_task_t*, pointer of current task in the
+ *         concurrency
+ */
+static ms_task_t *ms_get_task(ms_conn_t *c, bool warmup)
+{
+  ms_task_t *task= &c->curr_task;
+
+  while (1)
+  {
+    task->verify= false;
+    task->finish_verify= true;
+    task->get_miss= true;
+
+    if (warmup)
+    {
+      task->cmd= CMD_SET;
+      task->item= ms_get_next_set_item(c);
+
+      return task;
+    }
+
+    /* according to operation distribution to choose doing which operation */
+    ms_select_opt(c, task);
+
+    if (! ms_adjust_opt(c, task))
+    {
+      continue;
+    }
+
+    if ((ms_setting.verify_percent > 0) && (task->cmd == CMD_GET))
+    {
+      ms_task_data_verify_init(task);
+    }
+
+    if ((ms_setting.exp_ver_per > 0) && (task->cmd == CMD_GET)
+        && (task->item->exp_time > 0))
+    {
+      ms_task_expire_verify_init(task);
+    }
+
+    break;
+  }
+
+  /**
+   *  Only update get and delete counter, set counter will be
+   *  updated after set operation successes.
+   */
+  if (task->cmd == CMD_GET)
+  {
+    task->get_opt++;
+    task->cycle_undo_get--;
+  }
+
+  return task;
+} /* ms_get_task */
+
+
+/**
+ * send a signal to the main monitor thread
+ *
+ * @param sync_lock, pointer of the lock
+ */
+static void ms_send_signal(ms_sync_lock_t *sync_lock)
+{
+  pthread_mutex_lock(&sync_lock->lock);
+  sync_lock->count++;
+  pthread_cond_signal(&sync_lock->cond);
+  pthread_mutex_unlock(&sync_lock->lock);
+} /* ms_send_signal */
+
+
+/**
+ * If user only want to do get operation, but there is no object
+ * in server , so we use this function to warmup the server, and
+ * set some objects to server. It runs at the beginning of task.
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_warmup_server(ms_conn_t *c)
+{
+  ms_task_t *task;
+  ms_task_item_t *item;
+
+  /**
+   * Extra one loop to get the last command returned state.
+   * Normally it gets the previous command returned state.
+   */
+  if ((c->remain_warmup_num >= 0)
+      && (c->remain_warmup_num != c->warmup_num))
+  {
+    item= ms_get_cur_opt_item(c);
+    /* only update the set command result state for data verification */
+    if ((c->precmd.cmd == CMD_SET) && (c->precmd.retstat == MCD_STORED))
+    {
+      item->value_offset= item->key_suffix_offset;
+      /* set success, update counter */
+      c->set_cursor++;
+    }
+    else if (c->precmd.cmd == CMD_SET && c->precmd.retstat != MCD_STORED)
+    {
+      printf("key: %" PRIx64 " didn't set success\n", item->key_prefix);
+    }
+  }
+
+  /* the last time don't run a task */
+  if (c->remain_warmup_num-- > 0)
+  {
+    /* operate next task item */
+    task= ms_get_task(c, true);
+    item= task->item;
+    ms_mcd_set(c, item);
+  }
+
+  /**
+   *  finish warming up server, wait all connects initialize
+   *  complete. Then all connects can start do task at the same
+   *  time.
+   */
+  if (c->remain_warmup_num == -1)
+  {
+    ms_send_signal(&ms_global.init_lock);
+    c->remain_warmup_num--;       /* never run the if branch */
+  }
+} /* ms_warmup_server */
+
+
+/**
+ * dispatch single get and set task
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_single_getset_task_sch(ms_conn_t *c)
+{
+  ms_task_t *task;
+  ms_task_item_t *item;
+
+  /* the last time don't run a task */
+  if (c->remain_exec_num-- > 0)
+  {
+    task= ms_get_task(c, false);
+    item= task->item;
+    if (task->cmd == CMD_SET)
+    {
+      ms_mcd_set(c, item);
+    }
+    else if (task->cmd == CMD_GET)
+    {
+      assert(task->cmd == CMD_GET);
+      ms_mcd_get(c, item, task->verify);
+    }
+  }
+} /* ms_single_getset_task_sch */
+
+
+/**
+ * dispatch multi-get and set task
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_multi_getset_task_sch(ms_conn_t *c)
+{
+  ms_task_t *task;
+  ms_mlget_task_item_t *mlget_item;
+
+  while (1)
+  {
+    if (c->remain_exec_num-- > 0)
+    {
+      task= ms_get_task(c, false);
+      if (task->cmd == CMD_SET)             /* just do it */
+      {
+        ms_mcd_set(c, task->item);
+        break;
+      }
+      else
+      {
+        assert(task->cmd == CMD_GET);
+        mlget_item= &c->mlget_task.mlget_item[c->mlget_task.mlget_num];
+        mlget_item->item= task->item;
+        mlget_item->verify= task->verify;
+        mlget_item->finish_verify= task->finish_verify;
+        mlget_item->get_miss= task->get_miss;
+        c->mlget_task.mlget_num++;
+
+        /* enough multi-get task items can be done */
+        if ((c->mlget_task.mlget_num >= ms_setting.mult_key_num)
+            || ((c->remain_exec_num == 0) && (c->mlget_task.mlget_num > 0)))
+        {
+          ms_mcd_mlget(c);
+          break;
+        }
+      }
+    }
+    else
+    {
+      if ((c->remain_exec_num <= 0) && (c->mlget_task.mlget_num > 0))
+      {
+        ms_mcd_mlget(c);
+      }
+      break;
+    }
+  }
+} /* ms_multi_getset_task_sch */
+
+
+/**
+ * calculate the difference value of two time points
+ *
+ * @param start_time, the start time
+ * @param end_time, the end time
+ *
+ * @return uint64_t, the difference value between start_time and end_time in us
+ */
+int64_t ms_time_diff(struct timeval *start_time, struct timeval *end_time)
+{
+  int64_t endtime= end_time->tv_sec * 1000000 + end_time->tv_usec;
+  int64_t starttime= start_time->tv_sec * 1000000 + start_time->tv_usec;
+
+  assert(endtime >= starttime);
+
+  return endtime - starttime;
+} /* ms_time_diff */
+
+
+/**
+ * after get the response from server for multi-get, the
+ * function update the state of the task and do data verify if
+ * necessary.
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_update_multi_get_result(ms_conn_t *c)
+{
+  ms_mlget_task_item_t *mlget_item;
+  ms_task_item_t *item;
+  char *orignval= NULL;
+  char *orignkey= NULL;
+
+  if (c == NULL)
+  {
+    return;
+  }
+  assert(c != NULL);
+
+  for (int i= 0; i < c->mlget_task.mlget_num; i++)
+  {
+    mlget_item= &c->mlget_task.mlget_item[i];
+    item= mlget_item->item;
+    orignval= &ms_setting.char_block[item->value_offset];
+    orignkey= &ms_setting.char_block[item->key_suffix_offset];
+
+    /* update get miss counter */
+    if (mlget_item->get_miss)
+    {
+      atomic_add_size(&ms_stats.get_misses, 1);
+    }
+
+    /* get nothing from server for this task item */
+    if (mlget_item->verify && ! mlget_item->finish_verify)
+    {
+      /* verify expire time if necessary */
+      if (item->exp_time > 0)
+      {
+        struct timeval curr_time;
+        gettimeofday(&curr_time, NULL);
+
+        /* object doesn't expire but can't get it now */
+        if (curr_time.tv_sec - item->client_time
+            < item->exp_time - EXPIRE_TIME_ERROR)
+        {
+          atomic_add_size(&ms_stats.unexp_unget, 1);
+
+          if (ms_setting.verbose)
+          {
+            char set_time[64];
+            char cur_time[64];
+            strftime(set_time, 64, "%Y-%m-%d %H:%M:%S",
+                     localtime(&item->client_time));
+            strftime(cur_time, 64, "%Y-%m-%d %H:%M:%S",
+                     localtime(&curr_time.tv_sec));
+            fprintf(stderr,
+                    "\n\t<%d expire time verification failed, object "
+                    "doesn't expire but can't get it now\n"
+                    "\tkey len: %d\n"
+                    "\tkey: %" PRIx64 " %.*s\n"
+                    "\tset time: %s current time: %s "
+                    "diff time: %d expire time: %d\n"
+                    "\texpected data len: %d\n"
+                    "\texpected data: %.*s\n"
+                    "\treceived data: \n",
+                    c->sfd,
+                    item->key_size,
+                    item->key_prefix,
+                    item->key_size - (int)KEY_PREFIX_SIZE,
+                    orignkey,
+                    set_time,
+                    cur_time,
+                    (int)(curr_time.tv_sec - item->client_time),
+                    item->exp_time,
+                    item->value_size,
+                    item->value_size,
+                    orignval);
+            fflush(stderr);
+          }
+        }
+      }
+      else
+      {
+        atomic_add_size(&ms_stats.vef_miss, 1);
+
+        if (ms_setting.verbose)
+        {
+          fprintf(stderr, "\n<%d data verification failed\n"
+                          "\tkey len: %d\n"
+                          "\tkey: %" PRIx64 " %.*s\n"
+                          "\texpected data len: %d\n"
+                          "\texpected data: %.*s\n"
+                          "\treceived data: \n",
+                  c->sfd, item->key_size, item->key_prefix,
+                  item->key_size - (int)KEY_PREFIX_SIZE,
+                  orignkey, item->value_size, item->value_size, orignval);
+          fflush(stderr);
+        }
+      }
+    }
+  }
+  c->mlget_task.mlget_num= 0;
+  c->mlget_task.value_index= INVALID_OFFSET;
+} /* ms_update_multi_get_result */
+
+
+/**
+ * after get the response from server for single get, the
+ * function update the state of the task and do data verify if
+ * necessary.
+ *
+ * @param c, pointer of the concurrency
+ * @param item, pointer of task item which includes the object
+ *            information
+ */
+static void ms_update_single_get_result(ms_conn_t *c, ms_task_item_t *item)
+{
+  char *orignval= NULL;
+  char *orignkey= NULL;
+
+  if ((c == NULL) || (item == NULL))
+  {
+    return;
+  }
+  assert(c != NULL);
+  assert(item != NULL);
+
+  orignval= &ms_setting.char_block[item->value_offset];
+  orignkey= &ms_setting.char_block[item->key_suffix_offset];
+
+  /* update get miss counter */
+  if ((c->precmd.cmd == CMD_GET) && c->curr_task.get_miss)
+  {
+    atomic_add_size(&ms_stats.get_misses, 1);
+  }
+
+  /* get nothing from server for this task item */
+  if ((c->precmd.cmd == CMD_GET) && c->curr_task.verify
+      && ! c->curr_task.finish_verify)
+  {
+    /* verify expire time if necessary */
+    if (item->exp_time > 0)
+    {
+      struct timeval curr_time;
+      gettimeofday(&curr_time, NULL);
+
+      /* object doesn't expire but can't get it now */
+      if (curr_time.tv_sec - item->client_time
+          < item->exp_time - EXPIRE_TIME_ERROR)
+      {
+        atomic_add_size(&ms_stats.unexp_unget, 1);
+
+        if (ms_setting.verbose)
+        {
+          char set_time[64];
+          char cur_time[64];
+          strftime(set_time, 64, "%Y-%m-%d %H:%M:%S",
+                   localtime(&item->client_time));
+          strftime(cur_time, 64, "%Y-%m-%d %H:%M:%S",
+                   localtime(&curr_time.tv_sec));
+          fprintf(stderr,
+                  "\n\t<%d expire time verification failed, object "
+                  "doesn't expire but can't get it now\n"
+                  "\tkey len: %d\n"
+                  "\tkey: %" PRIx64 " %.*s\n"
+                  "\tset time: %s current time: %s "
+                  "diff time: %d expire time: %d\n"
+                  "\texpected data len: %d\n"
+                  "\texpected data: %.*s\n"
+                  "\treceived data: \n",
+                  c->sfd,
+                  item->key_size,
+                  item->key_prefix,
+                  item->key_size - (int)KEY_PREFIX_SIZE,
+                  orignkey,
+                  set_time,
+                  cur_time,
+                  (int)(curr_time.tv_sec - item->client_time),
+                  item->exp_time,
+                  item->value_size,
+                  item->value_size,
+                  orignval);
+          fflush(stderr);
+        }
+      }
+    }
+    else
+    {
+      atomic_add_size(&ms_stats.vef_miss, 1);
+
+      if (ms_setting.verbose)
+      {
+        fprintf(stderr, "\n<%d data verification failed\n"
+                        "\tkey len: %d\n"
+                        "\tkey: %" PRIx64 " %.*s\n"
+                        "\texpected data len: %d\n"
+                        "\texpected data: %.*s\n"
+                        "\treceived data: \n",
+                c->sfd, item->key_size, item->key_prefix,
+                item->key_size - (int)KEY_PREFIX_SIZE,
+                orignkey, item->value_size, item->value_size, orignval);
+        fflush(stderr);
+      }
+    }
+  }
+} /* ms_update_single_get_result */
+
+
+/**
+ * after get the response from server for set the function
+ * update the state of the task and do data verify if necessary.
+ *
+ * @param c, pointer of the concurrency
+ * @param item, pointer of task item which includes the object
+ *            information
+ */
+static void ms_update_set_result(ms_conn_t *c, ms_task_item_t *item)
+{
+  if ((c == NULL) || (item == NULL))
+  {
+    return;
+  }
+  assert(c != NULL);
+  assert(item != NULL);
+
+  if (c->precmd.cmd == CMD_SET)
+  {
+    switch (c->precmd.retstat)
+    {
+    case MCD_STORED:
+      if (item->value_offset == INVALID_OFFSET)
+      {
+        /* first set with the same offset of key suffix */
+        item->value_offset= item->key_suffix_offset;
+      }
+      else
+      {
+        /* not first set, just increase the value offset */
+        item->value_offset+= 1;
+      }
+
+      /* set successes, update counter */
+      c->set_cursor++;
+      c->curr_task.set_opt++;
+      c->curr_task.cycle_undo_set--;
+      break;
+
+    case MCD_SERVER_ERROR:
+    default:
+      break;
+    } /* switch */
+  }
+} /* ms_update_set_result */
+
+
+/**
+ * update the response time result
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_update_stat_result(ms_conn_t *c)
+{
+  bool get_miss= false;
+
+  if (c == NULL)
+  {
+    return;
+  }
+  assert(c != NULL);
+
+  gettimeofday(&c->end_time, NULL);
+  uint64_t time_diff= (uint64_t)ms_time_diff(&c->start_time, &c->end_time);
+
+  pthread_mutex_lock(&ms_statistic.stat_mutex);
+
+  switch (c->precmd.cmd)
+  {
+  case CMD_SET:
+    ms_record_event(&ms_statistic.set_stat, time_diff, false);
+    break;
+
+  case CMD_GET:
+    if (c->curr_task.get_miss)
+    {
+      get_miss= true;
+    }
+    ms_record_event(&ms_statistic.get_stat, time_diff, get_miss);
+    break;
+
+  default:
+    break;
+  } /* switch */
+
+  ms_record_event(&ms_statistic.total_stat, time_diff, get_miss);
+  pthread_mutex_unlock(&ms_statistic.stat_mutex);
+} /* ms_update_stat_result */
+
+
+/**
+ * after get response from server for the current operation, and
+ * before doing the next operation, update the state of the
+ * current operation.
+ *
+ * @param c, pointer of the concurrency
+ */
+static void ms_update_task_result(ms_conn_t *c)
+{
+  ms_task_item_t *item;
+
+  if (c == NULL)
+  {
+    return;
+  }
+  assert(c != NULL);
+
+  item= ms_get_cur_opt_item(c);
+  if (item == NULL)
+  {
+    return;
+  }
+  assert(item != NULL);
+
+  ms_update_set_result(c, item);
+
+  if ((ms_setting.stat_freq > 0)
+      && ((c->precmd.cmd == CMD_SET) || (c->precmd.cmd == CMD_GET)))
+  {
+    ms_update_stat_result(c);
+  }
+
+  /* update multi-get task item */
+  if (((ms_setting.mult_key_num > 1)
+       && (c->mlget_task.mlget_num >= ms_setting.mult_key_num))
+      || ((c->remain_exec_num == 0) && (c->mlget_task.mlget_num > 0)))
+  {
+    ms_update_multi_get_result(c);
+  }
+  else
+  {
+    ms_update_single_get_result(c, item);
+  }
+} /* ms_update_task_result */
+
+
+/**
+ * run get and set operation
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+static int ms_run_getset_task(ms_conn_t *c)
+{
+  /**
+   * extra one loop to get the last command return state. get the
+   * last command return state.
+   */
+  if ((c->remain_exec_num >= 0)
+      && (c->remain_exec_num != c->exec_num))
+  {
+    ms_update_task_result(c);
+  }
+
+  /* multi-get */
+  if (ms_setting.mult_key_num > 1)
+  {
+    /* operate next task item */
+    ms_multi_getset_task_sch(c);
+  }
+  else
+  {
+    /* operate next task item */
+    ms_single_getset_task_sch(c);
+  }
+
+  /* no task to do, exit */
+  if ((c->remain_exec_num == -1) || ms_global.time_out)
+  {
+    return -1;
+  }
+
+  return 0;
+} /* ms_run_getset_task */
+
+
+/**
+ * the state machine call the function to execute task.
+ *
+ * @param c, pointer of the concurrency
+ *
+ * @return int, if success, return 0, else return -1
+ */
+int ms_exec_task(struct conn *c)
+{
+  if (! ms_global.finish_warmup)
+  {
+    ms_warmup_server(c);
+  }
+  else
+  {
+    if (ms_run_getset_task(c) != 0)
+    {
+      return -1;
+    }
+  }
+
+  return 0;
+} /* ms_exec_task */
diff --git a/clients/ms_task.h b/clients/ms_task.h
new file mode 100644 (file)
index 0000000..c4917d1
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * File:   ms_task.h
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+#ifndef MS_TASK_H
+#define MS_TASK_H
+
+#include <sys/types.h>
+#include <stdint.h>
+#if !defined(__cplusplus)
+# include <stdbool.h>
+#endif
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UNIT_ITEMS_COUNT     1024               /* each window unit has 1024 items */
+#define KEY_PREFIX_SIZE      (sizeof(uint64_t)) /* key prefix length: 8 bytes */
+#define INVALID_OFFSET       (-1)               /* invalid offset in the character table */
+#define FIXED_EXPIRE_TIME    60                 /* default expire time is 60s */
+#define EXPIRE_TIME_ERROR    5                  /* default expire time error is 5s */
+
+/* information of a task item(object) */
+typedef struct task_item
+{
+  uint64_t key_prefix;                  /* prefix of the key, 8 bytes, binary */
+  int key_size;                         /* key size */
+  int key_suffix_offset;                /* suffix offset in the global character table */
+
+  int value_size;                       /* data size */
+  int value_offset;                     /* data offset in the global character table */
+
+  time_t client_time;                   /* the current client time */
+  int exp_time;                         /* expire time */
+} ms_task_item_t;
+
+/* task item for multi-get */
+typedef struct mlget_task_item
+{
+  ms_task_item_t *item;                 /* task item */
+  bool verify;                          /* whether verify data or not */
+  bool finish_verify;                   /* whether finish data verify or not */
+  bool get_miss;                        /* whether get miss or not */
+} ms_mlget_task_item_t;
+
+/* information of multi-get task */
+typedef struct mlget_task
+{
+  ms_mlget_task_item_t *mlget_item;        /* multi-get task array */
+  int mlget_num;                           /* how many tasks in mlget_task array */
+  int value_index;                         /* the nth value received by the connect, for multi-get */
+} ms_mlget_task_t;
+
+/* structure used to store the state of the running task */
+typedef struct task
+{
+  int cmd;                              /* command name */
+  bool verify;                          /* whether verify data or not */
+  bool finish_verify;                   /* whether finish data verify or not */
+  bool get_miss;                        /* whether get miss or not */
+  ms_task_item_t *item;                 /* task item */
+
+  /* counter for command distribution adjustment */
+  uint64_t get_opt;                     /* number of total get operations */
+  uint64_t set_opt;                     /* number of total set operations, no including warmup set count */
+  int cycle_undo_get;                   /* number of undo get in an adjustment cycle */
+  int cycle_undo_set;                   /* number of undo set in an adjustment cycle */
+  uint64_t verified_get;                /* number of total verified get operations */
+  uint64_t overwrite_set;               /* number of total overwrite set operations */
+} ms_task_t;
+
+struct conn;
+
+/* the state machine call the function to execute task.*/
+int ms_exec_task(struct conn *c);
+
+
+/* calculate the difference value of two time points */
+int64_t ms_time_diff(struct timeval *start_time, struct timeval *end_time);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of MS_TASK_H */
diff --git a/clients/ms_thread.c b/clients/ms_thread.c
new file mode 100644 (file)
index 0000000..dbfc62a
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * File:   ms_thread.c
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+
+#include "config.h"
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#include "ms_thread.h"
+#include "ms_setting.h"
+#include "ms_atomic.h"
+
+/* global variable */
+pthread_key_t ms_thread_key;
+
+/* array of thread context structure, each thread has a thread context structure */
+static ms_thread_ctx_t *ms_thread_ctx;
+
+/* functions */
+static void ms_set_current_time(void);
+static void ms_check_sock_timeout(void);
+static void ms_clock_handler(const int fd, const short which, void *arg);
+static int ms_set_thread_cpu_affinity(int cpu);
+static int ms_setup_thread(ms_thread_ctx_t *thread_ctx);
+static void *ms_worker_libevent(void *arg);
+static void ms_create_worker(void *(*func)(void *), void *arg);
+
+
+/**
+ *  time-sensitive callers can call it by hand with this,
+ *  outside the normal ever-1-second timer
+ */
+static void ms_set_current_time()
+{
+  struct timeval timer;
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+
+  gettimeofday(&timer, NULL);
+  ms_thread->curr_time= (rel_time_t)timer.tv_sec;
+} /* ms_set_current_time */
+
+
+/**
+ *  used to check whether UDP of command are waiting timeout
+ *  by the ever-1-second timer
+ */
+static void ms_check_sock_timeout(void)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  ms_conn_t *c= NULL;
+  int time_diff= 0;
+
+  for (int i= 0; i < ms_thread->thread_ctx->nconns; i++)
+  {
+    c= &ms_thread->conn[i];
+
+    if (c->udp)
+    {
+      time_diff= (int)(ms_thread->curr_time - (rel_time_t)c->start_time.tv_sec);
+
+      /* wait time out */
+      if (time_diff > SOCK_WAIT_TIMEOUT)
+      {
+        /* calculate dropped packets count */
+        if (c->recvpkt > 0)
+        {
+          atomic_add_size(&ms_stats.pkt_drop, c->packets - c->recvpkt);
+        }
+
+        atomic_add_size(&ms_stats.udp_timeout, 1);
+        ms_reset_conn(c, true);
+      }
+    }
+  }
+} /* ms_check_sock_timeout */
+
+
+/* if disconnect, the ever-1-second timer will call this function to reconnect */
+static void ms_reconn_thread_socks(void)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  for (int i= 0; i < ms_thread->thread_ctx->nconns; i++)
+  {
+    ms_reconn_socks(&ms_thread->conn[i]);
+  }
+} /* ms_reconn_thread_socks */
+
+
+/**
+ * the handler of the ever-1-second timer
+ *
+ * @param fd, the descriptors of the socket
+ * @param which, event flags
+ * @param arg, argument
+ */
+static void ms_clock_handler(const int fd, const short which, void *arg)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  struct timeval t=
+  {
+    .tv_sec= 1, .tv_usec= 0
+  };
+
+  UNUSED_ARGUMENT(fd);
+  UNUSED_ARGUMENT(which);
+  UNUSED_ARGUMENT(arg);
+
+  ms_set_current_time();
+
+  if (ms_thread->initialized)
+  {
+    /* only delete the event if it's actually there. */
+    evtimer_del(&ms_thread->clock_event);
+    ms_check_sock_timeout();
+  }
+  else
+  {
+    ms_thread->initialized= true;
+  }
+
+  ms_reconn_thread_socks();
+
+  evtimer_set(&ms_thread->clock_event, ms_clock_handler, 0);
+  event_base_set(ms_thread->base, &ms_thread->clock_event);
+  evtimer_add(&ms_thread->clock_event, &t);
+} /* ms_clock_handler */
+
+
+/**
+ * used to bind thread to CPU if the system supports
+ *
+ * @param cpu, cpu index
+ *
+ * @return if success, return 0, else return -1
+ */
+static int ms_set_thread_cpu_affinity(int cpu)
+{
+  int ret= 0;
+
+#ifdef HAVE_CPU_SET_T
+  cpu_set_t cpu_set;
+  CPU_ZERO(&cpu_set);
+  CPU_SET(cpu, &cpu_set);
+
+  if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set) == -1)
+  {
+    fprintf(stderr, "WARNING: Could not set CPU Affinity, continuing...\n");
+    ret= 1;
+  }
+#else
+  UNUSED_ARGUMENT(cpu);
+#endif
+
+  return ret;
+} /* ms_set_thread_cpu_affinity */
+
+
+/**
+ * Set up a thread's information.
+ *
+ * @param thread_ctx, pointer of the thread context structure
+ *
+ * @return if success, return 0, else return -1
+ */
+static int ms_setup_thread(ms_thread_ctx_t *thread_ctx)
+{
+
+  ms_thread_t *ms_thread= (ms_thread_t *)calloc(sizeof(*ms_thread), 1);
+  pthread_setspecific(ms_thread_key, (void *)ms_thread);
+
+  ms_thread->thread_ctx= thread_ctx;
+  ms_thread->nactive_conn= thread_ctx->nconns;
+  ms_thread->initialized= false;
+  static volatile uint32_t cnt= 0;
+
+  gettimeofday(&ms_thread->startup_time, NULL);
+
+  ms_thread->base= event_init();
+  if (ms_thread->base == NULL)
+  {
+    if (atomic_add_32_nv(&cnt, 1) == 0)
+    {
+      fprintf(stderr, "Can't allocate event base.\n");
+    }
+
+    return -1;
+  }
+
+  ms_thread->conn=
+    (ms_conn_t *)malloc((size_t)thread_ctx->nconns * sizeof(ms_conn_t));
+  if (ms_thread->conn == NULL)
+  {
+    if (atomic_add_32_nv(&cnt, 1) == 0)
+    {
+      fprintf(
+        stderr,
+        "Can't allocate concurrency structure for thread descriptors.");
+    }
+
+    return -1;
+  }
+  memset(ms_thread->conn, 0, (size_t)thread_ctx->nconns * sizeof(ms_conn_t));
+
+  for (int i= 0; i < thread_ctx->nconns; i++)
+  {
+    ms_thread->conn[i].conn_idx= i;
+    if (ms_setup_conn(&ms_thread->conn[i]) != 0)
+    {
+      /* only output this error once */
+      if (atomic_add_32_nv(&cnt, 1) == 0)
+      {
+        fprintf(stderr, "Initializing connection failed.\n");
+      }
+
+      return -1;
+    }
+  }
+
+  return 0;
+} /* ms_setup_thread */
+
+
+/**
+ * Worker thread: main event loop
+ *
+ * @param arg, the pointer of argument
+ *
+ * @return void*
+ */
+static void *ms_worker_libevent(void *arg)
+{
+  ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
+  ms_thread_ctx_t *thread_ctx= (ms_thread_ctx_t *)arg;
+
+  /**
+   * If system has more than one cpu and supports set cpu
+   * affinity, try to bind each thread to a cpu core;
+   */
+  if (ms_setting.ncpu > 1)
+  {
+    ms_set_thread_cpu_affinity(thread_ctx->thd_idx % ms_setting.ncpu);
+  }
+
+  if (ms_setup_thread(thread_ctx) != 0)
+  {
+    exit(1);
+  }
+
+  /* each thread with a timer */
+  ms_clock_handler(0, 0, 0);
+
+  event_base_loop(ms_thread->base, 0);
+
+  return NULL;
+} /* ms_worker_libevent */
+
+
+/**
+ * Creates a worker thread.
+ *
+ * @param func, the callback function
+ * @param arg, the argument to pass to the callback function
+ */
+static void ms_create_worker(void *(*func)(void *), void *arg)
+{
+  pthread_t thread;
+  pthread_attr_t attr;
+  int ret;
+
+  pthread_attr_init(&attr);
+
+  if ((ret= pthread_create(&thread, &attr, func, arg)) != 0)
+  {
+    fprintf(stderr, "Can't create thread: %s.\n", strerror(ret));
+    exit(1);
+  }
+} /* ms_create_worker */
+
+
+/* initialize threads */
+void ms_thread_init()
+{
+  ms_thread_ctx=
+    (ms_thread_ctx_t *)malloc(
+      sizeof(ms_thread_ctx_t) * (size_t)ms_setting.nthreads);
+  if (ms_thread_ctx == NULL)
+  {
+    fprintf(stderr, "Can't allocate thread descriptors.");
+    exit(1);
+  }
+
+  for (int i= 0; i < ms_setting.nthreads; i++)
+  {
+    ms_thread_ctx[i].thd_idx= i;
+    ms_thread_ctx[i].nconns= (int)((int)ms_setting.nconns / ms_setting.nthreads);
+
+    /**
+     *  If only one server, all the connections in all threads
+     *  connects the same server. For support multi-servers, simple
+     *  distribute thread to server.
+     */
+    ms_thread_ctx[i].srv_idx= i % ms_setting.srv_cnt;
+    ms_thread_ctx[i].tps_perconn= ms_setting.expected_tps
+                                  / (int)ms_setting.nconns;
+    ms_thread_ctx[i].exec_num_perconn= ms_setting.exec_num
+                                       / ms_setting.nconns;
+  }
+
+  if (pthread_key_create(&ms_thread_key, NULL))
+  {
+    fprintf(stderr, "Can't create pthread keys. Major malfunction!\n");
+    exit(1);
+  }
+  /* Create threads after we've done all the epoll setup. */
+  for (int i= 0; i < ms_setting.nthreads; i++)
+  {
+    ms_create_worker(ms_worker_libevent, (void *)&ms_thread_ctx[i]);
+  }
+} /* ms_thread_init */
+
+
+/* cleanup some resource of threads when all the threads exit */
+void ms_thread_cleanup()
+{
+  if (ms_thread_ctx != NULL)
+  {
+    free(ms_thread_ctx);
+  }
+  pthread_key_delete(ms_thread_key);
+} /* ms_thread_cleanup */
diff --git a/clients/ms_thread.h b/clients/ms_thread.h
new file mode 100644 (file)
index 0000000..3eea256
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * File:   ms_thread.h
+ * Author: Mingqiang Zhuang
+ *
+ * Created on February 10, 2009
+ *
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
+ * http://www.schoonerinfotech.com/
+ *
+ */
+
+/**
+ * Asynchronous memslap has the similar implementation of
+ * multi-threads with memcached. Asynchronous memslap creates
+ * one or more self-governed threads; each thread is bound with
+ * one CPU core if the system supports setting CPU core
+ * affinity. And every thread has private variables. There is
+ * less communication or some shared resources among all the
+ * threads. It can improve the performance because there are
+ * fewer locks and competition. In addition, each thread has a
+ * libevent to manage the events of network. Each thread has one
+ * or more self-governed concurrencies; each concurrency has one
+ * or more socket connections. All the concurrencies don't
+ * communicate with each other even though they are in the same
+ * thread.
+ */
+#ifndef MS_THREAD_H
+#define MS_THREAD_H
+
+#include <sched.h>
+#include "ms_conn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Time relative to server start. Smaller than time_t on 64-bit systems. */
+typedef unsigned int   rel_time_t;
+
+/* Used to store the context of each thread */
+typedef struct thread_ctx
+{
+  int thd_idx;                          /* the thread index */
+  int nconns;                           /* how many connections included by the thread */
+  int srv_idx;                          /* index of the thread */
+  int tps_perconn;                      /* expected throughput per connection */
+  int64_t exec_num_perconn;             /* execute number per connection */
+} ms_thread_ctx_t;
+
+/* Used to store the private variables of each thread */
+typedef struct thread
+{
+  ms_conn_t *conn;                      /* conn array to store all the conn in the thread */
+  int nactive_conn;                     /* how many connects are active */
+
+  ms_thread_ctx_t *thread_ctx;          /* thread context from the caller */
+  struct event_base *base;              /* libevent handler created by this thread */
+
+  rel_time_t curr_time;                 /* current time */
+  struct event clock_event;             /* clock event to time each one second */
+  bool initialized;                     /* whether clock_event has been initialized */
+
+  struct timeval startup_time;          /* start time of the thread */
+} ms_thread_t;
+
+/* initialize threads */
+void ms_thread_init(void);
+
+
+/* cleanup some resource of threads when all the threads exit */
+void ms_thread_cleanup(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of MS_THREAD_H */
index e7d8df94b067302c8ca2095501d2f5fa03c6e1ab..5d761e3c94729c03dca3931b005ec381f359abb0 100644 (file)
@@ -1,3 +1,14 @@
+/* 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 "libmemcached/common.h"
 #include <stdio.h>
 #include <ctype.h>
@@ -7,7 +18,7 @@
 
 long int timedif(struct timeval a, struct timeval b)
 {
-  register int us, s;
+  long us, s;
 
   us = (int)(a.tv_usec - b.tv_usec);
   us /= 1000;
@@ -18,7 +29,7 @@ long int timedif(struct timeval a, struct timeval b)
 
 void version_command(const char *command_name)
 {
-  printf("%s v%u.%u\n", command_name, 1, 0);
+  printf("%s v%u.%u\n", command_name, 1U, 0U);
   exit(0);
 }
 
@@ -60,7 +71,7 @@ void help_command(const char *command_name, const char *description,
 {
   unsigned int x;
 
-  printf("%s v%u.%u\n\n", command_name, 1, 0);
+  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");
 
@@ -81,7 +92,7 @@ void help_command(const char *command_name, const char *description,
 void process_hash_option(memcached_st *memc, char *opt_hash)
 {
   uint64_t set;
-  memcached_return rc;
+  memcached_return_t rc;
 
   if (opt_hash == NULL)
     return;
index 7ca92497ccbb3b855349dc358712d38c355589fd..f55997a5852eb754605693100ae2482aa4cc422c 100644 (file)
@@ -1,3 +1,14 @@
+/* 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 <getopt.h>
 #include <libmemcached/memcached.h>
 #include "client_options.h"
diff --git a/config/bootstrap b/config/bootstrap
deleted file mode 120000 (symlink)
index 43095ae..0000000
+++ /dev/null
@@ -1 +0,0 @@
-autorun.sh
\ No newline at end of file
index a7dd26ccd485cb2129a3da4e2c734862370bd315..c8054fe357bfb99b11c2d00f023700cf58b9c235 100644 (file)
@@ -1,3 +1,4 @@
+#!/usr/bin/env bash
 # libmemcached
 # Copyright (C) 2008 Brian Aker, Monty Taylor
 # All rights reserved.
@@ -6,7 +7,7 @@
 # the COPYING file in this directory for full text.
 
 AC_PREREQ(2.59)
-AC_INIT([libmemcached],[0.35],[http://tangent.org/552/libmemcached.html])
+AC_INIT([libmemcached],[0.37],[http://tangent.org/552/libmemcached.html])
 AC_CONFIG_SRCDIR([libmemcached/memcached.c])
 AC_CONFIG_AUX_DIR(config)
 AM_CONFIG_HEADER([config.h])
@@ -15,7 +16,7 @@ AC_CONFIG_MACRO_DIR([m4])
 PANDORA_CANONICAL_TARGET
 
 #shared library versioning
-MEMCACHED_LIBRARY_VERSION=3:0:0
+MEMCACHED_LIBRARY_VERSION=4:0:0
 #                         | | |
 #                  +------+ | +---+
 #                  |        |     |
@@ -27,53 +28,19 @@ MEMCACHED_LIBRARY_VERSION=3:0:0
 #                  |           set to zero if current is incremented
 #                  +- increment if interfaces have been added, removed or changed
 AC_SUBST(MEMCACHED_LIBRARY_VERSION)
-MEMCACHEDUTIL_LIBRARY_VERSION=0:0:0
-AC_SUBST(MEMCACHEDUTIL_LIBRARY_VERSION)
-MEMCACHEDPROTOCOL_LIBRARY_VERSION=0:0:0
-AC_SUBST(MEMCACHEDPROTOCOL_LIBRARY_VERSION)
 
 
-# libmemcached versioning when linked with GNU ld.
-if test "$lt_cv_prog_gnu_ld" = "yes"
-then
-    LD_VERSION_SCRIPT="-Wl,--version-script=\$(top_srcdir)/libmemcached/libmemcached.ver"
-    LD_UTIL_VERSION_SCRIPT="-Wl,--version-script=\$(top_srcdir)/libmemcached/util/libmemcachedutil.ver"
-    LD_PROTOCOL_VERSION_SCRIPT="-Wl,--version-script=\$(top_srcdir)/libmemcached/protocol/libmemcachedprotocol.ver"
-fi
-AC_SUBST(LD_VERSION_SCRIPT)
-AC_SUBST(LD_UTIL_VERSION_SCRIPT)
-AC_SUBST(LD_PROTOCOL_VERSION_SCRIPT)
-
-
-#--------------------------------------------------------------------
-# Check for libpthread
-#--------------------------------------------------------------------
-
-ACX_PTHREAD(,AC_MSG_ERROR(could not find libpthread))
-LIBS="${PTHREAD_LIBS} ${LIBS}"
-CFLAGS="${PTHREAD_CFLAGS} ${CFLAGS}"
-CC="$PTHREAD_CC"
-
+HASHKIT_LIBRARY_VERSION=0:0:0
+AC_SUBST(HASHKIT_LIBRARY_VERSION)
 
 AC_SEARCH_LIBS(getopt_long, gnugetopt)
-AC_SEARCH_LIBS(socket, socket)
 AC_SEARCH_LIBS(gethostbyname, nsl)
 
-save_LIBS="$LIBS"
-LIBS="$LIBS -lm"
-AC_LINK_IFELSE(
-  [AC_LANG_PROGRAM(
-    [[
-#include <stdlib.h>
-    ]],[[
-      float f= floorf((float) 1.0);
-    ]],
-    [LIBM="-lm"],[LIBM=""])])
-
-AC_SUBST(LIBM)
-LIBS="$save_LIBS"
+AC_CHECK_FUNCS([getline])
 
-AC_SEARCH_LIBS(floorf, m)
+PANDORA_HAVE_LIBEVENT
+PANDORA_REQUIRE_PTHREAD
+PANDORA_CXX_DEMANGLE
 
 dnl Specialty checks
 DETECT_BYTEORDER
@@ -81,20 +48,26 @@ ENABLE_UTILLIB
 SETSOCKOPT_SANITY
 ENABLE_HSIEH_HASH
 REQUIRE_POD2MAN
+REQUIRE_PODCHECKER
 PROTOCOL_BINARY_TEST
 WITH_MEMCACHED
 ENABLE_DEPRECATED
 PANDORA_HAVE_LIBINNODB
+PANDORA_PRINT_CALLSTACK
+
+AC_CHECK_HEADERS([atomic.h])
+AS_IF([test "x$ac_cv_header_atomic_h" = "xyes"],[
+      AC_CHECK_FUNCS(atomic_add_64)
+      AC_CHECK_FUNCS(atomic_add_32)
+      AS_IF([test "x$ac_cv_func_atomic_add_64" = "xyes" -a "x$ac_cv_func_atomic_add_32" = "xyes"],[
+            AC_DEFINE([USE_ATOMIC_H],
+                     [1],
+                      [Define to true if you want to use functions from atomic.h])])])
 
 AC_CONFIG_FILES([
   Makefile
-  clients/Makefile
-  tests/Makefile
   docs/Makefile
-  example/Makefile
-  libmemcached/Makefile
-  libmemcached/memcached_configure.h
-  support/Makefile
+  libmemcached/configure.h
   support/libmemcached.pc
   support/libmemcached.spec
   support/libmemcached-fc.spec
index 9a4ee49ac8cdc28ed71a234833acc6517603e586..03ba2eb66fbe4b2225e003d969d6c47ae70140dd 100644 (file)
-CLEANFILES= *.1 *.3
-
-
-EXTRA_DIST = libmemcached.pod\
-       libmemcachedutil.pod\
-       memcached_flush.pod\
-       memcached_dump.pod\
-       memcached_stats.pod\
-       memrm.pod\
-       memerror.pod\
-       libmemcached_examples.pod\
-       memcached_get.pod\
-       memcached_strerror.pod\
-       memslap.pod\
-       memcached_auto.pod\
-       memcached_quit.pod\
-       memcached_verbosity.pod\
-       memstat.pod\
-       memcached_behavior.pod\
-       memcached_callback.pod\
-       memcached_server_st.pod\
-        memcapable.pod \
-       memcat.pod\
-       memcached_create.pod\
-       memcached_pool.pod\
-       memcached_servers.pod\
-       memcp.pod\
-       memcached_delete.pod\
-       memcached_set.pod\
-       memcached_version.pod\
-       memflush.pod\
-       memdump.pod\
-       memcached_flush_buffers.pod\
-        memcached_analyze.pod\
-        memcached_generate_hash_value.pod\
-        memcached_memory_allocators.pod\
-        memcached_user_data.pod
-
-man_MANS = libmemcached.3\
-       libmemcached_examples.3\
-       memcapable.1\
-       memcat.1\
-       memcp.1\
-       memerror.1\
-       memflush.1\
-       memdump.1\
-       memrm.1\
-       memslap.1\
-       memstat.1\
-       memcached_add.3\
-       memcached_add_by_key.3\
-       memcached_append.3\
-       memcached_append_by_key.3\
-       memcached_analyze.3\
-       memcached_behavior_get.3\
-       memcached_behavior_set.3\
-       memcached_callback_get.3\
-       memcached_callback_set.3\
-       memcached_cas.3\
-       memcached_cas_by_key.3\
-       memcached_clone.3\
-       memcached_create.3\
-       memcached_decrement.3\
-       memcached_decrement_with_initial.3\
-       memcached_delete.3\
-       memcached_delete_by_key.3\
-       memcached_fetch.3\
-       memcached_fetch_execute.3\
-       memcached_fetch_result.3\
-       memcached_free.3\
-       memcached_get.3\
-       memcached_get_by_key.3\
-       memcached_increment.3\
-       memcached_increment_with_initial.3\
-       memcached_mget.3\
-       memcached_mget_by_key.3\
-        memcached_mget_execute.3 \
-        memcached_mget_execute_by_key.3 \
-       memcached_prepend.3\
-       memcached_prepend_by_key.3\
-       memcached_replace.3\
-       memcached_replace_by_key.3\
-       memcached_server_add.3\
-       memcached_server_count.3\
-       memcached_server_list.3\
-       memcached_server_list_append.3\
-       memcached_server_list_count.3\
-       memcached_server_list_free.3\
-       memcached_server_push.3\
-       memcached_servers_parse.3\
-       memcached_set.3\
-       memcached_set_by_key.3\
-       memcached_stat.3\
-       memcached_stat_get_keys.3\
-       memcached_stat_get_value.3\
-       memcached_stat_servername.3\
-       memcached_strerror.3\
-       memcached_quit.3\
-       memcached_verbosity.3\
-       memcached_lib_version.3\
-       memcached_version.3\
-        memcached_flush_buffers.3\
-        memcached_dump.3\
-        memcached_generate_hash_value.3\
-        memcached_set_memory_allocators.3\
-        memcached_get_memory_allocators.3\
-        memcached_set_user_data.3\
-        memcached_get_user_data.3
+# This file generates all of man/html pages that we use for documentation.
+#
+# When hacking this file you need to know that we take .pod files and turn
+# them into .pop files. .pop files are 1=1 for man pages, but one .pod
+# file may generate many .pop files.
+#
+#    -Brian
+#
+#
+CLEANFILES= *.1 *.3 *.html *.pop *.tmp
+
+BUILT_SOURCES=
+
+EXTRA_DIST= make_index.pl
+
+AUTO_PAGES= \
+           memcached_increment.pop \
+           memcached_increment_with_initial.pop \
+           memcached_decrement.pop \
+           memcached_decrement_with_initial.pop
+BUILT_SOURCES += ${AUTO_PAGES}
+
+BEHAVIOR_PAGES= \
+               memcached_behavior_get.pop \
+               memcached_behavior_set.pop
+BUILT_SOURCES += ${BEHAVIOR_PAGES}
+
+CALLBACK_PAGES= \
+               memcached_callback_get.pop \
+               memcached_callback_set.pop
+BUILT_SOURCES += ${CALLBACK_PAGES}
+
+CREATE_PAGES= \
+             memcached_clone.pop \
+             memcached_create.pop \
+             memcached_free.pop \
+             memcached_servers_reset.pop
+BUILT_SOURCES += ${CREATE_PAGES}
+
+DELETE_PAGES= \
+             memcached_delete.pop \
+             memcached_delete_by_key.pop
+BUILT_SOURCES += ${DELETE_PAGES}
+
+GENERIC_PAGES= \
+              libmemcached.pop \
+              libmemcached_examples.pop \
+              libmemcachedutil.pop \
+              memcached_analyze.pop \
+              memcached_dump.pop \
+              memcached_flush.pop \
+              memcached_flush_buffers.pop \
+              memcached_generate_hash_value.pop \
+              memcached_quit.pop \
+              memcached_strerror.pop \
+              memcached_verbosity.pop \
+              memcapable.pop \
+              memcat.pop \
+              memcp.pop \
+              memdump.pop \
+              memerror.pop \
+              memflush.pop \
+              memrm.pop \
+              memslap.pop \
+              memstat.pop
+BUILT_SOURCES += ${GENERIC_PAGES}
+
+GET_PAGES= \
+          memcached_get.pop \
+          memcached_get_by_key.pop \
+          memcached_fetch_result.pop \
+          memcached_fetch_execute.pop \
+          memcached_mget.pop \
+          memcached_mget_by_key.pop \
+          memcached_mget_execute.pop \
+          memcached_mget_execute_by_key.pop \
+          memcached_fetch.pop
+BUILT_SOURCES += ${GET_PAGES}
+
+MEMORY_ALLOCATORS_PAGES= \
+                        memcached_get_memory_allocators.pop \
+                        memcached_set_memory_allocators.pop
+BUILT_SOURCES += ${MEMORY_ALLOCATORS_PAGES}
+
+POOL_PAGES= \
+           memcached_pool_behavior_get.pop \
+           memcached_pool_behavior_set.pop \
+           memcached_pool_create.pop \
+           memcached_pool_destroy.pop \
+           memcached_pool_pop.pop \
+           memcached_pool_push.pop 
+BUILT_SOURCES += ${POOL_PAGES}
+
+RESULT_PAGES= \
+             memcached_result_cas.pop \
+             memcached_result_create.pop \
+             memcached_result_flags.pop \
+             memcached_result_free.pop \
+             memcached_result_key_length.pop \
+             memcached_result_key_value.pop \
+             memcached_result_length.pop \
+             memcached_result_st.pop \
+             memcached_result_value.pop
+BUILT_SOURCES += ${RESULT_PAGES}
+
+
+SERVER_PAGES= \
+             memcached_server_count.pop \
+             memcached_server_cursor.pop \
+             memcached_server_list.pop \
+             memcached_server_add.pop \
+             memcached_server_add_unix_socket.pop \
+             memcached_server_push.pop 
+BUILT_SOURCES += ${SERVER_PAGES}
+
+SERVER_ST_PAGES= \
+                memcached_server_list_free.pop \
+                memcached_server_list_count.pop \
+                memcached_server_list_append.pop \
+                memcached_servers_parse.pop 
+BUILT_SOURCES += ${SERVER_ST_PAGES}
+
+SET_PAGES= \
+          memcached_set.pop \
+          memcached_set_by_key.pop \
+          memcached_cas.pop \
+          memcached_cas_by_key.pop \
+          memcached_replace.pop \
+          memcached_replace_by_key.pop \
+          memcached_add.pop \
+          memcached_add_by_key.pop \
+          memcached_prepend.pop \
+          memcached_prepend_by_key.pop \
+          memcached_append.pop \
+          memcached_append_by_key.pop
+BUILT_SOURCES += ${SET_PAGES}
+
+STATS_PAGES= \
+            memcached_stat.pop \
+            memcached_stat_get_keys.pop .pop\
+            memcached_stat_get_value.pop \
+            memcached_stat_servername.pop
+BUILT_SOURCES += ${STATS_PAGES}
+
+USER_DATA_PAGES= \
+                memcached_get_user_data.pop \
+                memcached_set_user_data.pop
+BUILT_SOURCES += ${USER_DATA_PAGES}
+
+VERSION_PAGES= \
+              memcached_version.pop \
+              memcached_lib_version.pop
+BUILT_SOURCES += ${VERSION_PAGES}
+
+
+#
+# These are for libhashkit
+#
+HASHKIT_CREATE_PAGES= \
+                     hashkit_is_allocated.pop \
+                     hashkit_create.pop \
+                     hashkit_clone.pop \
+                     hashkit_free.pop
+BUILT_SOURCES += ${HASHKIT_CREATE_PAGES}
+
+HASHKIT_FUNCTIONS_PAGES= \
+                        hashkit_crc32.pop \
+                        hashkit_fnv1_32.pop \
+                        hashkit_fnv1_64.pop \
+                        hashkit_fnv1a_32.pop \
+                        hashkit_fnv1a_64.pop \
+                        hashkit_functions.pop \
+                        hashkit_hsieh.pop \
+                        hashkit_jenkins.pop \
+                        hashkit_md5.pop \
+                        hashkit_murmur.pop
+BUILT_SOURCES += ${HASHKIT_FUNCTIONS_PAGES}
+
+HASHKIT_ST_PAGES= \
+                 hashkit_value.pop
+BUILT_SOURCES += ${HASHKIT_ST_PAGES}
+
+
+HTML_FILES= \
+           hashkit_clone.html \
+           hashkit_crc32.html \
+           hashkit_create.html \
+           hashkit_fnv1_32.html \
+           hashkit_fnv1_64.html \
+           hashkit_fnv1a_32.html \
+           hashkit_fnv1a_64.html \
+           hashkit_free.html \
+           hashkit_functions.html \
+           hashkit_hsieh.html \
+           hashkit_is_allocated.html \
+           hashkit_jenkins.html \
+           hashkit_md5.html \
+           hashkit_murmur.html \
+           hashkit_value.html \
+           libmemcached_examples.html \
+           libmemcached.html \
+           libmemcachedutil.html \
+           memcached_add_by_key.html \
+           memcached_add.html \
+           memcached_analyze.html \
+           memcached_append_by_key.html \
+           memcached_append.html \
+           memcached_behavior_get.html \
+           memcached_behavior_set.html \
+           memcached_callback_get.html \
+           memcached_callback_set.html \
+           memcached_cas_by_key.html \
+           memcached_cas.html \
+           memcached_clone.html \
+           memcached_create.html \
+           memcached_decrement.html \
+           memcached_decrement_with_initial.html \
+           memcached_delete_by_key.html \
+           memcached_delete.html \
+           memcached_dump.html \
+           memcached_fetch_execute.html \
+           memcached_fetch.html \
+           memcached_fetch_result.html \
+           memcached_flush_buffers.html \
+           memcached_flush.html \
+           memcached_free.html \
+           memcached_generate_hash_value.html \
+           memcached_get_by_key.html \
+           memcached_get_memory_allocators.html \
+           memcached_get.html \
+           memcached_get_user_data.html \
+           memcached_increment.html \
+           memcached_increment_with_initial.html \
+           memcached_lib_version.html \
+           memcached_mget_by_key.html \
+           memcached_mget_execute_by_key.html \
+           memcached_mget_execute.html \
+           memcached_mget.html \
+           memcached_pool_behavior_get.html \
+           memcached_pool_behavior_set.html \
+           memcached_pool_create.html \
+           memcached_pool_destroy.html \
+           memcached_pool_pop.html \
+           memcached_pool_push.html \
+           memcached_prepend_by_key.html \
+           memcached_prepend.html \
+           memcached_quit.html \
+           memcached_replace_by_key.html \
+           memcached_replace.html \
+           memcached_result_cas.html \
+           memcached_result_create.html \
+           memcached_result_flags.html \
+           memcached_result_free.html \
+           memcached_result_key_length.html \
+           memcached_result_key_value.html \
+           memcached_result_length.html \
+           memcached_result_st.html \
+           memcached_result_value.html \
+           memcached_server_add.html \
+           memcached_server_add_unix_socket.html \
+           memcached_server_count.html \
+           memcached_server_cursor.html \
+           memcached_server_list_append.html \
+           memcached_server_list_count.html \
+           memcached_server_list_free.html \
+           memcached_server_list.html \
+           memcached_server_push.html \
+           memcached_servers_parse.html \
+           memcached_set_by_key.html \
+           memcached_set_memory_allocators.html \
+           memcached_set.html \
+           memcached_set_user_data.html \
+           memcached_stat_get_keys.html \
+           memcached_stat_get_value.html \
+           memcached_stat.html \
+           memcached_stat_servername.html \
+           memcached_strerror.html \
+           memcached_verbosity.html \
+           memcached_version.html \
+           memcapable.html \
+           memcat.html \
+           memcp.html \
+           memdump.html \
+           memerror.html \
+           memflush.html \
+           memrm.html \
+           memslap.html \
+           memstat.html
+
+POD_FILES= \
+            hashkit_create.pod \
+            hashkit_functions.pod \
+            hashkit_value.pod \
+            libmemcached.pod \
+            libmemcached_examples.pod \
+            libmemcachedutil.pod \
+            memcached_analyze.pod \
+            memcached_auto.pod \
+            memcached_behavior.pod \
+            memcached_callback.pod \
+            memcached_create.pod \
+            memcached_delete.pod \
+            memcached_dump.pod \
+            memcached_flush.pod \
+            memcached_flush_buffers.pod \
+            memcached_generate_hash_value.pod \
+            memcached_get.pod \
+            memcached_memory_allocators.pod \
+            memcached_pool.pod \
+            memcached_quit.pod \
+            memcached_server_st.pod \
+            memcached_servers.pod \
+            memcached_set.pod \
+            memcached_stats.pod \
+            memcached_strerror.pod \
+            memcached_user_data.pod \
+            memcached_verbosity.pod \
+            memcached_version.pod \
+            memcapable.pod \
+            memcat.pod \
+            memcp.pod \
+            memdump.pod \
+            memerror.pod \
+            memflush.pod \
+            memrm.pod \
+            memslap.pod \
+            memstat.pod
+EXTRA_DIST+= $(POD_FILES)
+
+man_MANS = \
+          hashkit_clone.3 \
+          hashkit_crc32.3 \
+          hashkit_create.3 \
+          hashkit_fnv1_32.3 \
+          hashkit_fnv1_64.3 \
+          hashkit_fnv1a_32.3 \
+          hashkit_fnv1a_64.3 \
+          hashkit_free.3 \
+          hashkit_functions.3 \
+          hashkit_hsieh.3 \
+          hashkit_is_allocated.3 \
+          hashkit_jenkins.3 \
+          hashkit_md5.3 \
+          hashkit_murmur.3 \
+          hashkit_value.3 \
+          libmemcached.3 \
+          libmemcached_examples.3 \
+          memcached_add.3 \
+          memcached_add_by_key.3 \
+          memcached_analyze.3 \
+          memcached_append.3 \
+          memcached_append_by_key.3 \
+          memcached_behavior_get.3 \
+          memcached_behavior_set.3 \
+          memcached_callback_get.3 \
+          memcached_callback_set.3 \
+          memcached_cas.3 \
+          memcached_cas_by_key.3 \
+          memcached_clone.3 \
+          memcached_create.3 \
+          memcached_decrement.3 \
+          memcached_decrement_with_initial.3 \
+          memcached_delete.3 \
+          memcached_delete_by_key.3 \
+          memcached_dump.3 \
+          memcached_fetch.3 \
+          memcached_fetch_execute.3 \
+          memcached_fetch_result.3 \
+          memcached_flush_buffers.3 \
+          memcached_free.3 \
+          memcached_generate_hash_value.3 \
+          memcached_get.3 \
+          memcached_get_by_key.3 \
+          memcached_get_memory_allocators.3 \
+          memcached_get_user_data.3 \
+          memcached_increment.3 \
+          memcached_increment_with_initial.3 \
+          memcached_lib_version.3 \
+          memcached_mget.3 \
+          memcached_mget_by_key.3 \
+          memcached_mget_execute.3  \
+          memcached_mget_execute_by_key.3  \
+          memcached_prepend.3 \
+          memcached_prepend_by_key.3 \
+          memcached_quit.3 \
+          memcached_replace.3 \
+          memcached_replace_by_key.3 \
+          memcached_server_add.3 \
+          memcached_server_count.3 \
+          memcached_server_cursor.3 \
+          memcached_server_list.3 \
+          memcached_server_list_append.3 \
+          memcached_server_list_count.3 \
+          memcached_server_list_free.3 \
+          memcached_server_push.3 \
+          memcached_servers_parse.3 \
+          memcached_set.3 \
+          memcached_set_by_key.3 \
+          memcached_set_memory_allocators.3 \
+          memcached_set_user_data.3 \
+          memcached_stat.3 \
+          memcached_stat_get_keys.3 \
+          memcached_stat_get_value.3 \
+          memcached_stat_servername.3 \
+          memcached_strerror.3 \
+          memcached_verbosity.3 \
+          memcached_version.3 \
+          memcapable.1 \
+          memcat.1 \
+          memcp.1 \
+          memdump.1 \
+          memerror.1 \
+          memflush.1 \
+          memrm.1 \
+          memslap.1 \
+          memstat.1
 
 if BUILD_LIBMEMCACHEDUTIL
-man_MANS+= libmemcachedutil.3 \
-       memcached_pool_behavior_set.3 \
-       memcached_pool_behavior_get.3 \
-       memcached_pool_create.3 \
-       memcached_pool_destroy.3 \
-       memcached_pool_push.3 \
-       memcached_pool_pop.3
+man_MANS+= \
+         libmemcachedutil.3 \
+         memcached_pool_behavior_set.3 \
+         memcached_pool_behavior_get.3 \
+         memcached_pool_create.3 \
+         memcached_pool_destroy.3 \
+         memcached_pool_push.3 \
+         memcached_pool_pop.3
 endif
 
 
-libmemcached.3: libmemcached.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/libmemcached.pod > libmemcached.3
+${CREATE_PAGES}: 
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_create.pod ${top_builddir}/docs/$@
 
-libmemcachedutil.3: libmemcachedutil.pod
-       ${POD2MAN} -c "libmemcachedutil" -r "" -s 3 ${top_srcdir}/docs/libmemcachedutil.pod > libmemcachedutil.3
+${SET_PAGES}: 
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_set.pod ${top_builddir}/docs/$@
 
-libmemcached_examples.3: libmemcached_examples.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/libmemcached_examples.pod > libmemcached_examples.3
+${DELETE_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_delete.pod ${top_builddir}/docs/$@
 
-memcached_create.3: memcached_create.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_create.pod > memcached_create.3
+${AUTO_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_auto.pod ${top_builddir}/docs/$@
 
-memcached_free.3: memcached_create.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_create.pod > memcached_free.3
+${GET_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_get.pod ${top_builddir}/docs/$@
 
-memcached_clone.3: memcached_create.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_create.pod > memcached_clone.3
+${SERVER_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_servers.pod ${top_builddir}/docs/$@
 
-memcached_set.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_set.3
+${SERVER_ST_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_server_st.pod ${top_builddir}/docs/$@
 
-memcached_set_by_key.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_set_by_key.3
+${GENERIC_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/$*.pod ${top_builddir}/docs/$@
 
-memcached_cas.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_cas.3
+${BEHAVIOR_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_behavior.pod ${top_builddir}/docs/$@
 
-memcached_cas_by_key.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_cas_by_key.3
+${CALLBACK_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_callback.pod ${top_builddir}/docs/$@
 
-memcached_replace.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_replace.3
+${STATS_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_stats.pod ${top_builddir}/docs/$@
 
-memcached_replace_by_key.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_replace_by_key.3
+${RESULT_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_result_st.pod ${top_builddir}/docs/$@
 
-memcached_add.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_add.3
+${VERSION_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_version.pod ${top_builddir}/docs/$@
 
-memcached_add_by_key.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_add_by_key.3
+${MEMORY_ALLOCATORS_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_memory_allocators.pod ${top_builddir}/docs/$@
 
-memcached_prepend.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_prepend.3
+${USER_DATA_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_user_data.pod ${top_builddir}/docs/$@
 
-memcached_prepend_by_key.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_prepend_by_key.3
 
-memcached_append.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_append.3
+${POOL_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/memcached_pool.pod ${top_builddir}/docs/$@
 
-memcached_append_by_key.3: memcached_set.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_set.pod > memcached_append_by_key.3
+${HASHKIT_CREATE_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/hashkit_create.pod ${top_builddir}/docs/$@
 
-memcached_delete.3: memcached_delete.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_delete.pod > memcached_delete.3
 
-memcached_delete_by_key.3: memcached_delete.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_delete.pod > memcached_delete_by_key.3
+${HASHKIT_FUNCTIONS_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/hashkit_functions.pod ${top_builddir}/docs/$@
 
-memcached_increment.3:
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_auto.pod > memcached_increment.3
+${HASHKIT_ST_PAGES}:
+       @rm -f $@
+       ln -s ${top_srcdir}/docs/hashkit_value.pod ${top_builddir}/docs/$@
 
-memcached_increment_with_initial.3:
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_auto.pod > memcached_increment_with_initial.3
+test-docs: $(POD_FILES)
+       ${PODCHECKER} $(top_srcdir)/docs/$?
 
-memcached_decrement.3:
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_auto.pod > memcached_decrement.3
+html-local: html-pages html-index
 
-memcached_decrement_with_initial.3:
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_auto.pod > memcached_decrement_with_initial.3
+html-pages: $(HTML_FILES) 
 
-memcached_dump.3: memcached_dump.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_dump.pod > memcached_dump.3
+html-index: html-pages
+       perl make_index.pl *.html > index.html
 
-memcached_flush.3: memcached_flush.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_flush.pod > memcached_flush.3
+SUFFIXES= .pop .pod .html .1 .3
 
-memcached_get.3: memcached_get.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_get.pod > memcached_get.3
+.pop: ${_set}
 
-memcached_get_by_key.3: memcached_get.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_get.pod > memcached_get_by_key.3
+.pop.html:
+       pod2html --infile=$< >  $@
 
-memcached_fetch_result.3: memcached_get.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_get.pod > memcached_fetch_result.3
-
-memcached_fetch_execute.3: memcached_get.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_get.pod > memcached_fetch_execute.3
-
-memcached_mget.3: memcached_get.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_get.pod > memcached_mget.3
-
-memcached_mget_by_key.3: memcached_get.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_get.pod > memcached_mget_by_key.3
-
-memcached_mget_execute.3: memcached_get.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_get.pod > memcached_mget_execute.3
-
-memcached_mget_execute_by_key.3: memcached_get.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_get.pod > memcached_mget_execute_by_key.3
-
-memcached_fetch.3: memcached_get.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_get.pod > memcached_fetch.3
-
-memcached_quit.3: memcached_quit.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_quit.pod > memcached_quit.3
-
-memcached_strerror.3: memcached_strerror.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_strerror.pod > memcached_strerror.3
-
-memcached_server_count.3: memcached_servers.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_servers.pod > memcached_server_count.3
-
-memcached_server_list.3: memcached_servers.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_servers.pod > memcached_server_list.3
-
-memcached_server_add.3: memcached_servers.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_servers.pod > memcached_server_add.3
-
-memcached_server_add_unix_socket.3: memcached_servers.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_servers.pod > memcached_server_add_unix_socket.3
-
-memcached_server_push.3: memcached_servers.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_servers.pod > memcached_server_push.3
-
-memcached_server_list_free.3: memcached_server_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_server_st.pod > memcached_server_list_free.3
-
-memcached_server_list_count.3: memcached_server_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_server_st.pod > memcached_server_list_count.3
-
-memcached_server_list_append.3: memcached_server_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_server_st.pod > memcached_server_list_append.3
-
-memcached_servers_parse.3: memcached_server_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_server_st.pod > memcached_servers_parse.3
-
-memcached_verbosity.3: memcached_verbosity.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_verbosity.pod > memcached_verbosity.3
-
-memcached_behavior_get.3: memcached_behavior.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_behavior.pod > memcached_behavior_get.3
-
-memcached_behavior_set.3: memcached_behavior.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_behavior.pod > memcached_behavior_set.3
-
-memcached_callback_get.3: memcached_callback.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_callback.pod > memcached_callback_get.3
-
-memcached_callback_set.3: memcached_callback.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_callback.pod > memcached_callback_set.3
-
-memcached_stat.3: memcached_stats.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_stats.pod > memcached_stat.3
-
-memcached_stat_servername.3: memcached_stats.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_stats.pod > memcached_stat_servername.3
-
-memcached_stat_get_value.3: memcached_stats.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_stats.pod > memcached_stat_get_value.3
-
-memcached_stat_get_keys.3: memcached_stats.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_stats.pod > memcached_stat_get_keys.3
-
-memcached_result_st.3: memcached_result_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_result_st.pod > memcached_result_st.3
-
-memcached_result_create.3: memcached_result_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_result_st.pod > memcached_result_create.3
-
-memcached_result_free.3: memcached_result_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_result_st.pod > memcached_result_free.3
-
-memcached_result_key_value.3: memcached_result_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_result_st.pod > memcached_result_key_value.3
-
-memcached_result_key_length.3: memcached_result_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_result_st.pod > memcached_result_key_length.3
-
-memcached_result_value.3: memcached_result_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_result_st.pod > memcached_result_value.3
-
-memcached_result_length.3: memcached_result_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_result_st.pod > memcached_result_length.3
-
-memcached_result_flags.3: memcached_result_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_result_st.pod > memcached_result_flags.3
-
-memcached_result_cas.3: memcached_result_st.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_result_st.pod > memcached_result_cas.3
-
-memcached_version.3: memcached_version.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_version.pod > memcached_version.3
-
-memcached_lib_version.3: memcached_version.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_version.pod  > memcached_lib_version.3
-
-memcached_flush_buffers.3: memcached_flush_buffers.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_flush_buffers.pod  > memcached_flush_buffers.3
-
-memcached_analyze.3: memcached_analyze.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_analyze.pod > memcached_analyze.3
-
-memcached_generate_hash_value.3: memcached_generate_hash_value.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_generate_hash_value.pod > memcached_generate_hash_value.3
-
-memcached_get_memory_allocators.3: memcached_memory_allocators.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_memory_allocators.pod > memcached_get_memory_allocators.3
-
-memcached_set_memory_allocators.3: memcached_memory_allocators.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_memory_allocators.pod > memcached_set_memory_allocators.3
-
-memcached_get_user_data.3: memcached_user_data.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_user_data.pod > memcached_get_user_data.3
-
-memcached_set_user_data.3: memcached_user_data.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 3 ${top_srcdir}/docs/memcached_user_data.pod > memcached_set_user_data.3
-
-memcached_pool_behavior_get.3: memcached_pool.pod
-       ${POD2MAN} -c "libmemcachedutil" -r "" -s 3 ${top_srcdir}/docs/memcached_pool.pod > memcached_pool_behavior_get.3
-
-memcached_pool_behavior_set.3: memcached_pool.pod
-       ${POD2MAN} -c "libmemcachedutil" -r "" -s 3 ${top_srcdir}/docs/memcached_pool.pod > memcached_pool_behavior_set.3
-
-memcached_pool_create.3: memcached_pool.pod
-       ${POD2MAN} -c "libmemcachedutil" -r "" -s 3 ${top_srcdir}/docs/memcached_pool.pod > memcached_pool_create.3
-
-memcached_pool_destroy.3: memcached_pool.pod
-       ${POD2MAN} -c "libmemcachedutil" -r "" -s 3 ${top_srcdir}/docs/memcached_pool.pod > memcached_pool_destroy.3
-
-memcached_pool_pop.3: memcached_pool.pod
-       ${POD2MAN} -c "libmemcachedutil" -r "" -s 3 ${top_srcdir}/docs/memcached_pool.pod > memcached_pool_pop.3
-
-memcached_pool_push.3: memcached_pool.pod
-       ${POD2MAN} -c "libmemcachedutil" -r "" -s 3 ${top_srcdir}/docs/memcached_pool.pod > memcached_pool_push.3
-
-memcp.1: memcp.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 1 ${top_srcdir}/docs/memcp.pod > memcp.1
-
-memslap.1: memslap.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 1 ${top_srcdir}/docs/memslap.pod > memslap.1
-
-memcapable.1: memcapable.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 1 ${top_srcdir}/docs/memcapable.pod > memcapable.1
-
-memcat.1: memcat.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 1 ${top_srcdir}/docs/memcat.pod > memcat.1
-
-memstat.1: memstat.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 1 ${top_srcdir}/docs/memstat.pod > memstat.1
-
-memrm.1: memrm.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 1 ${top_srcdir}/docs/memrm.pod > memrm.1
-
-memerror.1: memerror.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 1 ${top_srcdir}/docs/memerror.pod > memerror.1
-
-memdump.1: memdump.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 1 ${top_srcdir}/docs/memdump.pod > memdump.1
-
-memflush.1: memflush.pod
-       ${POD2MAN} -c "libmemcached" -r "" -s 1 ${top_srcdir}/docs/memflush.pod > memflush.1
-
-test:
-       podchecker $(top_srcdir)/docs/libmemcached.pod
-       podchecker $(top_srcdir)/docs/memcached_flush.pod
-       podchecker $(top_srcdir)/docs/memcached_stats.pod
-       podchecker $(top_srcdir)/docs/memrm.pod
-       podchecker $(top_srcdir)/docs/memerror.pod
-       podchecker $(top_srcdir)/docs/libmemcached_examples.pod
-       podchecker $(top_srcdir)/docs/memcached_get.pod
-       podchecker $(top_srcdir)/docs/memcached_strerror.pod
-       podchecker $(top_srcdir)/docs/memslap.pod
-       podchecker $(top_srcdir)/docs/memcached_auto.pod
-       podchecker $(top_srcdir)/docs/memcached_quit.pod
-       podchecker $(top_srcdir)/docs/memcached_verbosity.pod
-       podchecker $(top_srcdir)/docs/memstat.pod
-       podchecker $(top_srcdir)/docs/memcached_behavior.pod
-       podchecker $(top_srcdir)/docs/memcached_callback.pod
-       podchecker $(top_srcdir)/docs/memcached_server_st.pod
-       podchecker $(top_srcdir)/docs/memcat.pod
-       podchecker $(top_srcdir)/docs/memcached_create.pod
-       podchecker $(top_srcdir)/docs/memcached_servers.pod
-       podchecker $(top_srcdir)/docs/memcp.pod
-       podchecker $(top_srcdir)/docs/memcached_delete.pod
-       podchecker $(top_srcdir)/docs/memcached_set.pod
-       podchecker $(top_srcdir)/docs/memcached_version.pod
-       podchecker $(top_srcdir)/docs/memflush.pod
-       podchecker $(top_srcdir)/docs/memcached_flush_buffers.pod
-       podchecker $(top_srcdir)/docs/memcached_pool.pod
-       podchecker $(top_srcdir)/docs/memcached_memory_allocators.pod
-       podchecker $(top_srcdir)/docs/memcached_user_data.pod
-       podchecker $(top_srcdir)/docs/memcapable.pod
-
-html-local:
-       pod2htmltree "/libmemcached" .
+.pop.1:
+       ${POD2MAN} -c "$*" -r "" -s 1 $< >  $@
 
+.pop.3:
+       ${POD2MAN} -c "$*" -r "" -s 3 $< >  $@
diff --git a/docs/hashkit_create.pod b/docs/hashkit_create.pod
new file mode 100644 (file)
index 0000000..bcd5390
--- /dev/null
@@ -0,0 +1,57 @@
+=head1 NAME
+
+hashkit_create, hashkit_clone, hashkit_free, hashkit_is_allocated -
+Create and destroy hashkit objects
+
+=head1 LIBRARY
+
+C Library for hashing algorithms (libhashkit, -lhashkit)
+
+=head1 SYNOPSIS
+
+  #include <libhashkit/hashkit.h>
+
+  hashkit_st *hashkit_create(hashkit_st *hash);
+
+  hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr);
+
+  void hashkit_free(hashkit_st *hash);
+
+  bool hashkit_is_allocated(const hashkit_st *hash);
+
+=head1 DESCRIPTION
+
+The hashkit_create() function initializes a hashkit object for use. If
+you pass a NULL argument for hash, then the memory for the object is
+allocated. If you specify a pre-allocated piece of memory, that is
+initialized for use.
+
+The hashkit_clone() function initializes a hashkit object much like
+hashkit_create(), but instead of using default settings it will use
+the settings of the ptr hashkit object.
+
+The hashkit_free() frees any resources being consumed by the hashkit
+objects that were initialized with hashkit_create() or hashkit_clone().
+
+The hashkit_is_allocated() reports where the memory was allocated 
+for a hashkit object.
+
+=head1 RETURN VALUE
+
+hashkit_create() and hashkit_clone() will return NULL on failure or
+non-NULL on success.
+
+hashkit_is_allocated() returns true if the memory for the hashkit
+object was allocated inside of hashkit_create() or hashkit_clone(),
+otherwise it is false and was user-supplied memory.
+
+=head1 HOME
+
+To find out more information please check:
+L<https://launchpad.net/libmemcached>
+
+=head1 AUTHOR
+
+Brian Aker, E<lt>brian@tangent.orgE<gt>
+
+=cut
diff --git a/docs/hashkit_functions.pod b/docs/hashkit_functions.pod
new file mode 100644 (file)
index 0000000..4af8418
--- /dev/null
@@ -0,0 +1,54 @@
+=head1 NAME
+
+hashkit_default, hashkit_fnv1_64, hashkit_fnv1a_64, hashkit_fnv1_32,
+hashkit_fnv1a_32, hashkit_crc32, hashkit_hsieh, hashkit_murmur,
+hashkit_jenkins, hashkit_md5 - Various hash functions to use for
+calculating values for keys
+
+=head1 LIBRARY
+
+C Library for hashing algorithms (libhashkit, -lhashkit)
+
+=head1 SYNOPSIS
+
+  #include <libhashkit/hashkit.h>
+
+  uint32_t hashkit_default(const char *key, size_t key_length);
+  uint32_t hashkit_fnv1_64(const char *key, size_t key_length);
+  uint32_t hashkit_fnv1a_64(const char *key, size_t key_length);
+  uint32_t hashkit_fnv1_32(const char *key, size_t key_length);
+  uint32_t hashkit_fnv1a_32(const char *key, size_t key_length);
+  uint32_t hashkit_crc32(const char *key, size_t key_length);
+  uint32_t hashkit_hsieh(const char *key, size_t key_length);
+  uint32_t hashkit_murmur(const char *key, size_t key_length);
+  uint32_t hashkit_jenkins(const char *key, size_t key_length);
+  uint32_t hashkit_md5(const char *key, size_t key_length);
+
+=head1 DESCRIPTION
+
+These functions generate hash values from a key using a variety of
+algorithms. These functions can be used standalone, or as arguments
+to hashkit_set_hash_fn(3) or hashkit_set_continuum_hash_fn(3).
+
+The hashkit_hsieh() is only available if the library is built with
+the appropriate flag enabled.
+
+=head1 RETURN VALUE
+
+A 32-bit hash value.
+
+=head1 HOME
+
+To find out more information please check:
+L<https://launchpad.net/libmemcached>
+
+=head1 AUTHOR
+
+Brian Aker, E<lt>brian@tangent.orgE<gt>
+
+=head1 SEE ALSO
+
+hashkit_create(3) hashkit_value(3) hashkit_set_hash_fn(3)
+hashkit_set_continuum_hash_fn(3)
+
+=cut
diff --git a/docs/hashkit_value.pod b/docs/hashkit_value.pod
new file mode 100644 (file)
index 0000000..db594bc
--- /dev/null
@@ -0,0 +1,41 @@
+=head1 NAME
+
+hashkit_value - Generate a value for the given key
+
+=head1 LIBRARY
+
+C Library for hashing algorithms (libhashkit, -lhashkit)
+
+=head1 SYNOPSIS
+
+  #include <libhashkit/hashkit.h>
+
+  uint32_t hashkit_value(hashkit_st *hash,
+                         const char *key,
+                         size_t key_length);
+
+=head1 DESCRIPTION
+
+The hashkit_value() function generates a 32-bit hash value from the
+given key and key_length. The hash argument is an initialized hashkit
+object, and distribution type and hash function is used from this
+object while generating the value.
+
+=head1 RETURN VALUE
+
+A 32-bit hash value.
+
+=head1 HOME
+
+To find out more information please check:
+L<https://launchpad.net/libmemcached>
+
+=head1 AUTHOR
+
+Brian Aker, E<lt>brian@tangent.orgE<gt>
+
+=head1 SEE ALSO
+
+hashkit_create(3) hashkit_set_distribution(3) hashkit_set_hash_fn(3)
+
+=cut
index e1a95a73eebdd34bfcf69a8b5e355c37f75437be..46fc2da0d42c7e257e7fa4215fa648ea6576abf1 100644 (file)
@@ -32,7 +32,7 @@ allocated and then initialized by memcached_create(). Functions have been
 written in order to encapsulate the C<memcached_st>. It is not
 recommended that you operate directly against the structure.
 
-Nearly all functions return a C<memcached_return> value.
+Nearly all functions return a C<memcached_return_t> value.
 This value can be translated to a printable string with memcached_strerror(3).
 
 Partitioning based on keys is supported in the library. Using the key partioning 
@@ -113,7 +113,7 @@ structure.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 510c920693ae331e3828b9d6e7d98fcf179aa928..1c937fe7c9b41fcbb0de74eed346bfab2b04ef47 100644 (file)
@@ -11,7 +11,7 @@ the library.
 =head2 Creating and Freeing structure
 
   memcached_st *memc;
-  memcached_return rc;
+  memcached_return_t rc;
 
   memc= memcached_create(NULL);
   ...do stuff...
@@ -74,7 +74,7 @@ It is best practice to always look at the return value of any operation.
 
 =head2 Fetching multiple values
 
-  memcached_return rc;
+  memcached_return_t rc;
   char *keys[]= {"fudge", "son", "food"};
   size_t key_length[]= {5, 3, 4};
   unsigned int x;
@@ -101,7 +101,7 @@ C<MEMCACHED_MAX_KEY> is provided for usage.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index be410ecd1eaba8d03d73d73972aa4cf0d868ee22..fd2e4f6274bef2564f705e2555b6327c15d34ae6 100644 (file)
@@ -27,11 +27,11 @@ implementation. see memcached_pool_create(3).
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
-Trond Norbye, E<lt>trond.norbye@sun.comE<gt>
+Trond Norbye, E<lt>trond.norbye@gmail.comE<gt>
 
 =head1 SEE ALSO
 
diff --git a/docs/make_index.pl b/docs/make_index.pl
new file mode 100644 (file)
index 0000000..cb0d190
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/perl -w
+
+use strict;
+use CGI;
+
+sub main {
+  my $cgi = new CGI;
+
+  print $cgi->start_html('Libmemcached Documentation') . "\n";
+  print $cgi->h1('Libmemcached Documentation') . "\n";
+
+  print $cgi->a({ href => "libmemcached.html" }, "Introduction to Libmemcached") . $cgi->br() . "\n";
+  print $cgi->a({ href => "libmemcached_examples.html" }, "Libmemcached Examples") . $cgi->br() . "\n";
+  print $cgi->br() . "\n";
+  print $cgi->br() . "\n";
+
+  foreach (@ARGV)
+  {
+    my $url=  $_;
+    my $name= $_;
+    $name  =~ s/\.html//g;
+    next if $name eq 'index'; 
+    next if $name eq 'libmemcached'; 
+    next if $name eq 'libmemcached_examples'; 
+    print "<li\>" . $cgi->a({ href => $url }, $name) . $cgi->br() . "\n";
+  }
+  print $cgi->end_html; 
+}
+
+main();
index 346a1bdb27a8a5cf7acbf3a9f2569f47ace65c9e..9c0401f8de7a39106e62ed161655b26ee4609680 100644 (file)
@@ -10,9 +10,10 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  memcached_analysis_st *memcached_analyze(memcached_st *ptr,
-                                           memcached_stat_st *stat,
-                                           memcached_return *error);
+  memcached_analysis_st *
+    memcached_analyze (memcached_st *ptr,
+                       memcached_stat_st *stat,
+                       memcached_return_t *error);
 
 =head1 DESCRIPTION
 
@@ -31,7 +32,7 @@ you do not have to write an application to use this method.
 
 A pointer to the allocated C<memcached_analysis_st> structure on success and
 a NULL pointer on failure. You may inspect the error detail by checking the
-C<memcached_return> value.
+C<memcached_return_t> value.
 
 Any method returning a C<memcached_analysis_st> expects you to free the
 memory allocated for it.
@@ -39,7 +40,7 @@ memory allocated for it.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 482ac77c2b3b6ed66aaea4f250a33b8dbf2fa78c..bd6da19242e707cca39c022e835eab779b13a236 100644 (file)
@@ -12,19 +12,19 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  memcached_return
+  memcached_return_t
     memcached_increment (memcached_st *ptr, 
                          const char *key, size_t key_length,
                          unsigned int offset,
                          uint64_t *value);
 
-  memcached_return
+  memcached_return_t
     memcached_decrement (memcached_st *ptr, 
                          const char *key, size_t key_length,
                          unsigned int offset,
                          uint64_t *value);
 
-  memcached_return
+  memcached_return_t
     memcached_increment_with_initial (memcached_st *ptr,
                                       const char *key,
                                       size_t key_length,
@@ -33,7 +33,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
                                       time_t expiration,
                                       uint64_t *value);
 
-  memcached_return
+  memcached_return_t
     memcached_decrement_with_initial (memcached_st *ptr,
                                       const char *key,
                                       size_t key_length,
@@ -42,21 +42,21 @@ C Client Library for memcached (libmemcached, -lmemcached)
                                       time_t expiration,
                                       uint64_t *value);
 
-  memcached_return
+  memcached_return_t
     memcached_increment_by_key (memcached_st *ptr, 
                                 const char *master_key, size_t master_key_length,
                                 const char *key, size_t key_length,
                                 unsigned int offset,
                                 uint64_t *value);
 
-  memcached_return
+  memcached_return_t
     memcached_decrement_by_key (memcached_st *ptr, 
                                 const char *master_key, size_t master_key_length,
                                 const char *key, size_t key_length,
                                 unsigned int offset,
                                 uint64_t *value);
 
-  memcached_return
+  memcached_return_t
     memcached_increment_with_initial_by_key (memcached_st *ptr,
                                              const char *master_key,
                                              size_t master_key_length,
@@ -67,7 +67,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
                                              time_t expiration,
                                              uint64_t *value);
 
-  memcached_return
+  memcached_return_t
     memcached_decrement_with_initial_by_key (memcached_st *ptr,
                                              const char *master_key,
                                              size_t master_key_length,
@@ -117,14 +117,14 @@ above.
 
 =head1 RETURN
 
-A value of type C<memcached_return> is returned.
+A value of type C<memcached_return_t> is returned.
 On success that value will be C<MEMCACHED_SUCCESS>.
 Use memcached_strerror() to translate this value to a printable string.
 
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index dd7184541743adf05d6dcdcbe15649db76ffb497..2e0240afbe4c0c88a9463e22267739dc79f3543e 100644 (file)
@@ -14,7 +14,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
     memcached_behavior_get (memcached_st *ptr,
                             memcached_behavior flag);
 
-  memcached_return
+  memcached_return_t
     memcached_behavior_set (memcached_st *ptr,
                             memcached_behavior flag,
                             uint64_t data);
@@ -83,7 +83,7 @@ environments).
 
 Makes the default hashing algorithm for keys use MD5. The value can be set
 to either MEMCACHED_HASH_DEFAULT, MEMCACHED_HASH_MD5, MEMCACHED_HASH_CRC, MEMCACHED_HASH_FNV1_64, MEMCACHED_HASH_FNV1A_64, MEMCACHED_HASH_FNV1_32, MEMCACHED_HASH_FNV1A_32, MEMCACHED_HASH_JENKINS, MEMCACHED_HASH_HSIEH, and MEMCACHED_HASH_MURMUR.
-Each hash has it's advantages and it's weaknesses. If you dont know or dont care, just go with the default.
+Each hash has it's advantages and it's weaknesses. If you don't know or don't care, just go with the default.
 Support for MEMCACHED_HASH_HSIEH is a compile time option that is disabled by default. To enable support for this hashing algorithm, configure and build libmemcached with the --enable-hash_hsieh.
 
 =item MEMCACHED_BEHAVIOR_DISTRIBUTION
@@ -209,6 +209,37 @@ This replication does not dedicate certain memcached servers to store the
 replicas in, but instead it will store the replicas together with all of the
 other objects (on the 'n' next servers specified in your server list).
 
+=item MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ
+
+Allows randomizing the replica reads starting point. Normally the read is 
+done from primary server and in case of miss the read is done from primary
++ 1, then primary + 2 all the way to 'n' replicas. If this option is set 
+on the starting point of the replica reads is randomized between the servers.
+This allows distributing read load to multiple servers with the expense of 
+more write traffic.
+
+=item MEMCACHED_BEHAVIOR_CORK
+
+Enable TCP_CORK behavior. This is only available as an option Linux.
+MEMCACHED_NO_SERVERS is returned if no servers are available to test with.
+MEMCACHED_NOT_SUPPORTED is returned if we were not able to determine
+if support was available. All other responses then MEMCACHED_SUCCESS
+report an error of some sort. This behavior also enables 
+MEMCACHED_BEHAVIOR_TCP_NODELAY when set.
+
+
+=item MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE
+
+Find the current size of SO_SNDBUF. A value of 0 means either an error
+occured or no hosts were available. It is safe to assume system default
+if this occurs.
+
+=item MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE
+
+Find the current size of SO_RCVBUF. A value of 0 means either an error
+occured or no hosts were available. It is safe to assume system default
+if this occurs.
+
 =back
 
 =head1 RETURN
@@ -225,7 +256,7 @@ to data value, to taking a uin64_t.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 6eba4f3263080ed910bba2ebeb00324c2dca7a63..9175c29d2dc841b67b77a0fe53bbb151a91b6978 100644 (file)
@@ -10,15 +10,15 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  memcached_return 
+  memcached_return_t 
     memcached_callback_set (memcached_st *ptr, 
-                            memcached_callback flag, 
+                            memcached_callback_t flag, 
                             void *data);
 
   void *
     memcached_callback_get (memcached_st *ptr, 
-                            memcached_callback flag,
-                            memcached_return *error);
+                            memcached_callback_t flag,
+                            memcached_return_t *error);
 
 =head1 DESCRIPTION
 
@@ -84,7 +84,7 @@ 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 (*memcached_trigger_key)(memcached_st *ptr, char *key, size_t key_length, memcached_result_st *result);
+memcached_return_t (*memcached_trigger_key)(memcached_st *ptr, char *key, size_t key_length, memcached_result_st *result);
 
 =item  MEMCACHED_CALLBACK_DELETE_TRIGGER
 
@@ -92,7 +92,7 @@ This function implements a trigger upon successful deletion of a key. The memcac
 in order to make use of it.
 
 The prototype for this is:
-typedef memcached_return (*memcached_trigger_delete_key)(memcached_st *ptr, char *key, size_t key_length);
+typedef memcached_return_t (*memcached_trigger_delete_key)(memcached_st *ptr, char *key, size_t key_length);
 
 
 =back
@@ -100,7 +100,7 @@ typedef memcached_return (*memcached_trigger_delete_key)(memcached_st *ptr, char
 =head1 RETURN
 
 memcached_callback_get() return the function or structure that was provided.
-Upon error, nothing is set, null is returned, and the memcached_return
+Upon error, nothing is set, null is returned, and the memcached_return_t
 argument is set to MEMCACHED_FAILURE.
 
 memcached_callback_set() returns MEMCACHED_SUCCESS upon successful setting,
@@ -109,7 +109,7 @@ otherwise MEMCACHED_FAILURE on error.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 6150f0024cad3dde4ab397ee87c79a2e2c023a56..4323723b722101420a6f5ea991831caf29bb732b 100644 (file)
@@ -1,6 +1,6 @@
 =head1 NAME
 
-memcached_create, memcached_free - Create a memcached_st structure
+memcached_create, memcached_free, memcached_clone, memcached_servers_reset- Create a memcached_st structure
 
 =head1 LIBRARY
 
@@ -14,7 +14,9 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   void memcached_free (memcached_st *ptr);
 
-  memcached_st *memcached_clone(memcached_st *clone, memcached_st *source);
+  memcached_st *memcached_clone (memcached_st *destination, memcached_st *source);
+
+  void memcached_servers_reset(memcached_st);
 
 =head1 DESCRIPTION
 
@@ -26,28 +28,32 @@ a NULL. If a NULL passed in then a structure is allocated for you.
 memcached_clone() is similar to memcached_create(3) but it copies the
 defaults and list of servers from the source C<memcached_st>. If you pass a null as
 the argument for the source to clone, it is the same as a call to memcached_create().
-If the clone argument is NULL a C<memcached_st> will be allocated for you.
-If you pass a pointer to a memory area for the clone pointer, make sure you 
-memset it to 0 (unless you got the clone from a factory method in libmemcached).
+If the destination argument is NULL a C<memcached_st> will be allocated for you.
+
+memcached_servers_reset() allows you to zero out the list of servers that
+the memcached_st has.
 
 To clean up memory associated with a C<memcached_st> structure you should pass
 it to memcached_free() when you are finished using it. memcached_free() is
 the only way to make sure all memory is deallocated when you finish using
 the structure.
 
+You may wish to avoid using memcached_create(3) or memcached_clone(3) with a
+stack based allocation. The most common issues related to ABI safety involve
+heap allocated structures.
+
 =head1 RETURN
 
 memcached_create() returns a pointer to the memcached_st that was created
 (or initialized). On an allocation failure, it returns NULL.
 
 memcached_clone() returns a pointer to the memcached_st that was created
-(or initialized). On an allocation failure, it returns NULL. If you pass in 
-a preallocated structure it must be cleared first (aka memset()).
+(or initialized). On an allocation failure, it returns NULL.
 
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 4a4c76e562572a75555ffa35e6bb41df8598a505..89bff56a28bb05cf97b08a1e7403a8f384b333e9 100644 (file)
@@ -10,12 +10,12 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  memcached_return
+  memcached_return_t
     memcached_delete (memcached_st *ptr,
                       const char *key, size_t key_length,
                       time_t expiration);
 
-  memcached_return
+  memcached_return_t
   memcached_delete_by_key (memcached_st *ptr,
                            const char *master_key, size_t master_key_length,
                            const char *key, size_t key_length,
@@ -34,7 +34,7 @@ find the given value.
 
 =head1 RETURN
 
-A value of type C<memcached_return> is returned
+A value of type C<memcached_return_t> is returned
 On success that value will be C<MEMCACHED_SUCCESS>.
 Use memcached_strerror() to translate this value to a printable string.
 
@@ -44,7 +44,7 @@ means that the message was queued for delivery.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index a80a60d6a76c604eb0f0c9e31444107edb3d0f98..2d53701635e17b016ad53793cb3ccc3dfa33930d 100644 (file)
@@ -10,13 +10,13 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  memcached_return
+  memcached_return_t
     memcached_dump (memcached_st *ptr, 
-                    memcached_dump_func *function, 
+                    memcached_dump_fn *function, 
                     void *context, 
                     uint32_t number_of_callbacks);
 
-  typedef memcached_return (*memcached_dump_func)(memcached_st *ptr,  
+  typedef memcached_return_t (*memcached_dump_fn)(memcached_st *ptr,  
                                                   const char *key, 
                                                   size_t key_length, 
                                                   void *context);
@@ -32,14 +32,14 @@ Currently the binar protocol is not supported.
 
 =head1 RETURN
 
-A value of type C<memcached_return> is returned
+A value of type C<memcached_return_t> is returned
 On success that value will be C<MEMCACHED_SUCCESS>.
 Use memcached_strerror() to translate this value to a printable string.
 
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 0249fdaba88c5507d69422347e8008d08d5510f2..0ca9547226fdce5bd35f26f7e04b406645e9b781 100644 (file)
@@ -10,7 +10,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  memcached_return
+  memcached_return_t
     memcached_flush (memcached_st *ptr,
                      time_t expiration);
 
@@ -25,14 +25,14 @@ added.
 
 =head1 RETURN
 
-A value of type C<memcached_return> is returned
+A value of type C<memcached_return_t> is returned
 On success that value will be C<MEMCACHED_SUCCESS>.
 Use memcached_strerror() to translate this value to a printable string.
 
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index a655e70bdea41d119c279f636f7d3094e5c64e4a..11c06dc0d706186d0a1b1ed17a990e98c230aec9 100644 (file)
@@ -10,29 +10,29 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  memcached_return
+  memcached_return_t
     memcached_flush_buffers (memcached_st *ptr);
 
 =head1 DESCRIPTION
 
 memcached_flush_buffers() is used in conjunction with 
 MEMCACHED_BEHAVIOR_BUFFER_REQUESTS (see memcached_behavior(3)) to flush
-all buffers by sending the buffered commands to the server for processing..
+all buffers by sending the buffered commands to the server for processing.
 
 =head1 RETURN
 
-A value of type C<memcached_return> is returned
+A value of type C<memcached_return_t> is returned
 On success that value will be C<MEMCACHED_SUCCESS>.
 Use memcached_strerror() to translate this value to a printable string.
 
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
-Trond Norbye, E<lt>trond.norbye@sun.comE<gt>
+Trond Norbye, E<lt>trond.norbye@gmail.comE<gt>
 
 =head1 SEE ALSO
 
index dd45ab3ea22b41458d4bdf1996fc821c100367f9..a2af1fc4e8af57981f49c40cc98df51023a48dd2 100644 (file)
@@ -13,7 +13,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
   uint32_t
     memcached_generate_hash_value (const char *key,
                                    size_t key_length,
-                                   memcached_hash hash_algorithm);
+                                   memcached_hash_t hash_algorithm);
 
   uint32_t 
     memcached_generate_hash (memcached_st *ptr,
@@ -23,7 +23,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
 =head1 DESCRIPTION
 
 memcached_generate_hash_value() allows you to hash a key using one of
-the hash fuctions defined in the library. This method is provided for
+the hash functions defined in the library. This method is provided for
 the convenience of higher-level language bindings and is not necessary
 for normal memcache operations.
 
@@ -34,6 +34,9 @@ memcached_generate_hash() takes a memcached_st struture and produces
 the hash value that would have been generated based on the defaults
 of the memcached_st structure.
 
+As of version 0.36 all hash methods have been placed into the library
+libhashkit(3) which is linked with libmemcached(3).
+
 =head1 RETURN
 
 A 32-bit integer which is the result of hashing the given key.
@@ -43,7 +46,7 @@ returned.
 =head1 HOME
 
 To find out more information please check: 
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
@@ -51,7 +54,7 @@ Brian Aker, E<lt>brian@tangent.orgE<gt>
 
 =head1 SEE ALSO
 
-memcached(1) libmemcached(3) memcached_behavior_set(3)
+memcached(1) libmemcached(3) memcached_behavior_set(3) libhashkit(3)
 
 =cut
 
index db2c9b5ae9d8295b665bf1c0fd18758366d42b9a..ced98f1c0463639cb8b38d934f97e513846cc2ab 100644 (file)
@@ -12,68 +12,70 @@ C Client Library for memcached (libmemcached, -lmemcached)
   #include <memcached.h>
 
   memcached_result_st *
-  memcached_fetch_result(memcached_st *ptr, 
-                      memcached_result_st *result,
-                      memcached_return *error);
-
-  char *memcached_get (memcached_st *ptr,
-                       const char *key, size_t key_length,
-                       size_t *value_length, 
-                       uint32_t *flags,
-                       memcached_return *error);
-
-  memcached_return
-  memcached_mget (memcached_st *ptr, 
-                  const char * const *keys, 
-                  const size_t *key_length, 
+    memcached_fetch_result (memcached_st *ptr,
+                            memcached_result_st *result,
+                            memcached_return_t *error);
+
+  char *
+    memcached_get (memcached_st *ptr,
+                   const char *key, size_t key_length,
+                   size_t *value_length,
+                   uint32_t *flags,
+                   memcached_return_t *error);
+
+  memcached_return_t
+    memcached_mget (memcached_st *ptr,
+                  const char * const *keys,
+                  const size_t *key_length,
                   size_t number_of_keys);
   char *
-  memcached_get_by_key(memcached_st *ptr, 
-                       const char *master_key, size_t master_key_length, 
-                       const char *key, size_t key_length, 
-                       size_t *value_length, 
-                       uint32_t *flags,
-                       memcached_return *error);
-
-  memcached_return 
-  memcached_mget_by_key(memcached_st *ptr, 
-                        const char *master_key, size_t master_key_length,
-                        const char * const *keys, 
-                        const size_t *key_length, 
-                        size_t number_of_keys);
-
-  char *memcached_fetch (memcached_st *ptr,
-                         char *key, size_t *key_length, 
-                         size_t *value_length,
-                         uint32_t *flags, 
-                         memcached_return *error);
-
-  memcached_return 
-  memcached_fetch_execute(memcached_st *ptr, 
-                          memcached_return (*callback[])(memcached_st *ptr, memcached_result_st *result, void *context),
-                          void *context,
-                          unsigned int number_of_callbacks);
-
-
-  memcached_return
-  memcached_mget_execute(memcached_st *ptr,
-                         const char * const *keys,
-                         const size_t *key_length,
-                         size_t number_of_keys,
-                         memcached_execute_function *callback,
-                         void *context,
-                         unsigned int number_of_callbacks);
-
-  memcached_return 
-  memcached_mget_execute_by_key(memcached_st *ptr,
-                                const char *master_key,
-                                size_t master_key_length,
-                                const char * const *keys,
-                                const size_t *key_length,
-                                size_t number_of_keys,
-                                memcached_execute_function *callback,
-                                void *context,
-                                unsigned int number_of_callbacks);
+    memcached_get_by_key (memcached_st *ptr,
+                          const char *master_key, size_t master_key_length,
+                          const char *key, size_t key_length,
+                          size_t *value_length,
+                          uint32_t *flags,
+                          memcached_return_t *error);
+
+  memcached_return_t
+    memcached_mget_by_key (memcached_st *ptr,
+                           const char *master_key, size_t master_key_length,
+                           const char * const *keys,
+                           const size_t *key_length,
+                           size_t number_of_keys);
+
+  char *
+    memcached_fetch (memcached_st *ptr,
+                     char *key, size_t *key_length,
+                     size_t *value_length,
+                     uint32_t *flags,
+                     memcached_return_t *error);
+
+  memcached_return_t
+    memcached_fetch_execute (memcached_st *ptr,
+                             memcached_execute_fn *callback,
+                             void *context,
+                             uint32_t number_of_callbacks);
+
+
+  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,
+                            uint32_t number_of_callbacks);
+
+  memcached_return_t
+    memcached_mget_execute_by_key (memcached_st *ptr,
+                                   const char *master_key,
+                                   size_t master_key_length,
+                                   const char * const *keys,
+                                   const size_t *key_length,
+                                   size_t number_of_keys,
+                                   memcached_execute_fn *callback,
+                                   void *context,
+                                   uint32_t number_of_callbacks);
 
 
 =head1 DESCRIPTION
@@ -83,9 +85,9 @@ must pass in a key and its length to fetch the object. You must supply
 three pointer variables which will give you the state of the returned
 object.  A uint32_t pointer to contain whatever flags you stored with the value,
 a size_t pointer which will be filled with size of of the object, and a
-memcached_return pointer to hold any error. The object will be returned
+memcached_return_t pointer to hold any error. The object will be returned
 upon success and NULL will be returned on failure. Any object returned by
-memcached_get() must be released by the caller application. 
+memcached_get() must be released by the caller application.
 
 memcached_mget() is used to select multiple keys at once. For multiple key
 operations it is always faster to use this function. This function always
@@ -97,28 +99,28 @@ return NULL (aka no more values). If you need to quit in the middle of a
 memcached_get() call, execute a memcached_quit(). After you do this, you can
 issue new queries against the server.
 
-memcached_fetch() is used to fetch an individual value from the server. 
+memcached_fetch() is used to fetch an individual value from the server.
 memcached_mget() must always be called before using this method.  You
 must pass in a key and its length to fetch the object. You must supply
 three pointer variables which will give you the state of the returned
 object.  A uint32_t pointer to contain whatever flags you stored with the value,
 a size_t pointer which will be filled with size of of the object, and a
-memcached_return pointer to hold any error. The object will be returned
+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. 
+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_result() is used to return a memcached_result_st(3) structure 
+memcached_fetch_result() is used to return a memcached_result_st(3) structure
 from a memcached server. The result object is forward compatible with changes
-to the server. For more information please refer to the memcached_result_st(3) 
+to the server. For more information please refer to the memcached_result_st(3)
 help. This function will dynamically allocate a result structure for you
 if you do not pass one to the function.
 
 memcached_fetch_execute() is a callback function for result sets. Instead
 of returning the results to you for processing, it passes each of the
 result sets to the list of functions you provide. It passes to the function
-a memcached_st that can be cloned for use in the called function (it can not 
+a memcached_st that can be cloned for use in the called function (it can not
 be used directly). It also passes a result set which does not need to be freed.
 Finally it passes a "context". This is just a pointer to a memory reference
 you supply the calling function. Currently only one value is being passed
@@ -141,9 +143,9 @@ 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 supported when the C<MEMCACHED_BEHAVIOR_USE_UDP>
-has been set. Executing any of these functions with this behavior on will result in 
+has been set. Executing any of these functions with this behavior on will result in
 C<MEMCACHED_NOT_SUPPORTED> being returned or, for those functions which do not return
-a C<memcached_return>, the error function parameter will be set to 
+a C<memcached_return_t>, the error function parameter will be set to
 C<MEMCACHED_NOT_SUPPORTED>.
 
 =head1 RETURN
@@ -155,7 +157,7 @@ look at the value of error to determine what the actual error was.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 72fb1259484990e3b88993430c9b8917c2acdab9..cafa70c2be1dc374cfee56c2eeddc47465326945 100644 (file)
@@ -10,25 +10,33 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  memcached_return 
-    memcached_set_memory_allocators(memcached_st *ptr,
-                                    memcached_malloc_function mem_malloc,
-                                    memcached_free_function mem_free,
-                                    memcached_realloc_function mem_realloc,
-                                    memcached_calloc_function mem_calloc);
-
-  void memcached_get_memory_allocators(memcached_st *ptr,
-                                       memcached_malloc_function *mem_malloc,
-                                       memcached_free_function *mem_free,
-                                       memcached_realloc_function *mem_realloc,
-                                       memcached_calloc_function *mem_calloc);
-
-  void *(*memcached_malloc_function)(memcached_st *ptr, const size_t size);
-  void *(*memcached_realloc_function)(memcached_st *ptr, void *mem, 
-                                      const size_t size);
-  void  (*memcached_free_function)(memcached_st *ptr, void *mem);
-  void *(*memcached_calloc_function)(memcached_st *ptr, size_t nelem, 
-                                     const size_t elsize);
+  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
+    memcached_get_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 *
+  (*memcached_malloc_fn) (memcached_st *ptr, const size_t size);
+
+  void *
+    (*memcached_realloc_fn) (memcached_st *ptr, void *mem,
+                             const size_t size);
+
+  void
+    (*memcached_free_fn) (memcached_st *ptr, void *mem);
+
+  void *
+  (*memcached_calloc_fn) (memcached_st *ptr, size_t nelem,
+                          const size_t elsize);
 
 
 =head1 DESCRIPTION
@@ -53,17 +61,17 @@ structure.
 
 =head1 RETURN
 
-memcached_set_memory_allocators() return MEMCACHED_SUCCESS upon success, 
+memcached_set_memory_allocators() return MEMCACHED_SUCCESS upon success,
 and MEMCACHED_FAILURE if you don't pass a complete set of function pointers.
 
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
-Trond Norbye, E<lt>trond.norbye@sun.comE<gt>
+Trond Norbye, E<lt>trond.norbye@gmail.comE<gt>
 
 =head1 SEE ALSO
 
index ac85d3b9fdfbd9d30e922aaf082b5fc05f2552b4..b974be67901b00d5fd965a7a88704bad4405b7be 100644 (file)
@@ -10,20 +10,29 @@ C Client Library for memcached (libmemcachedutil, -lmemcachedutil)
 
   #include <libmemcached/memcached_pool.h>
 
-  memcached_pool_st *memcached_pool_create(memcached_st* mmc, int initial, int max);
-  memcached_st* memcached_pool_destroy(memcached_pool_st* pool);
+  memcached_pool_st *
+    memcached_pool_create(memcached_st* mmc, int initial, int max);
 
-  memcached_st* memcached_pool_pop(memcached_pool_st* pool, bool block, memcached_return *rc);
-  memcached_return memcached_pool_push(memcached_pool_st* pool, memcached_st *mmc);
+  memcached_st *
+    memcached_pool_destroy(memcached_pool_st* pool);
+
+  memcached_st *
+    memcached_pool_pop (memcached_pool_st* pool, bool block, memcached_return_t *rc);
+
+  memcached_return_t
+    memcached_pool_push(memcached_pool_st* pool, memcached_st *mmc);
 
   memcached_st *memcached_create (memcached_st *ptr);
 
-  memcached_return memcached_pool_behavior_set(memcached_pool_st *pool, 
-                                               memcached_behavior flag, 
-                                               uint64_t data)
-  memcached_return memcached_pool_behavior_get(memcached_pool_st *pool, 
-                                               memcached_behavior flag,
-                                               uint64_t *value)
+  memcached_return_t
+    memcached_pool_behavior_set(memcached_pool_st *pool,
+                                memcached_behavior_t flag,
+                                uint64_t data)
+
+  memcached_return_t
+    memcached_pool_behavior_get(memcached_pool_st *pool,
+                                memcached_behavior_t flag,
+                                uint64_t *value)
 
 =head1 DESCRIPTION
 
@@ -46,7 +55,7 @@ passed as an argument to memcached_pool_create(), and returns the
 ownership of the pointer to the caller.
 
 memcached_pool_pop() is used to grab a connection structure from the
-connection pool. The block argument specifies if the function should 
+connection pool. The block argument specifies if the function should
 block and wait for a connection structure to be available if we try
 to exceed the maximum size.
 
@@ -67,7 +76,7 @@ memcached_st structure used to create the pool. If connections are in
 use it returns NULL.
 
 memcached_pool_pop() returns a pointer to a memcached_st structure
-from the pool (or NULL if an allocation cannot be satisfied). 
+from the pool (or NULL if an allocation cannot be satisfied).
 
 memcached_pool_push() returns MEMCACHED_SUCCESS upon success.
 
@@ -77,11 +86,11 @@ returns MEMCACHED_SUCCESS upon success.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
-Trond Norbye, E<lt>trond.norbye@sun.comE<gt>
+Trond Norbye, E<lt>trond.norbye@gmail.comE<gt>
 
 =head1 SEE ALSO
 
index 0500b2aba4039ccecc0217a1ff0103e804869bbe..270dd4674e346dc92411471f95d586b78dbd07aa 100644 (file)
@@ -33,7 +33,7 @@ Use memcached_strerror() to translate this value to a printable string.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 246312974b9d46ee38aefa9bd8da31ef9fea5468..ab69f266686b122ede21b9feb2b80ca49a0f0766 100644 (file)
@@ -14,33 +14,35 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  memcached_result_st *memcached_result_create(memcached_st *ptr, 
-                                               memcached_result_st *result);
+  memcached_result_st *
+    memcached_result_create (memcached_st *ptr,
+                             memcached_result_st *result);
 
   void memcached_result_free(memcached_result_st *result);
 
-  char * memcached_result_key_value(memcached_result_st *result);
+  char * memcached_result_key_value (memcached_result_st *result);
 
-  size_t memcached_result_key_length(memcached_result_st *result);
+  size_t memcached_result_key_length (memcached_result_st *result);
 
-  char *memcached_result_value(memcached_result_st *ptr);
+  char *memcached_result_value (memcached_result_st *ptr);
 
-  size_t memcached_result_length(memcached_result_st *ptr);
+  size_t memcached_result_length (memcached_result_st *ptr);
 
-  uint32_t memcached_result_flags(memcached_result_st *result)
+  uint32_t memcached_result_flags (memcached_result_st *result)
 
-  uint64_t memcached_result_cas(memcached_result_st *result);
+  uint64_t memcached_result_cas (memcached_result_st *result);
 
-  memcached_return memcached_result_set_value (memcached_result_st *ptr, 
-                                              char *value, size_t length)
+  memcached_return_t
+    memcached_result_set_value (memcached_result_st *ptr,
+                                char *value, size_t length)
 
-  void memcached_result_set_flags(memcached_result_st *ptr, uint32_t flags)
+  void memcached_result_set_flags (memcached_result_st *ptr, uint32_t flags)
 
-  void memcached_result_set_expiration(memcached_result_st *ptr, time_t)
+  void memcached_result_set_expiration (memcached_result_st *ptr, time_t)
 
 =head1 DESCRIPTION
 
-libmemcached(3) can optionally return a memcached_result_st which acts as a 
+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
 that future memcached servers may implement (the best current example of
@@ -64,13 +66,13 @@ memcached_result_key_length() returns the key length associated with the
 current result object.
 
 memcached_result_value() returns the result value associated with the
-current result object. 
+current result object.
 
 memcached_result_length() returns the result length associated with the
-current result object. 
+current result object.
 
 memcached_result_flags() returns the flags associated with the
-current result object. 
+current result object.
 
 memcached_result_cas() returns the cas associated with the
 current result object. This value will only be available if the server
@@ -82,21 +84,24 @@ the result to this value. This function is used for trigger responses.
 void memcached_result_set_flags() takes a result structure and stores
 a new value for the flags field.
 
-void memcached_result_set_expiration(A) takes a result structure and stores 
+void memcached_result_set_expiration(A) takes a result structure and stores
 a new value for the expiration field (this is only used by read through
 triggers).
 
+You may wish to avoid using memcached_result_create(3) with a
+stack based allocation. The most common issues related to ABI safety involve
+heap allocated structures.
 
 =head1 RETURN
 
 Varies, see particular functions. All structures must have
-memcached_result_free() called on them for cleanup purposes. Failure to 
+memcached_result_free() called on them for cleanup purposes. Failure to
 do this will result in leaked memory.
 
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 08ff77851079778657eb8420e575d04c8e0f975c..32d4e1e98344b014e88fae9564707b3f9dfd9c69 100644 (file)
@@ -17,15 +17,15 @@ C Client Library for memcached (libmemcached, -lmemcached)
     memcached_server_list_append (memcached_server_st *ptr, 
                                   const char *hostname,
                                   unsigned int port, 
-                                  memcached_return *error);
+                                  memcached_return_t *error);
 
   unsigned int memcached_server_list_count (memcached_server_st *ptr);
 
   memcached_server_st *memcached_servers_parse (const char *server_strings);
 
-  const char *memcached_server_error(memcached_server_st *ptr);
+  const char *memcached_server_error (memcached_server_st *ptr);
 
-  void memcached_server_error_reset(memcached_server_st *ptr);
+  void memcached_server_error_reset (memcached_server_st *ptr);
 
 =head1 DESCRIPTION
 
@@ -39,7 +39,7 @@ of memcached_server_st that you passed to it.
 
 memcached_server_list_append() adds a server to the end of a
 memcached_server_st array. On error null will be returned and the
-memcached_return pointer you passed into the function will be set with the
+memcached_return_t pointer you passed into the function will be set with the
 appropriate error. If the value of port is zero, it is set to the default
 port of a memcached server.
 
@@ -61,7 +61,7 @@ Varies, see particular functions.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index a4495382683a7c32e89311e28e6fbe1f7746c320..6ffd8e225aa90aed1c32e8a01bd97d705ac2b2d0 100644 (file)
@@ -1,6 +1,6 @@
 =head1 NAME
 
-memcached_server_count, memcached_server_list, memcached_server_add, memcached_server_push, memcached_server_get_last_disconnect - Manage server list
+memcached_server_count, memcached_server_list, memcached_server_add, memcached_server_push, memcached_server_get_last_disconnect, memcached_server_cursor - Manage server list
 
 =head1 LIBRARY
 
@@ -10,36 +10,43 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  unsigned int memcached_server_count (memcached_st *ptr);
+  uint32_t memcached_server_count (memcached_st *ptr);
 
   memcached_server_st *
     memcached_server_list (memcached_st *ptr);
 
-  memcached_return
+  memcached_return_t
     memcached_server_add (memcached_st *ptr,
                           const char *hostname,
-                          unsigned int port);
+                          in_port_t port);
 
-  memcached_return
+  memcached_return_t
     memcached_server_add_udp (memcached_st *ptr,
                           const char *hostname,
-                          unsigned int port);
+                          in_port_t port);
 
-  memcached_return
+  memcached_return_t
     memcached_server_add_unix_socket (memcached_st *ptr,
                                       const char *socket);
 
-  memcached_return
+  memcached_return_t
     memcached_server_push (memcached_st *ptr,
                            memcached_server_st *list);
 
   memcached_server_st *
-    memcached_server_by_key (memcached_st *ptr,  
-                             const char *key, size_t key_length, 
-                             memcached_return *error);
-  memcached_server_st *                          
+    memcached_server_by_key (memcached_st *ptr,
+                             const char *key, size_t key_length,
+                             memcached_return_t *error);
+
+  memcached_server_st *
     memcached_server_get_last_disconnect (memcached_st *ptr)
-    
+
+  memcached_return_t
+    memcached_server_cursor(memcached_st *ptr,
+                           memcached_server_fn *callback,
+                           void *context,
+                           uint32_t number_of_callbacks);
+
 
 =head1 DESCRIPTION
 
@@ -58,17 +65,17 @@ currently used structure).
 memcached_server_add() pushes a single TCP server into the C<memcached_st>
 structure. This server will be placed at the end. Duplicate servers are
 allowed, so duplication is not checked. Executing this function with the
-C<MEMCACHED_BEHAVIOR_USE_UDP> behavior set will result in a 
+C<MEMCACHED_BEHAVIOR_USE_UDP> behavior set will result in a
 C<MEMCACHED_INVALID_HOST_PROTOCOL>.
 
 memcached_server_add_udp() pushes a single UDP server into the C<memcached_st>
 structure. This server will be placed at the end. Duplicate servers are
 allowed, so duplication is not checked. Executing this function with out
-setting the C<MEMCACHED_BEHAVIOR_USE_UDP> behavior will result in a 
+setting the C<MEMCACHED_BEHAVIOR_USE_UDP> behavior will result in a
 C<MEMCACHED_INVALID_HOST_PROTOCOL>.
 
-memcached_server_add_unix_socket() pushes a single UNIX socket into the 
-C<memcached_st> structure. This UNIX socket will be placed at the end. 
+memcached_server_add_unix_socket() pushes a single UNIX socket into the
+C<memcached_st> structure. This UNIX socket will be placed at the end.
 Duplicate servers are allowed, so duplication is not checked. The length
 of the filename must be one character less then MEMCACHED_MAX_HOST_LENGTH.
 
@@ -84,19 +91,26 @@ from its original structure and must be freed. If NULL is returned you
 should consult *error. The returning structure should be freed with
 memcached_server_free().
 
-memcached_server_get_last_disconnect() returns a pointer to the last server 
-for which there was a connection problem. It does not mean this particular 
-server is currently dead but if the library is reporting a server is, 
+memcached_server_get_last_disconnect() returns a pointer to the last server
+for which there was a connection problem. It does not mean this particular
+server is currently dead but if the library is reporting a server is,
 the returned server is a very good candidate.
 
+memcached_server_cursor() takes a memcached_st and loops through the 
+list of hosts currently in the cursor calling the list of callback 
+functions provided. You can optionally pass in a value via 
+context which will be provided to each callback function. An error
+return from any callback will terminate the loop. memcached_server_cursor()
+is passed the original caller memcached_st in its current state. 
+
 =head1 RETURN
 
 Varies, see particular functions.
 
 =head1 HOME
 
-To find out more information please check: 
-L<http://tangent.org/552/libmemcached.html>
+To find out more information please check:
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index dadb9d2bb53e37afa6e51b5f9c248daa2e578521..13330dcf8932d7cec6da5ec8bb5b0530b71b7932 100644 (file)
@@ -10,41 +10,41 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  memcached_return
+  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
+  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
+  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 
+  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 
+  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 
+  memcached_return_t 
     memcached_cas(memcached_st *ptr, 
                   const char *key, size_t key_length,
                   const char *value, size_t value_length, 
@@ -52,7 +52,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
                   uint32_t flags,
                   uint64_t cas);
 
-  memcached_return 
+  memcached_return_t 
     memcached_set_by_key(memcached_st *ptr, 
                          const char *master_key, size_t master_key_length, 
                          const char *key, size_t key_length, 
@@ -60,7 +60,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
                          time_t expiration,
                          uint32_t flags);
 
-  memcached_return 
+  memcached_return_t 
     memcached_add_by_key(memcached_st *ptr, 
                          const char *master_key, size_t master_key_length,
                          const char *key, size_t key_length,
@@ -68,7 +68,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
                          time_t expiration,
                          uint32_t flags);
 
-  memcached_return 
+  memcached_return_t 
     memcached_replace_by_key(memcached_st *ptr, 
                              const char *master_key, size_t master_key_length,
                              const char *key, size_t key_length,
@@ -76,7 +76,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
                              time_t expiration,
                              uint32_t flags);
 
-  memcached_return 
+  memcached_return_t 
     memcached_prepend_by_key(memcached_st *ptr, 
                              const char *master_key, size_t master_key_length,
                              const char *key, size_t key_length,
@@ -84,7 +84,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
                              time_t expiration,
                              uint32_t flags);
 
-  memcached_return 
+  memcached_return_t 
     memcached_append_by_key(memcached_st *ptr, 
                             const char *master_key, size_t master_key_length,
                             const char *key, size_t key_length,
@@ -92,7 +92,7 @@ C Client Library for memcached (libmemcached, -lmemcached)
                             time_t expiration,
                             uint32_t flags);
 
-  memcached_return 
+  memcached_return_t 
     memcached_cas_by_key(memcached_st *ptr, 
                          const char *master_key, size_t master_key_length,
                          const char *key, size_t key_length,
@@ -163,7 +163,7 @@ will be returned.
 
 =head1 RETURN
 
-All methods return a value of type C<memcached_return>.
+All methods return a value of type C<memcached_return_t>.
 On success the value will be C<MEMCACHED_SUCCESS>.
 Use memcached_strerror() to translate this value to a printable string.
 
@@ -173,7 +173,7 @@ legitmate error in the case of a collision.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 26b0252f743418b8bbe5de581bd6fca5cb3df8a0..fe093d105915a57bcd09fe53bc37aa5e833fdc9e 100644 (file)
@@ -12,21 +12,23 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   memcached_stat_st *memcached_stat (memcached_st *ptr,
                                      char *args,
-                                     memcached_return *error);
+                                     memcached_return_t *error);
 
-  memcached_return memcached_stat_servername (memcached_stat_st *stat,
-                                              char *args, 
-                                              char *hostname,
-                                              unsigned int port);
+  memcached_return_t memcached_stat_servername (memcached_stat_st *stat,
+                                                char *args, 
+                                                const char *hostname,
+                                                unsigned int port);
 
-  char *memcached_stat_get_value (memcached_st *ptr,
-                                  memcached_stat_st *stat, 
-                                  char *key,
-                                  memcached_return *error);
+  char *
+    memcached_stat_get_value (memcached_st *ptr,
+                              memcached_stat_st *stat, 
+                              const char *key,
+                              memcached_return_t *error);
 
-  char ** memcached_stat_get_keys (memcached_st *ptr,
-                                   memcached_stat_st *stat, 
-                                   memcached_return *error);
+  char ** 
+    memcached_stat_get_keys (memcached_st *ptr,
+                             memcached_stat_st *stat, 
+                             memcached_return_t *error);
 
 =head1 DESCRIPTION
 
@@ -68,7 +70,7 @@ memory allocated for it.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 7403685a2f92c463f814eab58b6c2ef02daef0d0..07801d8c99b4ae0477ec0fc2e322b5a2b3692618 100644 (file)
@@ -1,7 +1,7 @@
 =head1 NAME
 
 memcached_strerror - Get error string
+
 =head1 LIBRARY
 
 C Client Library for memcached (libmemcached, -lmemcached)
@@ -10,29 +10,30 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  char *memcached_strerror (memcached_st *ptr,
-                            memcached_return rc);
+  const char *
+    memcached_strerror (memcached_st *ptr,
+                        memcached_return_t rc);
 
 =head1 DESCRIPTION
 
-memcached_strerror() takes a C<memcached_return> value and returns a string
+memcached_strerror() takes a C<memcached_return_t> value and returns a string
 describing the error.
 
 This string must not be modified by the application.
 
-C<memcached_return> values are returned from nearly all libmemcached(3) functions.
+C<memcached_return_t> values are returned from nearly all libmemcached(3) functions.
 
-C<memcached_return> values are of an enum type so that you can set up responses
+C<memcached_return_t> values are of an enum type so that you can set up responses
 with switch/case and know that you are capturing all possible return values.
 
 =head1 RETURN
 
-memcached_strerror() returns a string describing a C<memcached_return> value.
+memcached_strerror() returns a string describing a C<memcached_return_t> value.
 
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 66a25d11afddf942015186be1a50424ce8f774d0..fc339dfce98d705beac8eb9b785fbf103404d994 100644 (file)
@@ -10,8 +10,9 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  void *memcached_get_user_data(memcached_st *ptr);
-  void *memcached_set_user_data(memcached_st *ptr, void *data);
+  void *memcached_get_user_data (memcached_st *ptr);
+
+  void *memcached_set_user_data (memcached_st *ptr, void *data);
 
 =head1 DESCRIPTION
 
@@ -35,11 +36,11 @@ data.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
-Trond Norbye, E<lt>trond.norbye@sun.comE<gt>
+Trond Norbye, E<lt>trond.norbye@gmail.comE<gt>
 
 =head1 SEE ALSO
 
index d7e1698b643132d4fbca70a1924f18d15e91992c..6cdac9144c0bb465eacf3fcc4bd5cd8d3ade424a 100644 (file)
@@ -10,8 +10,9 @@ C Client Library for memcached (libmemcached, -lmemcached)
 
   #include <memcached.h>
 
-  memcached_return memcached_verbosity (memcached_st *ptr,
-                                        unsigned int verbosity);
+  memcached_return_t 
+    memcached_verbosity (memcached_st *ptr,
+                         unsigned int verbosity);
 
 =head1 DESCRIPTION
 
@@ -20,14 +21,14 @@ memcached(1) servers referenced in the C<memcached_st> parameter.
 
 =head1 RETURN
 
-A value of type C<memcached_return> is returned
+A value of type C<memcached_return_t> is returned
 On success that value will be C<MEMCACHED_SUCCESS>.
 Use memcached_strerror() to translate this value to a printable string.
 
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 8307b2f3294cf5411151b82bdac920999fd23a32..26e54e0acf7c354988d21d5b36a4617b0ae0c550 100644 (file)
@@ -11,11 +11,11 @@ C Client Library for memcached (libmemcached, -lmemcached)
   #include <memcached.h>
 
   const char *
-    memcached_lib_version(void) 
+    memcached_lib_version (void) 
 
 
-  memcached_return
-    memcached_version(memcached_st *ptr)
+  memcached_return_t
+    memcached_version (memcached_st *ptr)
 
 
 =head1 DESCRIPTION
@@ -33,7 +33,7 @@ memcached server return code.
 A string with the version of libmemcached driver is returned from
 memcached_lib_version()
 
-A value of type C<memcached_return> is returned from memcached_version()
+A value of type C<memcached_return_t> is returned from memcached_version()
 On success that value will be C<MEMCACHED_SUCCESS>. If called with the
 C<MEMCACHED_BEHAVIOR_USE_UDP> behavior set, the value C<MEMCACHED_NOT_SUPPORTED> 
 will be returned. Use memcached_strerror() to translate this value to 
@@ -42,7 +42,7 @@ a printable string.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 6555988bafed37050af42647090a0940b9cad7cb..bd4d48f8dba488bb1832088455cb15d102717c8a 100644 (file)
@@ -1,6 +1,6 @@
 =head1 NAME
 
-memcapable - Check memcached server capabilites
+memcapable - Check memcached server capabilities
 
 =head1 SYNOPSIS
 
@@ -47,11 +47,11 @@ The current version of memcapable will only verify the binary protocol.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
-Trond Norbye, E<lt>trond.norbye@sun.comE<gt>
+Trond Norbye, E<lt>trond.norbye@gmail.comE<gt>
 
 =head1 SEE ALSO
 
index 04d8a30477fb3d236913a3707b65f2b6d097a760..12947c671c99765e64f75b0c2141bd91ee0ef6cd 100644 (file)
@@ -9,7 +9,7 @@ memcat - Copy a set of keys to stdout
 =head1 DESCRIPTION
 
 B<memcat> outputs to stdout the value a single or mutiple set of keys
-stored in a memcached(1) server.
+stored in a memcached(1) server. If any key is not found an error is returned.
 
 It is similar to the standard UNIX cat(1) utility. 
 
@@ -21,7 +21,7 @@ For a full list of operations run the tool with the B<--help> option.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 319e2f1590f634b00d10725310e4805d08c8e4ff..9be7cddade081bf3c94e64c7a0aaa443c4e51fc7 100644 (file)
@@ -24,7 +24,7 @@ For a full list of operations run the tool with the B<--help> option.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 97fe435d29fef8dd78cf255449ec3ea851b69641..5a26be573fc0d84d3995dd008d2628a256b10c17 100644 (file)
@@ -17,7 +17,7 @@ For a full list of operations run the tool with the B<--help> option.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 9dc2e0cef2a66b40508f47b4ed3069ff74e860c9..40278771a0c1c17b46a1a4ea3b7beeda74c96ce1 100644 (file)
@@ -16,7 +16,7 @@ For a full list of operations run the tool with the B<--help> option.
 =head1 HOME
 
 To find out more infoerroration please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 031e07d007beeefaec3769fc1f2242547785d27b..f26e10c3aa79b509ccda00ded267b836424296be 100644 (file)
@@ -19,7 +19,7 @@ For a full list of operations run the tool with the B<--help> option.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index d7ba38f88587a05ca3a8eed6ea0a3ffe1f941cec..9554f0a07fa4d184cadfa202fee23472e4c89801 100644 (file)
@@ -18,7 +18,7 @@ For a full list of operations run the tool with the B<--help> option.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<https://launchpad.net/libmemcached>
 
 =head1 AUTHOR
 
index 8af03166d0f8cd514deef93c29296228cedd9717..462f67fe944489cd2bf2146bdd3b88900e13e263 100644 (file)
@@ -9,20 +9,994 @@ memslap - Load testing and benchmarking tool for memcached
 =head1 DESCRIPTION
 
 B<memslap> is a load generation and benchmark tool for memcached(1)
-servers. It simulates loads on memcached server clusters.
+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. Furthermore, it also supports data
+verification, expire-time verification, UDP, binary protocol, facebook test,
+replication test, multi-get and reconnection, etc.
+
+Memslap manages network connections like memcached with
+libevent. Each thread of memslap is bound with a CPU core, all
+the threads don't communicate with each other, and there are several socket
+connections in each thread. Each connection keeps key size distribution,
+value size distribution, and command distribution by itself.
 
 You can specify servers via the B<--servers> option or via the
 environment variable C<MEMCACHED_SERVERS>.
 
-For a full list of operations run the tool with the B<--help> option.
+
+=head1 FEATURES
+
+Memslap is developed to for the following purposes:
+
+=over
+
+=item Manages network connections with libevent asynchronously.
+
+=item Set both TCP and UDP up to use non-blocking IO.
+
+=item Improves parallelism: higher performance in multi-threads environments.
+
+=item Improves time efficiency: faster processing speed.
+
+=item Generates key and value more efficiently; key size distribution and value size distribution are configurable.
+
+=item Supports get, multi-get, and set commands; command distribution is configurable.
+
+=item Supports controllable miss rate and overwrite rate.
+
+=item Supports data and expire-time verification.
+
+=item Supports dumping statistic information periodically. 
+
+=item Supports thousands of TCP connections.
+
+=item Supports binary protocol.
+
+=item Supports facebook test (set with TCP and multi-get with UDP) and replication test.
+
+=back
+
+=head1 DETAILS
+
+=head2 Effective implementation of network.
+
+For memslap, both TCP and UDP use non-blocking network IO. All
+the network events are managed by libevent as memcached. The network module
+of memslap is similar to memcached. Libevent can ensure
+memslap can handle network very efficiently.
+
+=head2 Effective implementation of multi-threads and concurrency
+
+Memslap has the similar implementation of multi-threads to
+memcached. Memslap creates one or more self-governed threads;
+each thread is bound with one CPU core if the system supports setting CPU
+core affinity. 
+
+In addition, each thread has a libevent to manage the events of the network;
+each thread has one or more self-governed concurrencies; and each
+concurrency has one or more socket connections. All the concurrencies don’t
+communicate with each other even though they are in the same thread.
+
+Memslap can create thousands of socket connections, and each
+concurrency has tens of socket connections. Each concurrency randomly or
+sequentially selects one socket connection from its socket connection pool
+to run, so memslap can ensure each concurrency handles one
+socket connection at any given time. Users can specify the number of
+concurrency and socket connections of each concurrency according to their
+expected workload. 
+
+=head2 Effective implementation of generating key and value
+
+In order to improve time efficiency and space efficiency, 
+memslap creates a random characters table with 10M characters. All the
+suffixes of keys and values are generated from this random characters table.
+
+Memslap uses the offset in the character table and the length
+of the string to identify a string. It can save much memory.
+Each key contains two parts, a prefix and a suffix. The prefix is an
+uint64_t, 8 bytes. In order to verify the data set before, 
+memslap need to ensure each key is unique, so it uses the prefix to identify
+a key. The prefix cannot include illegal characters, such as ‘\r’, ‘\n’,
+‘\0’ and ‘ ‘. And memslap has an algorithm to ensure that. 
+
+Memslap doesn’t generate all the objects (key-value pairs) at
+the beginning. It only generates enough objects to fill the task window
+(default 10K objects) of each concurrency. Each object has the following
+basic information, key prefix, key suffix offset in the character table, key
+length, value offset in the character table, and value length.
+
+In the work process, each concurrency sequentially or randomly selects an
+object from the window to do set operation or get operation. At the same
+time, each concurrency kicks objects out of its window and adds new object
+into it. 
+
+=head2 Simple but useful task scheduling
+
+Memslap uses libevent to schedule all the concurrencies of
+threads, and each concurrency schedules tasks based on the local task
+window. Memslap assumes that if each concurrency keeps the same
+key distribution, value distribution and commands distribution, from
+outside, memslap keeps all the distribution as a whole. 
+Each task window includes a lot of objects, each object stores its basic
+information, such as key, value, expire time, and so on. At any time, all
+the objects in the window keep the same and fixed key and value
+distribution. If an object is overwritten, the value of the object will be
+updated. Memslap verifies the data or expire-time according to
+the object information stored in the task window.
+
+Libevent selects which concurrency to handle based on a specific network
+event. Then the concurrency selects which command (get or set) to operate
+based on the command distribution. If it needs to kick out an old object and
+add a new object, in order to keep the same key and value distribution, the
+new object must have the same key length and value length. 
+
+If memcached server has two cache layers (memory and SSD), running
+memslap with different window sizes can get different cache
+miss rates. If memslap adds enough objects into the windows at
+the beginning, and the cache of memcached cannot store all the objects
+initialized, then memslap will get some objects from the second
+cache layer. It causes the first cache layer to miss. So the user can
+specify the window size to get the expected miss rate of the first cache
+layer. 
+
+=head2 Useful implementation of multi-servers , UDP, TCP, multi-get and binary protocol
+
+Because each thread is self-governed, memslap can assign
+different threads to handle different memcached servers. This is just one of
+the ways in which memslap supports multiple servers. The only
+limitation is that the number of servers cannot be greater than the number
+of threads. The other way to support multiple servers is for replication
+test. Each concurrency has one socket connection to each memcached server.
+For the implementation, memslap can set some objects to one
+memcached server, and get these objects from the other servers.
+
+By default, Memslap does single get. If the user specifies
+multi-get option, memslap will collect enough get commands and
+pack and send the commands together. 
+
+Memslap supports both the ASCII protocol and binary protocol,
+but it runs on the ASCII protocol by default. 
+Memslap by default runs on the TCP protocol, but it also
+supports UDP. Because UDP is unreliable, dropped packages and out-of-order
+packages may occur. Memslap creates a memory buffer to handle
+these problems. Memslap tries to read all the response data of
+one command from the server and reorders the response data. If some packages
+get lost, the waiting timeout mechanism can ensure half-baked packages will
+be discarded and the next command will be sent.
+
+
+=head1 USAGE
+
+Below are some usage samples:
+
+=over 4
+
+=item memslap -s 127.0.0.1:11211 -S 5s
+
+=item memslap -s 127.0.0.1:11211 -t 2m -v 0.2 -e 0.05 -b
+
+=item memslap -s 127.0.0.1:11211 -F config -t 2m -w 40k -S 20s -o 0.2
+
+=item memslap -s 127.0.0.1:11211 -F config -t 2m -T 4 -c 128 -d 20 -P 40k
+
+=item memslap -s 127.0.0.1:11211 -F config -t 2m -d 50 -a -n 40
+
+=item memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m
+
+=item memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m -p 2
+
+=back
+
+The user must specify one server at least to run memslap. The
+rest of the parameters have default values, as shown below:
+
+Thread number = 1                    Concurrency = 16
+
+Run time = 600 seconds                Configuration file = NULL
+
+Key size = 64                         Value size = 1024
+
+Get/set = 9:1                         Window size = 10k
+
+Execute number = 0                   Single get = true
+
+Multi-get = false                      Number of sockets of each concurrency = 1
+
+Reconnect = false                     Data verification = false
+
+Expire-time verification = false           ASCII protocol = true
+
+Binary protocol = false                 Dumping statistic information
+
+periodically = false
+
+Overwrite proportion = 0%             UDP = false
+
+TCP = true                           Limit throughput = false
+
+Facebook test = false                  Replication test = false
+
+=head2 Key size, value size and command distribution.
+
+All the distributions are read from the configuration file specified by user
+with “—cfg_cmd” option. If the user does not specify a configuration file,
+memslap will run with the default distribution (key size = 64,
+value size = 1024, get/set = 9:1). For information on how to edit the
+configuration file, refer to the “Configuration File” section.
+
+The minimum key size is 16 bytes; the maximum key size is 250 bytes. The
+precision of proportion is 0.001. The proportion of distribution will be
+rounded to 3 decimal places.
+
+The minimum value size is 1 bytes; the maximum value size is 1M bytes. The
+precision of proportion is 0.001. The proportion of distribution will be
+rounded to 3 decimal places.
+Currently, memslap only supports set and get commands. And it
+supports 100% set and 100% get. For 100% get, it will preset some objects to
+the server.
+
+=head2 Multi-thread and concurrency
+
+The high performance of memslap benefits from the special
+schedule of thread and concurrency. It’s important to specify the proper
+number of them. The default number of threads is 1; the default number of
+concurrency is 16. The user can use “—threads” and “--concurrency” to
+specify these variables.
+
+If the system supports setting CPU affinity and the number of threads
+specified by the user is greater than 1, memslap will try to
+bind each thread to a different CPU core. So if you want to get the best
+performance memslap, it is better to specify the number of
+thread equal to the number of CPU cores. The number of threads specified by
+the user can also be less or greater than the number of CPU cores. Because
+of the limitation of implementation, the number of concurrencies could be
+the multiple of the number of threads.
+
+1. For 8 CPU cores system
+
+For example:
+
+--threads=2 --concurrency=128
+
+--threads=8 --concurrency=128
+
+--threads=8 --concurrency=256
+
+--threads=12 --concurrency=144
+
+2. For 16 CPU cores system
+
+For example:
+
+--threads=8 --concurrency=128
+
+--threads=16 --concurrency=256
+
+--threads=16 --concurrency=512
+
+--threads=24 --concurrency=288
+
+The memslap performs very well, when
+used to test the performance of memcached servers.
+Most of the time, the bottleneck is the network or
+the server. If for some reason the user wants to
+limit the performance of memslap, there
+are two ways to do this:
+
+Decrease the number of threads and concurrencies.
+Use the option “--tps” that memslap
+provides to limit the throughput. This option allows
+the user to get the expected throughput. For
+example, assume that the maximum throughput is 50
+kops/s for a specific configuration, you can specify
+the throughput equal to or less than the maximum
+throughput using “--tps” option.
+
+=head2 Window size
+
+Most of the time, the user does not need to specify the window size. The
+default window size is 10k. For Schooner Memcached, the user can specify
+different window sizes to get different cache miss rates based on the test
+case. Memslap supports cache miss rate between 0% and 100%.
+If you use this utility to test the performance of Schooner Memcached, you
+can specify a proper window size to get the expected cache miss rate. The
+formula for calculating window size is as follows:
+
+Assume that the key size is 128 bytes, and the value size is 2048 bytes, and
+concurrency=128.
+
+1. Small cache cache_size=1M, 100% cache miss (all data get from SSD).
+win_size=10k
+
+2. cache_size=4G
+
+(1). cache miss rate 0%
+
+win_size=8k
+
+(2). cache miss rate 5%
+
+win_size=11k
+
+3. cache_size=16G
+
+(1). cache miss rate 0%
+
+win_size=32k
+
+(2). cache miss
+
+rate 5%
+
+win_size=46k
+
+The formula for calculating window size for cache miss rate 0%: 
+
+cache_size / concurrency / (key_size + value_size) * 0.5
+
+The formula for calculating window size for cache miss rate 5%: 
+
+cache_size / concurrency / (key_size + value_size) * 0.7
+
+=head2 Verification
+
+Memslap supports both data verification and expire-time
+verification. The user can use "--verify=" or "-v" to specify the proportion
+of data verification. In theory, it supports 100% data verification. The
+user can use "--exp_verify=" or "-e" to specify the proportion of
+expire-time verification. In theory, it supports 100% expire-time
+verification. Specify the "--verbose" options to get more detailed error
+information.
+
+For example: --exp_verify=0.01 –verify=0.1 , it means that 1% of the objects 
+set with expire-time, 10% of the objects gotten will be verified. If the
+objects are gotten, memslap will verify the expire-time and
+value. 
+
+=head2 multi-servers and multi-clients
+
+Memslap supports multi-servers based on self-governed thread.
+There is a limitation that the number of servers cannot be greater than the
+number of threads. Memslap assigns one thread to handle one
+server at least. The user can use the "--servers=" or "-s" option to specify
+multi-servers. 
+
+For example:
+
+--servers=10.1.1.1:11211,10.1.1.2:11212,10.1.1.3:11213 --threads=6 --concurrency=36
+
+The above command means that there are 6 threads, with each thread having 6
+concurrencies and that threads 0 and 3 handle server 0 (10.1.1.1); threads 1
+and 4 handle server 1 (10.1.1.2); and thread 2 and 5 handle server 2
+(10.1.1.3).  
+
+All the threads and concurrencies in memslap are self-governed.
+
+So is memslap. The user can start up several 
+memslap instances. The user can run memslap on different client
+machines to communicate with the same memcached server at the same. It is
+recommended that the user start different memslap on different
+machines using the same configuration. 
+
+=head2 Run with execute number mode or time mode
+
+The default memslap runs with time mode. The default run time
+is 10 minutes. If it times out, memslap will exit. Do not
+specify both execute number mode and time mode at the same time; just
+specify one instead. 
+
+For example:
+
+--time=30s (It means the test will run 30 seconds.)
+
+--execute_number=100000 (It means that after running 100000 commands, the test will exit.)
+
+=head2 Dump statistic information periodically.
+
+The user can use "--stat_freq=" or "-S" to specify the frequency.
+
+For example:
+
+--stat_freq=20s
+
+Memslap will dump the statistics of the commands (get and set) at the frequency of every 20
+seconds. 
+
+For more information on the format of dumping statistic information, refer to “Format of Output” section.
+
+=head2 Multi-get
+
+The user can use "--division=" or "-d" to specify multi-get keys count.
+Memslap by default does single get with TCP. Memslap also supports data 
+verification and expire-time verification for multi-get. 
+
+Memslap supports multi-get with both TCP and UDP. Because of
+the different implementation of the ASCII protocol and binary protocol,
+there are some differences between the two. For the ASCII protocol,
+memslap sends one “multi-get” to the server once. For the
+binary protocol, memslap sends several single get commands
+together as “multi-get” to the server.
+
+=head2 UDP and TCP
+
+Memslap supports both UDP and TCP. For TCP,
+memslap does not reconnect the memcached server if socket connections are
+lost. If all the socket connections are lost or memcached server crashes,
+memslap will exit. If the user specifies the “--reconnect”
+option when socket connections are lost, it will reconnect them. 
+
+User can use “--udp” to enable the UDP feature, but UDP comes with some
+limitations: 
+
+UDP cannot set data more than 1400 bytes. 
+
+UDP is not supported by the binary protocol because the binary protocol of
+memcached does not support that.
+
+UDP doesn’t support reconnection.
+
+=head2 Facebook test
+
+Set data with TCP and multi-get with UDP. Specify the following options: 
+
+"--facebook --division=50"
+
+If you want to create thousands of TCP connections, specify the
+
+"--conn_sock=" option. 
+
+For example: --facebook --division=50 --conn_sock=200
+
+The above command means that memslap will do facebook test,
+each concurrency has 200 socket TCP connections and one UDP socket.
+
+Memslap sets objects with the TCP socket, and multi-gets 50
+objects once with the UDP socket.
+
+If you specify "--division=50", the key size must be less that 25 bytes
+because the UDP packet size is 1400 bytes.
+
+=head2 Replication test
+
+For replication test, the user must specify at least two memcached servers.
+The user can use “—rep_write=” option to enable feature. 
+
+For example:
+
+--servers=10.1.1.1:11211,10.1.1.2:11212 –rep_write=2
+
+The above command means that there are 2 replication memcached servers,
+memslap will set objects to both server 0 and server 1, get
+objects which are set to server 0 before from server 1, and also get objects
+which are set to server 1 before from server 0. If server 0 crashes,
+memslap will only get objects from server 1. If server 0 comes
+back to life again, memslap will reconnect server 0. If both
+server 0 and server 1 crash, memslap will exit.
+
+=head2  Supports thousands of TCP connections
+
+Start memslap with "--conn_sock=" or "-n" to enable this
+feature. Make sure that your system can support opening thousands of files
+and creating thousands of sockets. However, this feature does not support
+reconnection if sockets disconnect. 
+
+For example: 
+
+--threads=8 --concurrency=128 --conn_sock=128
+
+The above command means that memslap starts up 8 threads, each
+thread has 16 concurrencies, each concurrency has 128 TCP socket
+connections, and the total number of TCP socket connections is 128 * 128 =
+16384.
+
+=head2 Supports binary protocol
+
+Start memslap with "--binary" or "-B" options to enable this
+feature. It supports all the above features except UDP, because the latest
+memcached 1.3.3 does not implement binary UDP protocol.
+
+For example:
+
+--binary
+
+Since memcached 1.3.3 doesn't implement binary UDP protocol,
+memslap does not support UDP. In addition, memcached 1.3.3 does not support
+multi-get. If you specify "--division=50" option, it just sends 50 get
+commands together as “mulit-get” to the server.
+
+=head1 Configuration file
+
+This section describes the format of the configuration file.  By default
+when no configuration file is specified memslap reads the default
+one located at ~/.memslap.cnf.
+
+Below is a sample configuration file:
+
+ ***************************************************************************
+ #comments should start with '#'
+ #key 
+ #start_len end_len proportion
+ #
+ #key length range from start_len to end_len
+ #start_len must be equal to or greater than 16
+ #end_len must be equal to or less than 250
+ #start_len must be equal to or greater than end_len
+ #memslap will generate keys according to the key range
+ #proportion: indicates keys generated from one range accounts for the total
+ generated keys  
+ #
+ #example1: key range 16~100 accounts for 80%
+ #          key range 101~200 accounts for 10%
+ #          key range 201~250 accounts for 10%
+ #          total should be 1 (0.8+0.1+0.1 = 1)
+ #
+ #          16 100 0.8  
+ #          101 200 0.1
+ #          201 249 0.1
+ #
+ #example2: all keys length are 128 bytes
+ #
+ #          128 128 1 
+ key
+ 128 128 1  
+ #value 
+ #start_len end_len proportion
+ #
+ #value length range from start_len to end_len
+ #start_len must be equal to or greater than 1
+ #end_len must be equal to or less than 1M
+ #start_len must be equal to or greater than end_len
+ #memslap will generate values according to the value range
+ #proportion: indicates values generated from one range accounts for the
+ total generated values  
+ #
+ #example1: value range 1~1000 accounts for 80%
+ #          value range 1001~10000 accounts for 10%
+ #          value range 10001~100000 accounts for 10%
+ #          total should be 1 (0.8+0.1+0.1 = 1)
+ #
+ #          1 1000 0.8  
+ #          1001 10000 0.1
+ #          10001 100000 0.1
+ #
+ #example2: all value length are 128 bytes
+ #
+ #          128 128 1 
+ value
+ 2048 2048 1
+ #cmd
+ #cmd_type cmd_proportion
+ #
+ #currently memslap only supports get and set command.
+ #
+ #cmd_type
+ #set     0
+ #get     1
+ #
+ #example: set command accounts for 50%
+ #         get command accounts for 50%
+ #         total should be 1 (0.5+0.5 = 1)
+ #
+ #         cmd
+ #         0    0.5
+ #         1    0.5
+ cmd
+ 0    0.1
+ 1.0 0.9
+
+
+
+=head1 Format of output
+
+At the beginning, memslap displays some configuration information as follows:
+
+=over 4
+
+=item servers : 127.0.0.1:11211
+
+=item threads count: 1
+
+=item concurrency: 16
+
+=item run time: 20s
+
+=item windows size: 10k
+
+=item set proportion: set_prop=0.10
+
+=item get proportion: get_prop=0.90
+
+=back
+
+=head2 Where
+
+=over 4
+
+=item servers : "servers"
+
+The servers used by memslap.
+
+=item threads count
+
+The number of threads memslap runs with.
+
+=item concurrency
+
+The number of concurrencies memslap runs with.
+
+=item run time
+
+How long to run memslap.
+
+=item windows size
+
+The task window size of each concurrency.
+
+=item set proportion
+
+The proportion of set command.
+
+=item get proportion
+
+The proportion of get command.
+
+=back
+
+The output of dynamic statistics is something like this:
+
+ ---------------------------------------------------------------------------------------------------------------------------------
+ Get Statistics
+ Type  Time(s)  Ops   TPS(ops/s)  Net(M/s)  Get_miss  Min(us)  Max(us)
+ Avg(us)  Std_dev    Geo_dist  
+ Period   5   345826  69165     65.3      0         27      2198     203
+ 95.43      177.29
+ Global  20  1257935  62896     71.8      0         26      3791     224
+ 117.79     192.60
+  
+ Set Statistics
+ Type  Time(s)  Ops   TPS(ops/s)  Net(M/s)  Get_miss  Min(us)  Max(us)
+ Avg(us)  Std_dev    Geo_dist  
+ Period   5    38425   7685      7.3       0         42      628     240
+ 88.05      220.21
+ Global   20   139780  6989      8.0       0         37      3790    253
+ 117.93     224.83
+  
+ Total Statistics
+ Type  Time(s)  Ops   TPS(ops/s)  Net(M/s)  Get_miss  Min(us)  Max(us)
+ Avg(us)  Std_dev    Geo_dist 
+ Period   5   384252   76850     72.5      0        27      2198     207
+ 94.72      181.18
+ Global  20  1397720   69886     79.7      0        26      3791     227
+ 117.93     195.60
+ ---------------------------------------------------------------------------------------------------------------------------------
+
+=head2 Where
+
+=over 4
+
+=item Get Statistics
+
+Statistics information of get command
+
+=item Set Statistics
+
+Statistics information of set command
+
+=item Total Statistics
+
+Statistics information of both get and set command
+
+=item Period
+
+Result within a period
+
+=item Global
+
+Accumulated results
+
+=item Ops
+
+Total operations
+
+=item TPS
+
+Throughput, operations/second
+
+=item Net
+
+The rate of network
+
+=item Get_miss
+
+How many objects can’t be gotten
+
+=item Min
+
+The minimum response time
+
+=item Max
+
+The maximum response time
+
+=item Avg: 
+
+The average response time
+
+=item Std_dev
+
+Standard deviation of response time
+
+=item Geo_dist
+
+Geometric distribution based on natural exponential function
+
+=back
+
+At the end, memslap will output something like this:
+
+  ---------------------------------------------------------------------------------------------------------------------------------
+  Get Statistics (1257956 events)
+    Min:        26
+    Max:      3791
+    Avg:       224
+    Geo:    192.60
+    Std:    116.23
+                    Log2 Dist:
+                      4:        0       10    84490   215345
+                      8:   484890   459823    12543      824
+                     12:       31
+
+   Set Statistics (139782 events)
+      Min:        37
+      Max:      3790
+      Avg:       253
+      Geo:    224.84
+      Std:    116.83
+      Log2 Dist: 
+        4:        0        0     4200 16988
+        8:    50784    65574 2064      167
+        12:        5
+   
+    Total Statistics (1397738 events)
+        Min:        26
+        Max:      3791
+        Avg:       227
+        Geo:    195.60
+        Std:    116.60
+        Log2 Dist:
+          4:        0       10    88690   232333
+          8:   535674   525397    14607      991
+          12:       36
+
+  cmd_get: 1257969
+  cmd_set: 139785
+  get_misses: 0
+  verify_misses: 0
+  verify_failed: 0
+  expired_get: 0
+  unexpired_unget: 0
+  written_bytes: 242516030
+  read_bytes: 1003702556
+  object_bytes: 152086080
+  packet_disorder: 0
+  packet_drop: 0
+  udp_timeout: 0
+
+  Run time: 20.0s Ops: 1397754 TPS: 69817 Net_rate: 59.4M/s
+  ---------------------------------------------------------------------------------------------------------------------------------
+
+=head2 Where
+
+=over 4
+
+=item Get Statistics
+
+Get statistics of response time
+
+=item Set Statistics
+
+Set statistics of response time
+
+=item Total Statistics
+
+Both get and set statistics of response time
+
+=item Min
+
+The accumulated and minimum response time
+
+=item Max
+
+The accumulated and maximum response time
+
+=item Avg
+
+The accumulated and average response time
+
+=item Std
+
+Standard deviation of response time
+
+=item Log2 Dist
+
+Geometric distribution based on logarithm 2
+
+=item cmd_get
+
+Total get commands done
+
+=item cmd_set
+
+Total set commands done
+
+=item get_misses
+
+How many objects can’t be gotten from server
+
+=item verify_misses
+
+How many objects need to verify but can’t get them
+
+=item verify_failed
+
+How many objects with insistent value
+
+=item expired_get
+
+How many objects are expired but we get them
+
+=item unexpired_unget
+
+How many objects are unexpired but we can’t get them
+
+=item written_bytes
+
+Total written bytes
+
+=item read_bytes
+
+Total read bytes
+
+=item object_bytes
+
+Total object bytes
+
+=item packet_disorder
+
+How many UDP packages are disorder
+
+=item packet_drop
+
+How many UDP packages are lost
+
+=item udp_timeout
+
+How many times UDP time out happen
+
+=item Run time
+
+Total run time
+
+=item Ops
+
+Total operations 
+
+=item TPS
+
+Throughput, operations/second
+
+=item Net_rate
+
+The average rate of network
+
+=back
+
+=head1 OPTIONS
+
+-s, --servers=
+    List one or more servers to connect. Servers count must be less than
+    threads count. e.g.: --servers=localhost:1234,localhost:11211
+
+-T, --threads=
+    Number of threads to startup, better equal to CPU numbers. Default 8.
+
+-c, --concurrency=
+    Number of concurrency to simulate with load. Default 128.
+
+-n, --conn_sock=
+    Number of TCP socks per concurrency. Default 1.
+
+-x, --execute_number=
+    Number of operations(get and set) to execute for the
+    given test. Default 1000000.
+
+-t, --time=
+    How long the test to run, suffix: s-seconds, m-minutes, h-hours,
+    d-days e.g.: --time=2h.
+
+-F, --cfg_cmd=
+    Load the configure file to get command,key and value distribution list.
+
+-w, --win_size=
+    Task window size of each concurrency, suffix: K, M e.g.: --win_size=10k.
+    Default 10k.
+
+-X, --fixed_size=
+    Fixed length of value.
+
+-v, --verify=
+    The proportion of date verification, e.g.: --verify=0.01
+
+-d, --division=
+    Number of keys to multi-get once. Default 1, means single get.
+
+-S, --stat_freq=
+    Frequency of dumping statistic information. suffix: s-seconds,
+    m-minutes, e.g.: --resp_freq=10s.
+
+-e, --exp_verify=
+    The proportion of objects with expire time, e.g.: --exp_verify=0.01.
+    Default no object with expire time
+
+-o, --overwrite=
+    The proportion of objects need overwrite, e.g.: --overwrite=0.01.
+    Default never overwrite object.
+
+-R, --reconnect 
+    Reconnect support, when connection is closed it will be reconnected.
+
+-U, --udp 
+    UDP support, default memslap uses TCP, TCP port and UDP port of
+    server must be same.
+
+-a, --facebook 
+    Whether it enables facebook test feature, set with TCP and multi-get with UDP.
+
+-B, --binary 
+    Whether it enables binary protocol. Default with ASCII protocol.
+
+-P, --tps=
+    Expected throughput, suffix: K, e.g.: --tps=10k.
+
+-p, --rep_write=
+    The first nth servers can write data, e.g.: --rep_write=2.
+
+-b, --verbose 
+    Whether it outputs detailed information when verification fails.
+
+-h, --help 
+    Display this message and then exit.
+
+-V, --version 
+    Display the version of the application and then exit.
+
+=head1 EXAMPLES
+
+memslap -s 127.0.0.1:11211 -S 5s
+
+memslap -s 127.0.0.1:11211 -t 2m -v 0.2 -e 0.05 -b
+
+memslap -s 127.0.0.1:11211 -F config -t 2m -w 40k -S 20s -o 0.2
+
+memslap -s 127.0.0.1:11211 -F config -t 2m -T 4 -c 128 -d 20 -P 40k
+
+memslap -s 127.0.0.1:11211 -F config -t 2m -d 50 -a -n 40
+
+memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m
+
+memslap -s 127.0.0.1:11211,127.0.0.1:11212 -F config -t 2m -p 2
 
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<http://launchpad.org/libmemcached>
 
-=head1 AUTHOR
+=head1 AUTHORS
 
+Mingqiang Zhuang E<lt>mingqiangzhuang@hengtiansoft.comE<gt> (Schooner Technolgy)
 Brian Aker, E<lt>brian@tangent.orgE<gt>
 
 =head1 SEE ALSO
index 83aa6abed865393b672ee2adc0034a893d440b53..9341e7c8c02aaa71d7575cd260b89b5f419593d1 100644 (file)
@@ -19,7 +19,7 @@ For a full list of operations run the tool with the B<--help> option.
 =head1 HOME
 
 To find out more information please check:
-L<http://tangent.org/552/libmemcached.html>
+L<http://launchpad.org/libmemcached>
 
 =head1 AUTHOR
 
diff --git a/example/Makefile.am b/example/Makefile.am
deleted file mode 100644 (file)
index 9c57082..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-noinst_PROGRAMS = memcached_light
-
-memcached_light_SOURCES= memcached_light.c \
-                         memcached_light.h \
-                         storage.h \
-                         interface_v0.c \
-                         interface_v1.c
-memcached_light_LDADD= $(top_builddir)/libmemcached/libmemcachedprotocol.la $(LIBINNODB)
-memcached_light_DEPENDENCIES= $(top_builddir)/libmemcached/libmemcachedprotocol.la
-
-if BUILD_BYTEORDER
-memcached_light_LDADD+= $(top_builddir)/libmemcached/libbyteorder.la
-memcached_light_DEPENDENCIES+= $(top_builddir)/libmemcached/libbyteorder.la
-endif
-
-if HAVE_LIBINNODB
-memcached_light_SOURCES+= storage_innodb.c
-else
-memcached_light_SOURCES+= storage.c
-endif
diff --git a/example/include.am b/example/include.am
new file mode 100644 (file)
index 0000000..daae642
--- /dev/null
@@ -0,0 +1,24 @@
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+
+noinst_PROGRAMS += example/memcached_light
+
+example_memcached_light_SOURCES= \
+       example/interface_v0.c \
+       example/interface_v1.c \
+       example/memcached_light.c \
+       example/memcached_light.h \
+       example/storage.h
+
+example_memcached_light_LDADD= libmemcached/libmemcachedprotocol.la $(LIBINNODB)
+
+if BUILD_BYTEORDER
+example_memcached_light_LDADD+= libmemcached/libbyteorder.la
+endif
+
+if HAVE_LIBINNODB
+example_memcached_light_SOURCES+= example/storage_innodb.c
+else
+example_memcached_light_SOURCES+= example/storage.c
+endif
index f52abfa2c8dc0b5e3d5b23b9624c65da864bcaba..2fcc0790da7a260910c3ddb0036d5cf0ed4479d8 100644 (file)
@@ -65,7 +65,8 @@ static protocol_binary_response_status append_handler(const void *cookie,
                                                       const void* val,
                                                       uint32_t vallen,
                                                       uint64_t cas,
-                                                      uint64_t *result_cas) {
+                                                      uint64_t *result_cas)
+{
   (void)cookie;
   protocol_binary_response_status rval= PROTOCOL_BINARY_RESPONSE_SUCCESS;
 
index c4495b5946802eca82b3e4ae11ada8573d9bf9ac..4a53217ab831dfd966cae7cc9990c4455770da7d 100644 (file)
@@ -50,11 +50,20 @@ static int num_server_sockets= 0;
 static void* socket_userdata_map[1024];
 static bool verbose= false;
 
+struct options_st {
+  char *pid_file;
+  bool has_port;
+  in_port_t port;
+} global_options;
+
+typedef struct options_st options_st;
+
 /**
  * Create a socket and bind it to a specific port number
  * @param port the port number to bind to
  */
-static int server_socket(const char *port) {
+static int server_socket(const char *port)
+{
   struct addrinfo *ai;
   struct addrinfo hints= { .ai_flags= AI_PASSIVE,
                            .ai_family= AF_UNSPEC,
@@ -226,29 +235,34 @@ static void work(void);
  */
 int main(int argc, char **argv)
 {
-  bool port_specified= false;
   int cmd;
   memcached_binary_protocol_callback_st *interface= &interface_v0_impl;
 
+  memset(&global_options, 0, sizeof(global_options));
+
   /*
    * We need to initialize the handlers manually due to a bug in the
    * warnings generated by struct initialization in gcc (all the way up to 4.4)
    */
   initialize_interface_v0_handler();
 
-  while ((cmd= getopt(argc, argv, "v1p:?")) != EOF)
+  while ((cmd= getopt(argc, argv, "v1pP:?h")) != EOF)
   {
     switch (cmd) {
     case '1':
       interface= &interface_v1_impl;
       break;
+    case 'P':
+      global_options.pid_file= strdup(optarg);
+      break;
     case 'p':
-      port_specified= true;
+      global_options.has_port= true;
       (void)server_socket(optarg);
       break;
     case 'v':
       verbose= true;
       break;
+    case 'h':  /* FALLTHROUGH */
     case '?':  /* FALLTHROUGH */
     default:
       (void)fprintf(stderr, "Usage: %s [-p port] [-v] [-1]\n", argv[0]);
@@ -256,15 +270,33 @@ int main(int argc, char **argv)
     }
   }
 
-  if (!initialize_storage())
+  if (! initialize_storage())
   {
     /* Error message already printed */
     return 1;
   }
 
-  if (!port_specified)
+  if (! global_options.has_port)
     (void)server_socket("9999");
 
+  if (global_options.pid_file)
+  {
+    FILE *pid_file;
+    uint32_t pid;
+
+    pid_file= fopen(global_options.pid_file, "w+");
+
+    if (pid_file == NULL)
+    {
+      perror(strerror(errno));
+      abort();
+    }
+
+    pid= (uint32_t)getpid();
+    fprintf(pid_file, "%u\n", pid);
+    fclose(pid_file);
+  }
+
   if (num_server_sockets == 0)
   {
     fprintf(stderr, "I don't have any server sockets\n");
@@ -311,7 +343,6 @@ static void work(void)
     fds[max_poll].events= POLLIN;
     fds[max_poll].revents= 0;
     fds[max_poll].fd= server_sockets[max_poll];
-    ++max_poll;
   }
 
   while (true)
diff --git a/libhashkit/algorithm.h b/libhashkit/algorithm.h
new file mode 100644 (file)
index 0000000..d3f576c
--- /dev/null
@@ -0,0 +1,48 @@
+/* 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.
+ */
+
+/**
+ * @file
+ * @brief HashKit Header
+ */
+
+#ifndef HASHKIT_ALGORITHM_H
+#define HASHKIT_ALGORITHM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HASHKIT_API
+uint32_t hashkit_default(const char *key, size_t key_length);
+HASHKIT_API
+uint32_t hashkit_fnv1_64(const char *key, size_t key_length);
+HASHKIT_API
+uint32_t hashkit_fnv1a_64(const char *key, size_t key_length);
+HASHKIT_API
+uint32_t hashkit_fnv1_32(const char *key, size_t key_length);
+HASHKIT_API
+uint32_t hashkit_fnv1a_32(const char *key, size_t key_length);
+HASHKIT_API
+uint32_t hashkit_crc32(const char *key, size_t key_length);
+#ifdef HAVE_HSIEH_HASH
+HASHKIT_API
+uint32_t hashkit_hsieh(const char *key, size_t key_length);
+#endif
+HASHKIT_API
+uint32_t hashkit_murmur(const char *key, size_t key_length);
+HASHKIT_API
+uint32_t hashkit_jenkins(const char *key, size_t key_length);
+HASHKIT_API
+uint32_t hashkit_md5(const char *key, size_t key_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HASHKIT_ALGORITHM_H */
diff --git a/libhashkit/behavior.c b/libhashkit/behavior.c
new file mode 100644 (file)
index 0000000..19f08b1
--- /dev/null
@@ -0,0 +1,147 @@
+/* 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 "common.h"
+
+static hashkit_fn *fetch_hash_fn(hashkit_hash_algorithm_t hash_algorithm)
+{
+  switch (hash_algorithm)
+  {
+  case HASHKIT_HASH_DEFAULT:
+    return hashkit_default;
+  case HASHKIT_HASH_MD5:
+    return hashkit_md5;
+  case HASHKIT_HASH_CRC:
+    return hashkit_crc32;
+  case HASHKIT_HASH_FNV1_64:
+    return hashkit_fnv1_64;
+  case HASHKIT_HASH_FNV1A_64:
+    return hashkit_fnv1a_64;
+  case HASHKIT_HASH_FNV1_32:
+    return hashkit_fnv1_32;
+  case HASHKIT_HASH_FNV1A_32:
+    return hashkit_fnv1a_32;
+  case HASHKIT_HASH_HSIEH:
+#ifdef HAVE_HSIEH_HASH
+    return hashkit_hsieh;
+#else
+    return NULL;
+#endif
+  case HASHKIT_HASH_MURMUR:
+    return hashkit_murmur;
+  case HASHKIT_HASH_JENKINS:
+    return hashkit_jenkins;
+  case HASHKIT_HASH_MAX:
+  default:
+#ifdef HAVE_DEBUG
+    fprintf(stderr, "hashkit_hash_t was extended but hashkit_generate_value was not updated\n");
+    fflush(stderr);
+    assert(0);
+#endif
+    break;
+  }
+
+  return NULL;
+}
+
+hashkit_return_t hashkit_behavior_set_distribution(hashkit_st *hashkit, hashkit_distribution_t distribution)
+{
+  hashkit->distribution= distribution;
+
+  return HASHKIT_SUCCESS;
+}
+
+
+hashkit_distribution_t hashkit_behavior_get_distribution(hashkit_st *hashkit)
+{
+  return hashkit->distribution;
+}
+
+
+/**
+  @note For the moment we will not allow the user to set the distribution hash type.
+*/
+hashkit_return_t hashkit_behavior_set_key_hash_algorithm(hashkit_st *hashkit, hashkit_hash_algorithm_t hash_algorithm)
+{
+  hashkit_fn *hash_fn= fetch_hash_fn(hash_algorithm);
+
+  if (hash_fn == NULL)
+    return HASHKIT_FAILURE;
+
+  hashkit->hash_fn= hash_fn;
+  hashkit->for_key= hash_algorithm;
+  hashkit->for_distribution= hash_algorithm;
+  
+  return HASHKIT_SUCCESS;
+}
+
+
+hashkit_hash_algorithm_t hashkit_behavior_get_key_hash_algorithm(hashkit_st *hashkit)
+{
+  return hashkit->for_key;
+}
+
+
+void hashkit_behavior_set_active_fn(hashkit_st *hashkit, hashkit_active_fn *function)
+{
+  hashkit->active_fn= function;
+}
+
+
+hashkit_active_fn * hashkit_behavior_get_active_fn(hashkit_st *hashkit)
+{
+  return hashkit->active_fn;
+}
+
+
+void hashkit_behavior_set_continuum_hash_fn(hashkit_st *hashkit, hashkit_fn *function)
+{
+  hashkit->continuum_hash_fn= function;
+}
+
+
+hashkit_fn * hashkit_behavior_get_continuum_hash_fn(hashkit_st *hashkit)
+{
+  return hashkit->continuum_hash_fn;
+}
+
+
+void hashkit_behavior_set_continuum_key_fn(hashkit_st *hashkit, hashkit_key_fn *function)
+{
+  hashkit->continuum_key_fn= function;
+}
+
+
+hashkit_key_fn * hashkit_behavior_get_continuum_key_fn(hashkit_st *hashkit)
+{
+  return hashkit->continuum_key_fn;
+}
+
+
+void hashkit_behavior_set_sort_fn(hashkit_st *hashkit, hashkit_sort_fn *function)
+{
+  hashkit->sort_fn= function;
+}
+
+
+hashkit_sort_fn * hashkit_behavior_get_sort_fn(hashkit_st *hashkit)
+{
+  return hashkit->sort_fn;
+}
+
+
+void hashkit_behavior_set_weight_fn(hashkit_st *hashkit, hashkit_weight_fn *function)
+{
+  hashkit->weight_fn= function;
+}
+
+
+hashkit_weight_fn * hashkit_behavior_get_weight_fn(hashkit_st *hashkit)
+{
+  return hashkit->weight_fn;
+}
diff --git a/libhashkit/behavior.h b/libhashkit/behavior.h
new file mode 100644 (file)
index 0000000..126a7c9
--- /dev/null
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+/**
+ * @file
+ * @brief HashKit Header
+ */
+
+#ifndef HASHKIT_BEHAVIOR_H
+#define HASHKIT_BEHAVIORH
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+HASHKIT_API
+hashkit_return_t hashkit_behavior_set_distribution(hashkit_st *hashkit, hashkit_distribution_t distribution);
+
+HASHKIT_API
+hashkit_distribution_t hashkit_behavior_get_distribution(hashkit_st *hashkit);
+
+HASHKIT_API
+hashkit_return_t hashkit_behavior_set_key_hash_algorithm(hashkit_st *hashkit, hashkit_hash_algorithm_t hash_algorithm);
+
+HASHKIT_API
+hashkit_hash_algorithm_t hashkit_behavior_get_key_hash_algorithm(hashkit_st *hashkit);
+
+HASHKIT_API
+void hashkit_behavior_set_active_fn(hashkit_st *hash, hashkit_active_fn *function);
+
+HASHKIT_API
+hashkit_active_fn * hashkit_behavior_get_active_fn(hashkit_st *hash);
+
+HASHKIT_API
+void hashkit_behavior_set_continuum_hash_fn(hashkit_st *hash, hashkit_fn *function);
+
+HASHKIT_API
+hashkit_fn * hashkit_behavior_get_continuum_hash_fn(hashkit_st *hash);
+
+HASHKIT_API
+void hashkit_behavior_set_continuum_key_fn(hashkit_st *hash, hashkit_key_fn *function);
+
+HASHKIT_API
+hashkit_key_fn * hashkit_behavior_get_continuum_key_fn(hashkit_st *hash);
+
+HASHKIT_API
+void hashkit_behavior_set_sort_fn(hashkit_st *hash, hashkit_sort_fn *function);
+
+HASHKIT_API
+hashkit_sort_fn * hashkit_behavior_get_sort_fn(hashkit_st *hash);
+
+HASHKIT_API
+void hashkit_behavior_set_weight_fn(hashkit_st *hash, hashkit_weight_fn *function);
+
+HASHKIT_API
+hashkit_weight_fn * hashkit_behavior_get_weight_fn(hashkit_st *hash);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HASHKIT_BEHAVIOR_H */
diff --git a/libhashkit/common.h b/libhashkit/common.h
new file mode 100644 (file)
index 0000000..0a7ac84
--- /dev/null
@@ -0,0 +1,33 @@
+/* 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.
+ */
+
+/**
+ * @file
+ * @brief System Include Files
+ */
+
+#ifndef HASHKIT_COMMON_H
+#define HASHKIT_COMMON_H
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "hashkit.h"
+
+HASHKIT_LOCAL
+void md5_signature(const unsigned char *key, unsigned int length, unsigned char *result);
+
+HASHKIT_LOCAL
+int update_continuum(hashkit_st *hashkit);
+
+#endif /* HASHKIT_COMMON_H */
diff --git a/libhashkit/crc32.c b/libhashkit/crc32.c
new file mode 100644 (file)
index 0000000..023abbb
--- /dev/null
@@ -0,0 +1,85 @@
+/* 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 "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)
+{
+  uint64_t x;
+  uint32_t crc= UINT32_MAX;
+
+  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/default.c b/libhashkit/default.c
new file mode 100644 (file)
index 0000000..bc0d452
--- /dev/null
@@ -0,0 +1,28 @@
+/* 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 "common.h"
+
+uint32_t hashkit_default(const char *key, size_t key_length)
+{
+  const char *ptr= key;
+  uint32_t value= 0;
+
+  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/fnv.c b/libhashkit/fnv.c
new file mode 100644 (file)
index 0000000..fd171ce
--- /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 "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)
+{
+  /* Thanks to pierre@demartines.com for the pointer */
+  uint64_t hash= FNV_64_INIT;
+  size_t x= 0;
+
+  for (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)
+{
+  uint32_t hash= (uint32_t) FNV_64_INIT;
+  size_t x= 0;
+
+  for (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)
+{
+  uint32_t hash= FNV_32_INIT;
+  size_t x= 0;
+
+  for (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)
+{
+  uint32_t hash= FNV_32_INIT;
+  size_t x= 0;
+
+  for (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/hashkit.c b/libhashkit/hashkit.c
new file mode 100644 (file)
index 0000000..5403313
--- /dev/null
@@ -0,0 +1,252 @@
+/* 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 "common.h"
+
+inline static bool _is_allocated(const hashkit_st *hashk)
+{
+  return hashk->options.is_allocated == true;
+}
+
+inline static bool _is_initialized(const hashkit_st *hashk)
+{
+  return hashk->options.is_initialized == true;
+}
+
+/**
+  @note We make no assumptions that "hashk" has been, or not been allocated from heap/stack. We just know we didn't do it.
+*/
+hashkit_st *hashkit_create(hashkit_st *hashk)
+{
+  if (hashk == NULL)
+  {
+    hashk= (hashkit_st *)malloc(sizeof(hashkit_st));
+    if (hashk == NULL)
+    {
+      return NULL;
+    }
+
+    hashk->options.is_allocated= true;
+  }
+  else
+  {
+    hashk->options.is_allocated= false;
+  }
+
+  hashk->options.is_initialized= true;
+
+  hashk->distribution= HASHKIT_DISTRIBUTION_MODULA;
+  hashk->continuum_count= 0;
+  hashk->continuum_points_count= 0;
+  hashk->list_size= 0;
+  hashk->context_size= 0;
+  hashk->continuum= NULL;
+  hashk->hash_fn= NULL;
+  hashk->active_fn= NULL;
+  hashk->continuum_hash_fn= NULL;
+  hashk->continuum_key_fn= NULL;
+  hashk->sort_fn= NULL;
+  hashk->weight_fn= NULL;
+  hashk->list= NULL;
+
+  return hashk;
+}
+
+
+void hashkit_free(hashkit_st *hashk)
+{
+  assert(_is_initialized(hashk) == true);
+
+  if (hashk->continuum != NULL)
+  {
+    free(hashk->continuum);
+  }
+
+  /**
+    We don't know if hashk is pointing to something else,
+    so we go on and set is_initialized.
+  */
+  hashk->options.is_initialized= false;
+
+  if (_is_allocated(hashk))
+  {
+    free(hashk);
+  }
+}
+
+/**
+  @note We do assume source is valid. If source does not exist, we allocate.
+*/
+hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *source)
+{
+  hashkit_st *new_clone;
+
+  if (source == NULL)
+  {
+    return hashkit_create(destination);
+  }
+  else
+  {
+    assert(_is_initialized(source) == true);
+  }
+
+  /* new_clone will be a pointer to destination */ 
+  new_clone= hashkit_create(destination);
+  assert((destination ?  ((_is_allocated(new_clone) == false)) : (_is_allocated(new_clone) == true)));
+
+  // Should only happen on allocation failure.
+  if (new_clone == NULL)
+  {
+    return NULL;
+  }
+
+  // For the moment we will not clone this.
+  new_clone->continuum= NULL;
+
+  new_clone->distribution= source->distribution;
+  new_clone->continuum_count= source->continuum_count;
+  new_clone->continuum_points_count= source->continuum_points_count;
+  new_clone->list_size= source->list_size;
+  new_clone->context_size= source->context_size;
+
+
+  new_clone->hash_fn= source->hash_fn;
+  new_clone->active_fn= source->active_fn;
+  new_clone->continuum_hash_fn= source->continuum_hash_fn;
+  new_clone->continuum_key_fn= source->continuum_key_fn;
+  new_clone->sort_fn= source->sort_fn;
+  new_clone->weight_fn= source->weight_fn;
+  new_clone->list= source->list;
+
+  return new_clone;
+}
+
+
+#if 0
+void hashkit_set_list(hashkit_st *hashkit, void *list, size_t list_size, size_t context_size)
+{
+  hashkit->list= list;
+  hashkit->list_size= list_size;
+  hashkit->context_size= context_size;
+}
+
+
+uint32_t hashkit_value(hashkit_st *hashkit, const char *key, size_t key_length)
+{
+  if (hashkit->hash_fn == NULL)
+    return hashkit_default(key, key_length);
+
+  return hashkit->hash_fn(key, key_length);
+}
+
+
+uint32_t hashkit_index(hashkit_st *hashkit, uint32_t hash_value)
+{
+  if (hashkit->list_size == 1)
+    return 0;
+
+  switch (hashkit->distribution)
+  {
+  case HASHKIT_DISTRIBUTION_MODULA:
+    return hash_value % (uint32_t)hashkit->list_size;
+
+  case HASHKIT_DISTRIBUTION_RANDOM:
+    return (uint32_t)random() % (uint32_t)hashkit->list_size;
+
+  case HASHKIT_DISTRIBUTION_KETAMA:
+  {
+    hashkit_continuum_point_st *begin, *end, *left, *right, *middle;
+    begin= left= hashkit->continuum;
+    end= right= hashkit->continuum + hashkit->continuum_points_count;
+
+    while (left < right)
+    {
+      middle= left + (right - left) / 2;
+      if (middle->value < hash_value)
+        left= middle + 1;
+      else
+        right= middle;
+    }
+    if (right == end)
+      right= begin;
+    return right->index;
+  }
+
+  case HASHKIT_DISTRIBUTION_MAX:
+  default:
+    /* We have added a distribution without extending the logic */
+    return hash_value % (uint32_t)hashkit->list_size;
+  }
+
+  /* NOTREACHED */
+}
+
+
+int hashkit_run_distribution(hashkit_st *hashkit)
+{
+  switch (hashkit->distribution)
+  {
+  case HASHKIT_DISTRIBUTION_MODULA:
+    if (hashkit->sort_fn != NULL && hashkit->list_size > 1)
+      hashkit->sort_fn(hashkit->list, hashkit->list_size);
+    break;
+  case HASHKIT_DISTRIBUTION_RANDOM:
+    break;
+  case HASHKIT_DISTRIBUTION_KETAMA:
+    return update_continuum(hashkit);
+  case HASHKIT_DISTRIBUTION_MAX:
+  default:
+    /* We have added a distribution without extending the logic */
+    break;
+  }
+
+  return 0;
+}
+#endif
+
+
+uint32_t hashkit_generate_value(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm)
+{
+  switch (hash_algorithm)
+  {
+  case HASHKIT_HASH_DEFAULT:
+    return hashkit_default(key, key_length);
+  case HASHKIT_HASH_MD5:
+    return hashkit_md5(key, key_length);
+  case HASHKIT_HASH_CRC:
+    return hashkit_crc32(key, key_length);
+  case HASHKIT_HASH_FNV1_64:
+    return hashkit_fnv1_64(key, key_length);
+  case HASHKIT_HASH_FNV1A_64:
+    return hashkit_fnv1a_64(key, key_length);
+  case HASHKIT_HASH_FNV1_32:
+    return hashkit_fnv1_32(key, key_length);
+  case HASHKIT_HASH_FNV1A_32:
+    return hashkit_fnv1a_32(key, key_length);
+  case HASHKIT_HASH_HSIEH:
+#ifdef HAVE_HSIEH_HASH
+    return hashkit_hsieh(key, key_length);
+#else
+    return 1;
+#endif
+  case HASHKIT_HASH_MURMUR:
+    return hashkit_murmur(key, key_length);
+  case HASHKIT_HASH_JENKINS:
+    return hashkit_jenkins(key, key_length);
+  case HASHKIT_HASH_MAX:
+  default:
+#ifdef HAVE_DEBUG
+    fprintf(stderr, "hashkit_hash_t was extended but hashkit_generate_value was not updated\n");
+    fflush(stderr);
+    assert(0);
+#endif
+    break;
+  }
+
+  return 1;
+}
diff --git a/libhashkit/hashkit.h b/libhashkit/hashkit.h
new file mode 100644 (file)
index 0000000..6dd08f4
--- /dev/null
@@ -0,0 +1,112 @@
+/* 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.
+ */
+
+/**
+ * @file
+ * @brief HashKit Header
+ */
+
+#ifndef HASHKIT_H
+#define HASHKIT_H
+
+#if !defined(__cplusplus)
+# include <stdbool.h>
+#endif
+#include <inttypes.h>
+#include <sys/types.h>
+#include <libhashkit/visibility.h>
+#include <libhashkit/types.h>
+#include <libhashkit/algorithm.h>
+#include <libhashkit/behavior.h>
+#include <libhashkit/strerror.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup hashkit_constants Constants
+ * @ingroup hashkit
+ * @{
+ */
+
+/* Defines. */
+#define HASHKIT_MAX_KEY 251
+#define HASHKIT_POINTS_PER_NODE 100
+#define HASHKIT_POINTS_PER_NODE_WEIGHTED 160
+#define HASHKIT_CONTINUUM_ADDITION 10
+#define HASHKIT_CONTINUUM_KEY_SIZE 86
+
+/** @} */
+
+/**
+ * @ingroup hashkit
+ */
+struct hashkit_st
+{
+  hashkit_options_st options;
+  hashkit_distribution_t distribution;
+  uint32_t continuum_count;
+  uint32_t continuum_points_count;
+  size_t list_size;
+  size_t context_size;
+
+  /**
+    @note There are two places we use hashing, one is for when we have a key
+    and we want to find out what server it should be placed on. The second is
+    for when we are placing a value into the continuum.
+  */
+  hashkit_hash_algorithm_t for_key;
+  hashkit_hash_algorithm_t for_distribution;
+
+  hashkit_continuum_point_st *continuum;
+  hashkit_fn *hash_fn;
+  hashkit_active_fn *active_fn;
+  hashkit_fn *continuum_hash_fn;
+  hashkit_key_fn *continuum_key_fn;
+  hashkit_sort_fn *sort_fn;
+  hashkit_weight_fn *weight_fn;
+  void *list;
+};
+
+/**
+ * @ingroup hashkit
+ */
+struct hashkit_continuum_point_st
+{
+  uint32_t index;
+  uint32_t value;
+};
+
+/**
+ * @addtogroup hashkit Pandora Hash Declarations
+ * @{
+ */
+
+HASHKIT_API
+hashkit_st *hashkit_create(hashkit_st *hash);
+
+HASHKIT_API
+hashkit_st *hashkit_clone(hashkit_st *destination, const hashkit_st *ptr);
+
+HASHKIT_API
+void hashkit_free(hashkit_st *hash);
+
+HASHKIT_API
+uint32_t hashkit_generate_value(const char *key, size_t key_length, hashkit_hash_algorithm_t hash_algorithm);
+
+#define hashkit_is_allocated(__object) ((__object)->options.is_allocated)
+#define hashkit_is_initialized(__object) ((__object)->options.is_initialized)
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HASHKIT_H */
diff --git a/libhashkit/hsieh.c b/libhashkit/hsieh.c
new file mode 100644 (file)
index 0000000..9060bba
--- /dev/null
@@ -0,0 +1,68 @@
+/* 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 "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)
+{
+  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 ^= key[sizeof (uint16_t)] << 18;
+          hash += hash >> 11;
+          break;
+  case 2: hash += get16bits (key);
+          hash ^= hash << 11;
+          hash += hash >> 17;
+          break;
+  case 1: hash += *key;
+          hash ^= hash << 10;
+          hash += hash >> 1;
+  }
+
+  /* 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/include.am b/libhashkit/include.am
new file mode 100644 (file)
index 0000000..dd941f9
--- /dev/null
@@ -0,0 +1,47 @@
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+#
+# 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.
+
+lib_LTLIBRARIES+= libhashkit/libhashkit.la
+
+nobase_include_HEADERS+= \
+                           libhashkit/algorithm.h \
+                           libhashkit/behavior.h \
+                           libhashkit/hashkit.h \
+                           libhashkit/strerror.h \
+                           libhashkit/types.h \
+                           libhashkit/visibility.h
+
+noinst_HEADERS+= \
+                libhashkit/common.h
+
+libhashkit_libhashkit_la_SOURCES= \
+                                 libhashkit/crc32.c \
+                                 libhashkit/behavior.c \
+                                 libhashkit/default.c \
+                                 libhashkit/fnv.c \
+                                 libhashkit/hashkit.c \
+                                 libhashkit/jenkins.c \
+                                 libhashkit/ketama.c \
+                                 libhashkit/md5.c \
+                                 libhashkit/murmur.c \
+                                 libhashkit/strerror.c
+
+if INCLUDE_HSIEH_SRC
+libhashkit_libhashkit_la_SOURCES+= libhashkit/hsieh.c
+endif
+
+libhashkit_libhashkit_la_CFLAGS= \
+                     ${AM_CFLAGS} \
+                     -DBUILDING_HASHKIT
+
+libhashkit_libhashkit_la_LDFLAGS= \
+                                 $(LIBM) \
+                                 -version-info $(HASHKIT_LIBRARY_VERSION)
diff --git a/libhashkit/jenkins.c b/libhashkit/jenkins.c
new file mode 100644 (file)
index 0000000..29d9454
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+*
+* 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 "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)
+{
+  uint32_t a,b,c;                                          /* internal state */
+  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */
+
+  /* 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
new file mode 100644 (file)
index 0000000..83b4755
--- /dev/null
@@ -0,0 +1,162 @@
+/* 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 "common.h"
+#include <math.h>
+
+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;
+}
diff --git a/libhashkit/md5.c b/libhashkit/md5.c
new file mode 100644 (file)
index 0000000..d550c77
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+  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 "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)
+{
+  unsigned char results[16];
+
+  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
new file mode 100644 (file)
index 0000000..cd5e641
--- /dev/null
@@ -0,0 +1,76 @@
+/* 
+  "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 "common.h"
+
+uint32_t hashkit_murmur(const char *key, size_t length)
+{
+  /* 
+    '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;
+
+  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/strerror.c b/libhashkit/strerror.c
new file mode 100644 (file)
index 0000000..270fa21
--- /dev/null
@@ -0,0 +1,26 @@
+/* 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 "common.h"
+
+const char *hashkit_strerror(hashkit_st *ptr __attribute__((unused)), hashkit_return_t rc)
+{
+  switch (rc)
+  {
+  case HASHKIT_SUCCESS:
+    return "SUCCESS";
+  case HASHKIT_FAILURE:
+    return "FAILURE";
+  case HASHKIT_MEMORY_ALLOCATION_FAILURE:
+    return "MEMORY ALLOCATION FAILURE";
+  case HASHKIT_MAXIMUM_RETURN:
+    return "Gibberish returned!";
+  default:
+    return "Gibberish returned!";
+  }
+}
diff --git a/libhashkit/strerror.h b/libhashkit/strerror.h
new file mode 100644 (file)
index 0000000..4cb9197
--- /dev/null
@@ -0,0 +1,22 @@
+/* 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.
+ */
+
+#ifndef HASHKIT_STRERROR_H
+#define HASHKIT_STRERROR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *hashkit_strerror(hashkit_st *ptr __attribute__((unused)), hashkit_return_t rc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HASHKIT_STRERROR_H */
diff --git a/libhashkit/types.h b/libhashkit/types.h
new file mode 100644 (file)
index 0000000..a06be2f
--- /dev/null
@@ -0,0 +1,92 @@
+
+/* 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.
+ */
+
+/**
+ * @file
+ * @brief HashKit Header
+ */
+
+#ifndef HASHKIT_TYPES_H
+#define HASHKIT_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup hashkit_types Types
+ * @ingroup hashkit
+ * @{
+ */
+
+typedef enum {
+  HASHKIT_SUCCESS,
+  HASHKIT_FAILURE,
+  HASHKIT_MEMORY_ALLOCATION_FAILURE,
+  HASHKIT_MAXIMUM_RETURN /* Always add new error code before */
+} hashkit_return_t;
+
+/**
+  @todo hashkit_options_t is for future use, currently we do not define any user options.
+ */
+
+typedef enum
+{
+  HASHKIT_OPTION_MAX
+} hashkit_options_t;
+
+typedef struct
+{
+  /* We use the following for internal book keeping. */
+  bool is_initialized:1;
+  bool is_allocated:1;
+} hashkit_options_st;
+
+typedef enum {
+  HASHKIT_HASH_DEFAULT= 0,
+  HASHKIT_HASH_MD5,
+  HASHKIT_HASH_CRC,
+  HASHKIT_HASH_FNV1_64,
+  HASHKIT_HASH_FNV1A_64,
+  HASHKIT_HASH_FNV1_32,
+  HASHKIT_HASH_FNV1A_32,
+  HASHKIT_HASH_HSIEH,
+  HASHKIT_HASH_MURMUR,
+  HASHKIT_HASH_JENKINS,
+  HASHKIT_HASH_MAX
+} hashkit_hash_algorithm_t;
+
+/**
+ * Hash distributions that are available to use.
+ */
+typedef enum
+{
+  HASHKIT_DISTRIBUTION_MODULA,
+  HASHKIT_DISTRIBUTION_RANDOM,
+  HASHKIT_DISTRIBUTION_KETAMA,
+  HASHKIT_DISTRIBUTION_MAX /* Always add new values before this. */
+} hashkit_distribution_t;
+
+
+typedef struct hashkit_st hashkit_st;
+typedef struct hashkit_continuum_point_st hashkit_continuum_point_st;
+typedef bool (hashkit_active_fn)(void *context);
+typedef uint32_t (hashkit_fn)(const char *key, size_t key_length);
+typedef size_t (hashkit_key_fn)(char *key, size_t key_length, uint32_t point_index, void *context);
+typedef void (hashkit_sort_fn)(void *context, size_t count);
+typedef uint32_t (hashkit_weight_fn)(void *context);
+
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HASHKIT_TYPES_H */
diff --git a/libhashkit/visibility.h b/libhashkit/visibility.h
new file mode 100644 (file)
index 0000000..7691d4b
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Summary: interface for HashKit functions
+ * Description: visibitliy macros for HashKit library
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in this directory for full text.
+ * 
+ * Author: Monty Taylor
+ */
+
+/**
+ * @file
+ * @brief Visibility control macros
+ */
+
+#ifndef HASHKIT_VISIBILITY_H
+#define HASHKIT_VISIBILITY_H
+
+/**
+ *
+ * HASHKIT_API is used for the public API symbols. It either DLL imports or
+ * DLL exports (or does nothing for static build).
+ *
+ * HASHKIT_LOCAL is used for non-api symbols.
+ */
+
+#if defined(BUILDING_HASHKIT)
+# if defined(HAVE_VISIBILITY) && HAVE_VISIBILITY
+#  define HASHKIT_API __attribute__ ((visibility("default")))
+#  define HASHKIT_LOCAL  __attribute__ ((visibility("hidden")))
+# elif defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#  define HASHKIT_API __global
+#  define HASHKIT_LOCAL __hidden
+# elif defined(_MSC_VER)
+#  define HASHKIT_API extern __declspec(dllexport) 
+#  define HASHKIT_LOCAL
+# else
+#  define HASHKIT_API
+#  define HASHKIT_LOCAL
+# endif /* defined(HAVE_VISIBILITY) */
+#else  /* defined(BUILDING_HASHKIT) */
+# if defined(_MSC_VER)
+#  define HASHKIT_API extern __declspec(dllimport) 
+#  define HASHKIT_LOCAL
+# else
+#  define HASHKIT_API
+#  define HASHKIT_LOCAL
+# endif /* defined(_MSC_VER) */
+#endif /* defined(BUILDING_HASHKIT) */
+
+#endif /* HASHKIT_VISIBILITY_H */
diff --git a/libmemcached/Makefile.am b/libmemcached/Makefile.am
deleted file mode 100644 (file)
index ac9aa10..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-EXTRA_DIST = libmemcached.ver \
-             libmemcached_probes.d \
-             memcached/README.txt \
-             memcached_configure.h.in \
-             protocol/libmemcachedprotocol.ver \
-             util/libmemcachedutil.ver
-
-
-EXTRA_HEADERS =
-BUILT_SOURCES=
-
-noinst_HEADERS = libmemcached_probes.h \
-                 memcached_io.h \
-                 memcached_internal.h \
-                 common.h \
-                 memcached/protocol_binary.h \
-                 protocol/common.h \
-                 protocol/ascii_handler.h \
-                 protocol/binary_handler.h
-
-pkginclude_HEADERS= memcached.h \
-                   memcached.hpp \
-                   exception.hpp \
-                    memcached_configure.h \
-                   memcached_constants.h \
-                   memcached_get.h \
-                   memcached_result.h \
-                   memcached_server.h \
-                   memcached_storage.h \
-                   memcached_string.h \
-                   memcached_types.h \
-                   memcached_watchpoint.h \
-                    protocol_handler.h \
-                   visibility.h
-
-nobase_pkginclude_HEADERS=protocol/cache.h \
-                          protocol/callback.h
-
-
-libmemcachedprotocol_la_SOURCES= protocol/ascii_handler.c \
-                                 protocol/binary_handler.c \
-                                 protocol/cache.c \
-                                 protocol/pedantic.c \
-                                 protocol/protocol_handler.c
-
-libmemcachedprotocol_la_LDFLAGS= -version-info $(MEMCACHEDPROTOCOL_LIBRARY_VERSION) $(LD_PROTOCOL_VERSION_SCRIPT)
-
-lib_LTLIBRARIES = libmemcached.la libmemcachedprotocol.la
-noinst_LTLIBRARIES = libmemcachedcallbacks.la
-libmemcachedcallbacks_la_CFLAGS = ${AM_CFLAGS} ${NO_STRICT_ALIASING}
-libmemcachedcallbacks_la_SOURCES = memcached_callback.c
-
-libmemcached_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION}
-libmemcached_la_SOURCES = crc.c \
-                         memcached.c \
-                         memcached_auto.c \
-                         memcached_analyze.c \
-                         memcached_behavior.c \
-                         memcached_connect.c \
-                         memcached_delete.c \
-                         memcached_do.c \
-                         memcached_dump.c \
-                         memcached_fetch.c \
-                         memcached_flush.c \
-                         memcached_get.c \
-                         memcached_hash.c \
-                         memcached_hosts.c \
-                         memcached_io.c \
-                         memcached_purge.c \
-                          memcached_flush_buffers.c \
-                         md5.c \
-                         memcached_key.c \
-                         memcached_quit.c \
-                         memcached_parse.c \
-                         memcached_response.c \
-                         memcached_result.c \
-                         memcached_server.c \
-                         memcached_storage.c \
-                         memcached_string.c \
-                         memcached_stats.c \
-                         memcached_strerror.c \
-                         memcached_verbosity.c \
-                         memcached_version.c \
-                         murmur_hash.c \
-                         jenkins_hash.c \
-                          memcached_allocators.c
-
-
-if INCLUDE_HSIEH_SRC
-libmemcached_la_SOURCES += hsieh_hash.c
-endif
-
-libmemcached_la_DEPENDENCIES= libmemcachedcallbacks.la
-libmemcached_la_LIBADD= $(LIBM) libmemcachedcallbacks.la
-libmemcached_la_LDFLAGS = -version-info $(MEMCACHED_LIBRARY_VERSION) $(LD_VERSION_SCRIPT) $(LIBM)
-
-if BUILD_LIBMEMCACHEDUTIL
-pkginclude_HEADERS+= memcached_util.h memcached_pool.h
-lib_LTLIBRARIES+= libmemcachedutil.la
-endif
-
-libmemcachedutil_la_SOURCES= util/memcached_pool.c
-libmemcachedutil_la_LDFLAGS= -version-info $(MEMCACHEDUTIL_LIBRARY_VERSION) $(LD_UTIL_VERSION_SCRIPT)
-libmemcachedutil_la_LIBADD= libmemcached.la
-libmemcachedutil_la_DEPENDENCIES=libmemcached.la
-
-if BUILD_BYTEORDER
-noinst_LTLIBRARIES += libbyteorder.la
-libbyteorder_la_SOURCES= byteorder.c byteorder.h
-libmemcached_la_LIBADD += libbyteorder.la
-libmemcached_la_DEPENDENCIES+= libbyteorder.la
-libmemcachedprotocol_la_LIBADD=libbyteorder.la
-libmemcachedprotocol_la_DEPENDENCIES=libbyteorder.la
-endif
-
-if HAVE_DTRACE
-BUILT_SOURCES+= dtrace_probes.h
-libmemcached_la_SOURCES += libmemcached_probes.d
-endif
-
-if DTRACE_NEEDS_OBJECTS
-libmemcached_la_DEPENDENCIES += libmemcached_probes.o
-endif
-
-SUFFIXES= .d
-
-dtrace_probes.h: libmemcached_probes.d
-       $(DTRACE) $(DTRACEFLAGS) -h -o dtrace_probes.h -s libmemcached_probes.d
-
-libmemcached_probes.o: libmemcached_probes.d $(libmemcached_la_OBJECTS)
-       $(DTRACE) $(DTRACEFLAGS) -o .libs/libmemcached_probes.o -G -s libmemcached_probes.d `grep '^pic_object' *.lo | cut -f 2 -d\'`
-       $(DTRACE) $(DTRACEFLAGS) -o libmemcached_probes.o -G -s libmemcached_probes.d `grep non_pic_object *.lo | cut -f 2 -d\' `
-
diff --git a/libmemcached/allocators.c b/libmemcached/allocators.c
new file mode 100644 (file)
index 0000000..767371c
--- /dev/null
@@ -0,0 +1,72 @@
+#include "common.h"
+
+void libmemcached_free(memcached_st *ptr, void *mem)
+{
+  (void) ptr;
+  free(mem);
+}
+
+void *libmemcached_malloc(memcached_st *ptr, size_t size)
+{
+  (void) ptr;
+  return malloc(size);
+}
+
+void *libmemcached_realloc(memcached_st *ptr, void *mem, size_t size)
+{
+  (void) ptr;
+  return realloc(mem, size);
+}
+
+void *libmemcached_calloc(memcached_st *ptr, size_t nelem, size_t size)
+{
+  if (ptr->call_malloc != libmemcached_malloc)
+  {
+     void *ret = libmemcached_malloc(ptr, nelem * size);
+     if (ret != NULL) 
+       memset(ret, 0, nelem * size);
+
+     return ret;
+  }
+
+  return calloc(nelem, size);
+}
+
+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)
+{
+  /* All should be set, or none should be set */
+  if (mem_malloc == NULL && mem_free == NULL && mem_realloc == NULL && mem_calloc == NULL) 
+  {
+    ptr->call_malloc= libmemcached_malloc;
+    ptr->call_free= libmemcached_free;
+    ptr->call_realloc= libmemcached_realloc;
+    ptr->call_calloc= libmemcached_calloc;
+  }
+  else if (mem_malloc == NULL || mem_free == NULL || mem_realloc == NULL || mem_calloc == NULL)
+    return MEMCACHED_FAILURE;
+  else
+  {
+    ptr->call_malloc= mem_malloc;
+    ptr->call_free= mem_free;
+    ptr->call_realloc= mem_realloc;
+    ptr->call_calloc= mem_calloc;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+void memcached_get_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)
+{
+   *mem_malloc= ptr->call_malloc;
+   *mem_free= ptr->call_free;
+   *mem_realloc= ptr->call_realloc;
+   *mem_calloc= ptr->call_calloc;
+}
diff --git a/libmemcached/analyze.c b/libmemcached/analyze.c
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/analyze.h b/libmemcached/analyze.h
new file mode 100644 (file)
index 0000000..dbec8b2
--- /dev/null
@@ -0,0 +1,45 @@
+/* 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: Generate a memcached_analysis_st
+ *
+ */
+
+#ifndef __MEMCACHED_ANALYZE_H__
+#define __MEMCACHED_ANALYZE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct memcached_analysis_st {
+  memcached_st *root;
+  uint32_t average_item_size;
+  uint32_t longest_uptime;
+  uint32_t least_free_server;
+  uint32_t most_consumed_server;
+  uint32_t oldest_server;
+  double pool_hit_ratio;
+  uint64_t most_used_bytes;
+  uint64_t least_remaining_bytes;
+};
+
+
+LIBMEMCACHED_API
+memcached_analysis_st *memcached_analyze(memcached_st *memc,
+                                         memcached_stat_st *memc_stat,
+                                         memcached_return_t *error);
+
+LIBMEMCACHED_API
+void memcached_analyze_free(memcached_analysis_st *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_ANALYZE_H__ */
diff --git a/libmemcached/auto.c b/libmemcached/auto.c
new file mode 100644 (file)
index 0000000..017f7f3
--- /dev/null
@@ -0,0 +1,279 @@
+/* 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 "common.h"
+
+static memcached_return_t memcached_auto(memcached_st *ptr,
+                                         const char *verb,
+                                         const char *master_key, size_t master_key_length,
+                                         const char *key, size_t key_length,
+                                         uint64_t offset,
+                                         uint64_t *value)
+{
+  size_t send_length;
+  memcached_return_t rc;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+  uint32_t server_key;
+  memcached_server_instance_st *instance;
+  bool no_reply= ptr->flags.no_reply;
+
+  unlikely (memcached_server_count(ptr) == 0)
+    return MEMCACHED_NO_SERVERS;
+
+  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(ptr, master_key, master_key_length);
+  instance= memcached_server_instance_fetch(ptr, server_key);
+
+  send_length= (size_t)snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                                "%s %s%.*s %" PRIu64 "%s\r\n", verb,
+                                ptr->prefix_key,
+                                (int)key_length, key,
+                                offset, no_reply ? " noreply" : "");
+  unlikely (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
+    return MEMCACHED_WRITE_FAILURE;
+
+  rc= memcached_do(instance, buffer, send_length, 1);
+  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, "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 *master_key, size_t master_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_instance_st *instance;
+  bool no_reply= ptr->flags.no_reply;
+
+  unlikely (memcached_server_count(ptr) == 0)
+    return MEMCACHED_NO_SERVERS;
+
+  server_key= memcached_generate_hash(ptr, master_key, master_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);
+  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 + 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);
+
+  if ((memcached_do(instance, request.bytes,
+                    sizeof(request.bytes), 0)!=MEMCACHED_SUCCESS) ||
+      (memcached_io_write(instance, key, key_length, 1) == -1))
+  {
+    memcached_io_reset(instance);
+    return MEMCACHED_WRITE_FAILURE;
+  }
+
+  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)
+{
+  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)
+{
+  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 *master_key, size_t master_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;
+
+  LIBMEMCACHED_MEMCACHED_INCREMENT_START();
+  if (ptr->flags.binary_protocol)
+  {
+    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
+                         master_key, master_key_length, key, key_length,
+                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
+                         value);
+  }
+  else
+  {
+     rc= memcached_auto(ptr, "incr", master_key, master_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 *master_key, size_t master_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;
+
+  LIBMEMCACHED_MEMCACHED_DECREMENT_START();
+  if (ptr->flags.binary_protocol)
+    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
+                         master_key, master_key_length, key, key_length,
+                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
+                         value);
+  else
+    rc= memcached_auto(ptr, "decr", master_key, master_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)
+{
+  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 *master_key,
+                                                         size_t master_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;
+
+  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
+  if (ptr->flags.binary_protocol)
+    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
+                         master_key, master_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)
+{
+  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 *master_key,
+                                                           size_t master_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;
+
+  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
+  if (ptr->flags.binary_protocol)
+  {
+    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
+                         master_key, master_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.h b/libmemcached/auto.h
new file mode 100644 (file)
index 0000000..c80d0bd
--- /dev/null
@@ -0,0 +1,85 @@
+/* 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.
+ *
+ */
+
+#ifndef __MEMCACHED_AUTO_H__
+#define __MEMCACHED_AUTO_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_increment(memcached_st *ptr,
+                                     const char *key, size_t key_length,
+                                     uint32_t offset,
+                                     uint64_t *value);
+LIBMEMCACHED_API
+memcached_return_t memcached_decrement(memcached_st *ptr,
+                                     const char *key, size_t key_length,
+                                     uint32_t offset,
+                                     uint64_t *value);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_increment_by_key(memcached_st *ptr,
+                                            const char *master_key, size_t master_key_length,
+                                            const char *key, size_t key_length,
+                                            uint64_t offset,
+                                            uint64_t *value);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_decrement_by_key(memcached_st *ptr,
+                                            const char *master_key, size_t master_key_length,
+                                            const char *key, size_t key_length,
+                                            uint64_t offset,
+                                            uint64_t *value);
+
+LIBMEMCACHED_API
+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);
+LIBMEMCACHED_API
+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);
+LIBMEMCACHED_API
+memcached_return_t memcached_increment_with_initial_by_key(memcached_st *ptr,
+                                                         const char *master_key,
+                                                         size_t master_key_length,
+                                                         const char *key,
+                                                         size_t key_length,
+                                                         uint64_t offset,
+                                                         uint64_t initial,
+                                                         time_t expiration,
+                                                         uint64_t *value);
+LIBMEMCACHED_API
+memcached_return_t memcached_decrement_with_initial_by_key(memcached_st *ptr,
+                                                         const char *master_key,
+                                                         size_t master_key_length,
+                                                         const char *key,
+                                                         size_t key_length,
+                                                         uint64_t offset,
+                                                         uint64_t initial,
+                                                         time_t expiration,
+                                                         uint64_t *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_AUTO_H__ */
diff --git a/libmemcached/behavior.c b/libmemcached/behavior.c
new file mode 100644 (file)
index 0000000..01f5bd3
--- /dev/null
@@ -0,0 +1,416 @@
+/* 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 "common.h"
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+
+static bool set_flag(uint64_t data)
+{
+  // Wordy :)
+  return data ? true : false;
+}
+
+static memcached_return_t set_hash(memcached_hash_t *store, memcached_hash_t type)
+{
+#ifndef HAVE_HSIEH_HASH
+  if (type == MEMCACHED_HASH_HSIEH)
+    return MEMCACHED_FAILURE;
+#endif
+  if (type < MEMCACHED_HASH_MAX)
+  {
+    *store= type;
+  }
+  else
+  {
+    return MEMCACHED_FAILURE;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+/*
+  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_SERVER_FAILURE_LIMIT:
+    ptr->server_failure_limit= (uint32_t)data;
+    break;
+  case MEMCACHED_BEHAVIOR_BINARY_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);
+    memcached_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
+    ptr->flags.buffer_requests= set_flag(data);
+    memcached_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);
+    memcached_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_DISTRIBUTION:
+    return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data);
+  case MEMCACHED_BEHAVIOR_KETAMA:
+    {
+      if (data)
+      {
+        (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5);
+        (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5);
+        (void)memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
+      }
+      else
+      {
+        (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_DEFAULT);
+        (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_DEFAULT);
+        (void)memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA);
+      }
+
+      break;
+    }
+  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->flags.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:
+    ptr->flags.use_cache_lookups= set_flag(data);
+    memcached_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_VERIFY_KEY:
+    if (ptr->flags.binary_protocol)
+      return MEMCACHED_FAILURE;
+    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;
+    memcached_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
+    ptr->recv_size= (int32_t)data;
+    memcached_quit(ptr);
+    break;
+  case MEMCACHED_BEHAVIOR_USER_DATA:
+    return MEMCACHED_FAILURE;
+  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:
+      {
+        memcached_server_instance_st *instance;
+        bool action= set_flag(data);
+
+        if (action == false)
+        {
+          ptr->flags.cork= set_flag(false);
+          return MEMCACHED_SUCCESS;
+        }
+
+        instance= memcached_server_instance_fetch(ptr, 0);
+        if (! instance)
+          return MEMCACHED_NO_SERVERS;
+
+
+        /* We just try the first host, and if it is down we return zero */
+        memcached_return_t rc;
+        rc= memcached_connect(instance);
+        if (rc != MEMCACHED_SUCCESS)
+        {
+          return rc;
+        }
+
+        /* Now we test! */
+        memcached_ternary_t enabled;
+        enabled= cork_switch(instance, true);
+
+        switch (enabled)
+        {
+        case MEM_FALSE:
+          return ptr->cached_errno ? MEMCACHED_ERRNO : MEMCACHED_FAILURE ;
+        case MEM_TRUE:
+          {
+            enabled= cork_switch(instance, false);
+
+            if (enabled == false) // Possible bug in OS?
+            {
+              memcached_quit_server(instance, false); // We should reset everything on this error.
+              return MEMCACHED_ERRNO;  // Errno will be true because we will have already set it.
+            }
+            ptr->flags.cork= true;
+            ptr->flags.tcp_nodelay= true;
+          }
+          break;
+        case MEM_NOT:
+        default:
+          return MEMCACHED_NOT_SUPPORTED;
+        }
+      }
+      break;
+  case MEMCACHED_BEHAVIOR_MAX:
+  default:
+    /* Shouldn't get here */
+    WATCHPOINT_ASSERT(0);
+    return MEMCACHED_FAILURE;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+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 ptr->flags.use_cache_lookups;
+  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->flags.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 ptr->hash;
+  case MEMCACHED_BEHAVIOR_KETAMA_HASH:
+    return ptr->distribution_hash;
+  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_SOCKET_SEND_SIZE:
+    {
+      int sock_size= 0;
+      socklen_t sock_length= sizeof(int);
+      memcached_server_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 (getsockopt(instance->fd, SOL_SOCKET,
+                       SO_SNDBUF, &sock_size, &sock_length))
+          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_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 (getsockopt(instance->fd, SOL_SOCKET,
+                       SO_RCVBUF, &sock_size, &sock_length))
+          return 0; /* Zero means error */
+
+      }
+
+      return (uint64_t) sock_size;
+    }
+  case MEMCACHED_BEHAVIOR_USER_DATA:
+    return MEMCACHED_FAILURE;
+  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:
+    return ptr->flags.cork;
+  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)
+  {
+    ptr->distribution= type;
+    run_distribution(ptr);
+  }
+  else
+  {
+    return MEMCACHED_FAILURE;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+
+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)
+{
+  return set_hash(&ptr->hash, type);
+}
+
+memcached_hash_t memcached_behavior_get_key_hash(memcached_st *ptr)
+{
+  return ptr->hash;
+}
+
+memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *ptr, memcached_hash_t type)
+{
+  return set_hash(&ptr->distribution_hash, type);
+}
+
+memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *ptr)
+{
+  return ptr->distribution_hash;
+}
diff --git a/libmemcached/behavior.h b/libmemcached/behavior.h
new file mode 100644 (file)
index 0000000..7a00873
--- /dev/null
@@ -0,0 +1,48 @@
+/* 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.
+ *
+ */
+
+#ifndef __MEMCACHED_BEHAVIOR_H__
+#define __MEMCACHED_BEHAVIOR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_behavior_set(memcached_st *ptr, const memcached_behavior_t flag, uint64_t data);
+
+LIBMEMCACHED_API
+uint64_t memcached_behavior_get(memcached_st *ptr, const memcached_behavior_t flag);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_behavior_set_distribution(memcached_st *ptr, memcached_server_distribution_t type);
+
+LIBMEMCACHED_API
+memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st *ptr);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_behavior_set_key_hash(memcached_st *ptr, memcached_hash_t type);
+
+LIBMEMCACHED_API
+memcached_hash_t memcached_behavior_get_key_hash(memcached_st *ptr);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *ptr, memcached_hash_t type);
+
+LIBMEMCACHED_API
+memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *ptr);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_BEHAVIOR_H__ */
index 5b1cf88bc8d0090a2ac9840783791c9cec861a20..4b6eeb07acbeafaf2ea54107f15e824dcf47ed73 100644 (file)
@@ -1,9 +1,20 @@
+/* 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. */
 static inline uint64_t swap64(uint64_t in)
 {
-#ifndef BYTEORDER_BIG_ENDIAN
+#ifndef WORDS_BIGENDIAN
   /* Little endian, flip the bytes around until someone makes a faster/better
    * way to do this. */
   uint64_t rv= 0;
index 254641f81dfaaf01f56cf3696837e5e4942e1791..17e66a78f59e0d52ee235b9a08dc53af26cd618e 100644 (file)
@@ -1,3 +1,14 @@
+/* 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:
+ *
+ */
+
 #ifndef LIBMEMCACHED_BYTEORDER_H
 #define LIBMEMCACHED_BYTEORDER_H
 
@@ -12,9 +23,9 @@
 
 #ifndef HAVE_HTONLL
 LIBMEMCACHED_LOCAL
-extern uint64_t ntohll(uint64_t);
+uint64_t ntohll(uint64_t);
 LIBMEMCACHED_LOCAL
-extern uint64_t htonll(uint64_t);
+uint64_t htonll(uint64_t);
 #endif
 
 #ifdef linux
diff --git a/libmemcached/callback.c b/libmemcached/callback.c
new file mode 100644 (file)
index 0000000..252b433
--- /dev/null
@@ -0,0 +1,188 @@
+/* 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 "common.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/tcp.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:
+    {
+      char *key= (char *)data;
+
+      if (key)
+      {
+        size_t key_length= strlen(key);
+
+        if (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)
+        {
+          return MEMCACHED_BAD_KEY_PROVIDED;
+        }
+
+        if ((key_length > MEMCACHED_PREFIX_KEY_MAX_SIZE -1)
+            || (strcpy(ptr->prefix_key, key) == NULL))
+        {
+          ptr->prefix_key_length= 0;
+          return MEMCACHED_BAD_KEY_PROVIDED;
+        }
+        else
+        {
+          ptr->prefix_key_length= key_length;
+        }
+      }
+      else
+      {
+        memset(ptr->prefix_key, 0, MEMCACHED_PREFIX_KEY_MAX_SIZE);
+        ptr->prefix_key_length= 0;
+      }
+
+      break;
+    }
+  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[0] == 0)
+      {
+        *error= MEMCACHED_FAILURE;
+        return NULL;
+      }
+      else
+      {
+        *error= MEMCACHED_SUCCESS;
+        return (void *)ptr->prefix_key;
+      }
+    }
+  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.h b/libmemcached/callback.h
new file mode 100644 (file)
index 0000000..de64a19
--- /dev/null
@@ -0,0 +1,32 @@
+/* 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.
+ *
+ */
+
+#ifndef __MEMCACHED_CALLBACK_H__
+#define __MEMCACHED_CALLBACK_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_callback_set(memcached_st *ptr,
+                                          const memcached_callback_t flag,
+                                          void *data);
+LIBMEMCACHED_API
+void *memcached_callback_get(memcached_st *ptr,
+                             const memcached_callback_t flag,
+                             memcached_return_t *error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_CALLBACK_H__ */
index b46d5ba06cd3a5c22fd2ef8bcc62a4f118723c0e..1d77ba1674891c01a94a42af89fbda3fc66b0a0d 100644 (file)
@@ -1,3 +1,14 @@
+/* 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:
+ *
+ */
+
 /*
   Common include file for libmemached
 */
 
 
 #include "libmemcached/memcached.h"
-#include "libmemcached/memcached_watchpoint.h"
+#include "libmemcached/watchpoint.h"
+
+typedef struct memcached_server_st memcached_server_instance_st;
 
 /* These are private not to be installed headers */
-#include "libmemcached/memcached_io.h"
-#include "libmemcached/memcached_internal.h"
+#include "libmemcached/io.h"
+#include "libmemcached/internal.h"
 #include "libmemcached/libmemcached_probes.h"
 #include "libmemcached/memcached/protocol_binary.h"
 #include "libmemcached/byteorder.h"
+#include "libmemcached/response.h"
 
 /* string value */
-struct memcached_continuum_item_st {
+struct memcached_continuum_item_st
+{
   uint32_t index;
   uint32_t value;
 };
 
+/* Yum, Fortran.... can you make the reference? */
+typedef enum {
+  MEM_NOT= -1,
+  MEM_FALSE= false,
+  MEM_TRUE= true,
+} memcached_ternary_t;
+
 
 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
 
@@ -68,34 +90,11 @@ struct memcached_continuum_item_st {
 #define unlikely(x)     if(__builtin_expect((x) != 0, 0))
 #endif
 
-
 #define MEMCACHED_BLOCK_SIZE 1024
 #define MEMCACHED_DEFAULT_COMMAND_SIZE 350
 #define SMALL_STRING_LEN 1024
 #define HUGE_STRING_LEN 8196
 
-
-typedef enum {
-  MEM_NO_BLOCK= (1 << 0),
-  MEM_TCP_NODELAY= (1 << 1),
-  MEM_REUSE_MEMORY= (1 << 2),
-  MEM_USE_MD5= (1 << 3),
-  /* 4 was once Ketama */
-  MEM_USE_CRC= (1 << 5),
-  MEM_USE_CACHE_LOOKUPS= (1 << 6),
-  MEM_SUPPORT_CAS= (1 << 7),
-  MEM_BUFFER_REQUESTS= (1 << 8),
-  MEM_USE_SORT_HOSTS= (1 << 9),
-  MEM_VERIFY_KEY= (1 << 10),
-  /* 11 used for weighted ketama */
-  MEM_KETAMA_WEIGHTED= (1 << 11),
-  MEM_BINARY_PROTOCOL= (1 << 12),
-  MEM_HASH_WITH_PREFIX_KEY= (1 << 13),
-  MEM_NOREPLY= (1 << 14),
-  MEM_USE_UDP= (1 << 15),
-  MEM_AUTO_EJECT_HOSTS= (1 << 16)
-} memcached_flags;
-
 /* Hashing algo */
 
 LIBMEMCACHED_LOCAL
@@ -113,42 +112,38 @@ LIBMEMCACHED_LOCAL
 uint32_t jenkins_hash(const void *key, size_t length, uint32_t initval);
 
 LIBMEMCACHED_LOCAL
-memcached_return memcached_connect(memcached_server_st *ptr);
-LIBMEMCACHED_LOCAL
-memcached_return memcached_response(memcached_server_st *ptr,
-                                    char *buffer, size_t buffer_length,
-                                    memcached_result_st *result);
+memcached_return_t memcached_connect(memcached_server_instance_st *ptr);
 LIBMEMCACHED_LOCAL
-void memcached_quit_server(memcached_server_st *ptr, uint8_t io_death);
+void memcached_quit_server(memcached_server_instance_st *ptr, uint8_t io_death);
 
 #define memcached_server_response_increment(A) (A)->cursor_active++
 #define memcached_server_response_decrement(A) (A)->cursor_active--
 #define memcached_server_response_reset(A) (A)->cursor_active=0
 
 LIBMEMCACHED_LOCAL
-memcached_return memcached_do(memcached_server_st *ptr, const void *commmand,
-                              size_t command_length, uint8_t with_flush);
+memcached_return_t memcached_do(memcached_server_instance_st *ptr, const void *commmand,
+                                size_t command_length, uint8_t with_flush);
 LIBMEMCACHED_LOCAL
-memcached_return value_fetch(memcached_server_st *ptr,
-                             char *buffer,
-                             memcached_result_st *result);
+memcached_return_t value_fetch(memcached_server_instance_st *ptr,
+                               char *buffer,
+                               memcached_result_st *result);
 LIBMEMCACHED_LOCAL
-void server_list_free(memcached_st *ptr, memcached_server_st *servers);
+void server_list_free(memcached_st *ptr, memcached_server_instance_st *servers);
 
 LIBMEMCACHED_LOCAL
-memcached_return memcached_key_test(const char * const *keys, 
-                                    const size_t *key_length,
-                                    size_t number_of_keys);
+memcached_return_t memcached_key_test(const char * const *keys,
+                                      const size_t *key_length,
+                                      size_t number_of_keys);
 
 
 LIBMEMCACHED_LOCAL
 uint32_t generate_hash(memcached_st *ptr, const char *key, size_t key_length);
 
 LIBMEMCACHED_LOCAL
-memcached_return memcached_purge(memcached_server_st *ptr);
+memcached_return_t memcached_purge(memcached_server_instance_st *ptr);
 
-static inline memcached_return memcached_validate_key_length(size_t key_length,
-                                                             bool binary) {
+static inline memcached_return_t memcached_validate_key_length(size_t key_length, bool binary)
+{
   unlikely (key_length == 0)
     return MEMCACHED_BAD_KEY_PROVIDED;
 
@@ -166,4 +161,42 @@ static inline memcached_return memcached_validate_key_length(size_t key_length,
   return MEMCACHED_SUCCESS;
 }
 
+#ifdef TCP_CORK
+  #define CORK TCP_CORK
+#elif defined TCP_NOPUSH
+  #define CORK TCP_NOPUSH
+#endif
+
+/*
+  cork_switch() tries to enable TCP_CORK. IF TCP_CORK is not an option
+  on the system it returns false but sets errno to 0. Otherwise on
+  failure errno is set.
+*/
+static inline memcached_ternary_t cork_switch(memcached_server_st *ptr, bool enable)
+{
+#ifdef CORK
+  if (ptr->type != MEMCACHED_CONNECTION_TCP)
+    return MEM_FALSE;
+
+  int err= setsockopt(ptr->fd, IPPROTO_TCP, CORK,
+                      &enable, (socklen_t)sizeof(int));
+  if (! err)
+  {
+    return MEM_TRUE;
+  }
+  else
+  {
+    ptr->cached_errno= errno;
+    return MEM_FALSE;
+  }
+#else
+  (void)ptr;
+  (void)enable;
+
+  ptr->cached_errno= 0;
+
+  return MEM_NOT;
+#endif
+}
+
 #endif /* LIBMEMCACHED_COMMON_H */
diff --git a/libmemcached/configure.h.in b/libmemcached/configure.h.in
new file mode 100644 (file)
index 0000000..c4301df
--- /dev/null
@@ -0,0 +1,28 @@
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker, Trond Norbye
+ * 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.
+ *
+ */
+
+#ifndef MEMCACHED_CONFIGURE_H
+#define MEMCACHED_CONFIGURE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+@DEPRECATED@
+
+#define LIBMEMCACHED_VERSION_STRING "@VERSION@"
+#define LIBMEMCACHED_VERSION_HEX @PANDORA_HEX_VERSION@
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEMCACHED_CONFIGURE_H */
diff --git a/libmemcached/connect.c b/libmemcached/connect.c
new file mode 100644 (file)
index 0000000..6d08eb7
--- /dev/null
@@ -0,0 +1,372 @@
+#include "common.h"
+#include <netdb.h>
+#include <poll.h>
+#include <sys/time.h>
+
+static memcached_return_t set_hostinfo(memcached_server_st *server)
+{
+  struct addrinfo *ai;
+  struct addrinfo hints;
+  int e;
+  char str_port[NI_MAXSERV];
+
+  snprintf(str_port, NI_MAXSERV, "%u", (uint32_t)server->port);
+
+  memset(&hints, 0, sizeof(hints));
+
+ // hints.ai_family= AF_INET;
+  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;
+  }
+
+  e= getaddrinfo(server->hostname, str_port, &hints, &ai);
+  if (e != 0)
+  {
+    WATCHPOINT_STRING(server->hostname);
+    WATCHPOINT_STRING(gai_strerror(e));
+    return MEMCACHED_HOST_LOOKUP_FAILURE;
+  }
+
+  if (server->address_info)
+  {
+    freeaddrinfo(server->address_info);
+    server->address_info= NULL;
+  }
+  server->address_info= ai;
+
+  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 (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->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 */
+  int flags;
+
+  do
+    flags= fcntl(ptr->fd, F_GETFL, 0);
+  while (flags == -1 && (errno == EINTR || errno == EAGAIN));
+
+  unlikely (flags == -1)
+  {
+    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)
+    {
+      return MEMCACHED_CONNECTION_FAILURE;
+    }
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t unix_socket_connect(memcached_server_st *ptr)
+{
+  struct sockaddr_un servAddr;
+
+  if (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;
+    strcpy(servAddr.sun_path, ptr->hostname); /* 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;
+}
+
+static memcached_return_t network_connect(memcached_server_st *ptr)
+{
+  if (ptr->fd == -1)
+  {
+    struct addrinfo *use;
+
+    WATCHPOINT_ASSERT(ptr->cursor_active == 0);
+
+    if (! ptr->options.sockaddr_inited ||
+        (!(ptr->root->flags.use_cache_lookups)))
+    {
+      memcached_return_t rc;
+
+      rc= set_hostinfo(ptr);
+      if (rc != MEMCACHED_SUCCESS)
+        return rc;
+      ptr->options.sockaddr_inited= true;
+    }
+
+    use= ptr->address_info;
+    /* Create the socket */
+    while (use != NULL)
+    {
+      /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
+      if (ptr->type == MEMCACHED_CONNECTION_UDP && use->ai_family != AF_INET)
+      {
+        use= use->ai_next;
+        continue;
+      }
+
+      if ((ptr->fd= socket(use->ai_family,
+                           use->ai_socktype,
+                           use->ai_protocol)) < 0)
+      {
+        ptr->cached_errno= errno;
+        WATCHPOINT_ERRNO(errno);
+        return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
+      }
+
+      (void)set_socket_options(ptr);
+
+      /* connect to server */
+      while (ptr->fd != -1 &&
+             connect(ptr->fd, use->ai_addr, use->ai_addrlen) < 0)
+      {
+        ptr->cached_errno= errno;
+        if (errno == EINPROGRESS || /* nonblocking mode - first return, */
+            errno == EALREADY) /* nonblocking mode - subsequent returns */
+        {
+          struct pollfd fds[1];
+          fds[0].fd = ptr->fd;
+          fds[0].events = POLLOUT;
+          int error= poll(fds, 1, ptr->root->connect_timeout);
+
+          if (error != 1 || fds[0].revents & POLLERR)
+          {
+            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) ? errno : err;
+            }
+
+            (void)close(ptr->fd);
+            ptr->fd= -1;
+          }
+        }
+        else if (errno == EISCONN) /* we are connected :-) */
+        {
+          break;
+        }
+        else if (errno != EINTR)
+        {
+          (void)close(ptr->fd);
+          ptr->fd= -1;
+          break;
+        }
+      }
+
+      if (ptr->fd != -1)
+      {
+        ptr->server_failure_counter= 0;
+        return MEMCACHED_SUCCESS;
+      }
+      use = use->ai_next;
+    }
+  }
+
+  if (ptr->fd == -1)
+  {
+    /* 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;
+    }
+    ptr->server_failure_counter++;
+    if (ptr->cached_errno == 0)
+      return MEMCACHED_TIMEOUT;
+
+    return MEMCACHED_ERRNO; /* The last error should be from connect() */
+  }
+
+  ptr->server_failure_counter= 0;
+  return MEMCACHED_SUCCESS; /* The last error should be from connect() */
+}
+
+
+memcached_return_t memcached_connect(memcached_server_st *ptr)
+{
+  memcached_return_t rc= MEMCACHED_NO_SERVERS;
+  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->root->server_failure_limit)
+  {
+    struct timeval curr_time;
+
+    gettimeofday(&curr_time, NULL);
+
+    /* if we've had too many consecutive errors on this server, mark it dead. */
+    if (ptr->server_failure_counter >= ptr->root->server_failure_limit)
+    {
+      ptr->next_retry= curr_time.tv_sec + ptr->root->retry_timeout;
+      ptr->server_failure_counter= 0;
+    }
+
+    if (curr_time.tv_sec < ptr->next_retry)
+    {
+      if (memcached_behavior_get(ptr->root, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS))
+      {
+        run_distribution(ptr->root);
+      }
+
+      ptr->root->last_disconnected_server = ptr;
+      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);
+    break;
+  case MEMCACHED_CONNECTION_UNIX_SOCKET:
+    rc= unix_socket_connect(ptr);
+    break;
+  case MEMCACHED_CONNECTION_MAX:
+  default:
+    WATCHPOINT_ASSERT(0);
+  }
+
+  unlikely ( rc != MEMCACHED_SUCCESS) ptr->root->last_disconnected_server = ptr;
+
+  LIBMEMCACHED_MEMCACHED_CONNECT_END();
+
+  return rc;
+}
diff --git a/libmemcached/constants.h b/libmemcached/constants.h
new file mode 100644 (file)
index 0000000..11b2f67
--- /dev/null
@@ -0,0 +1,158 @@
+/* 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: Constants for libmemcached
+ *
+ */
+
+#ifndef __MEMCACHED_CONSTANTS_H__
+#define __MEMCACHED_CONSTANTS_H__
+
+/* Public defines */
+#define MEMCACHED_DEFAULT_PORT 11211
+#define MEMCACHED_MAX_KEY 251 /* We add one to have it null terminated */
+#define MEMCACHED_MAX_BUFFER 8196
+#define MEMCACHED_MAX_HOST_LENGTH 64
+#define MEMCACHED_MAX_HOST_SORT_LENGTH 86 /* Used for Ketama */
+#define MEMCACHED_POINTS_PER_SERVER 100
+#define MEMCACHED_POINTS_PER_SERVER_KETAMA 160
+#define MEMCACHED_CONTINUUM_SIZE MEMCACHED_POINTS_PER_SERVER*100 /* This would then set max hosts to 100 */
+#define MEMCACHED_STRIDE 4
+#define MEMCACHED_DEFAULT_TIMEOUT 1000
+#define MEMCACHED_CONTINUUM_ADDITION 10 /* How many extra slots we should build for in the continuum */
+#define MEMCACHED_PREFIX_KEY_MAX_SIZE 128
+#define MEMCACHED_EXPIRATION_NOT_ADD 0xffffffffU
+#define MEMCACHED_VERSION_STRING_LENGTH 24
+
+
+typedef enum {
+  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_MAXIMUM_RETURN /* Always add new error code before */
+} memcached_return_t;
+
+
+typedef enum {
+  MEMCACHED_DISTRIBUTION_MODULA,
+  MEMCACHED_DISTRIBUTION_CONSISTENT,
+  MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA,
+  MEMCACHED_DISTRIBUTION_RANDOM,
+  MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY,
+  MEMCACHED_DISTRIBUTION_CONSISTENT_MAX
+} memcached_server_distribution_t;
+
+typedef enum {
+  MEMCACHED_BEHAVIOR_NO_BLOCK,
+  MEMCACHED_BEHAVIOR_TCP_NODELAY,
+  MEMCACHED_BEHAVIOR_HASH,
+  MEMCACHED_BEHAVIOR_KETAMA,
+  MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE,
+  MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE,
+  MEMCACHED_BEHAVIOR_CACHE_LOOKUPS,
+  MEMCACHED_BEHAVIOR_SUPPORT_CAS,
+  MEMCACHED_BEHAVIOR_POLL_TIMEOUT,
+  MEMCACHED_BEHAVIOR_DISTRIBUTION,
+  MEMCACHED_BEHAVIOR_BUFFER_REQUESTS,
+  MEMCACHED_BEHAVIOR_USER_DATA,
+  MEMCACHED_BEHAVIOR_SORT_HOSTS,
+  MEMCACHED_BEHAVIOR_VERIFY_KEY,
+  MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT,
+  MEMCACHED_BEHAVIOR_RETRY_TIMEOUT,
+  MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED,
+  MEMCACHED_BEHAVIOR_KETAMA_HASH,
+  MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
+  MEMCACHED_BEHAVIOR_SND_TIMEOUT,
+  MEMCACHED_BEHAVIOR_RCV_TIMEOUT,
+  MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT,
+  MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK,
+  MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK,
+  MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH,
+  MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY,
+  MEMCACHED_BEHAVIOR_NOREPLY,
+  MEMCACHED_BEHAVIOR_USE_UDP,
+  MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS,
+  MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS,
+  MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ,
+  MEMCACHED_BEHAVIOR_CORK,
+  MEMCACHED_BEHAVIOR_MAX
+} memcached_behavior_t;
+
+typedef enum {
+  MEMCACHED_CALLBACK_PREFIX_KEY = 0,
+  MEMCACHED_CALLBACK_USER_DATA = 1,
+  MEMCACHED_CALLBACK_CLEANUP_FUNCTION = 2,
+  MEMCACHED_CALLBACK_CLONE_FUNCTION = 3,
+#ifdef MEMCACHED_ENABLE_DEPRECATED
+  MEMCACHED_CALLBACK_MALLOC_FUNCTION = 4,
+  MEMCACHED_CALLBACK_REALLOC_FUNCTION = 5,
+  MEMCACHED_CALLBACK_FREE_FUNCTION = 6,
+#endif
+  MEMCACHED_CALLBACK_GET_FAILURE = 7,
+  MEMCACHED_CALLBACK_DELETE_TRIGGER = 8,
+  MEMCACHED_CALLBACK_MAX
+} memcached_callback_t;
+
+typedef enum {
+  MEMCACHED_HASH_DEFAULT= 0,
+  MEMCACHED_HASH_MD5,
+  MEMCACHED_HASH_CRC,
+  MEMCACHED_HASH_FNV1_64,
+  MEMCACHED_HASH_FNV1A_64,
+  MEMCACHED_HASH_FNV1_32,
+  MEMCACHED_HASH_FNV1A_32,
+  MEMCACHED_HASH_HSIEH,
+  MEMCACHED_HASH_MURMUR,
+  MEMCACHED_HASH_JENKINS,
+  MEMCACHED_HASH_MAX
+} memcached_hash_t;
+
+typedef enum {
+  MEMCACHED_CONNECTION_UNKNOWN,
+  MEMCACHED_CONNECTION_TCP,
+  MEMCACHED_CONNECTION_UDP,
+  MEMCACHED_CONNECTION_UNIX_SOCKET,
+  MEMCACHED_CONNECTION_MAX
+} memcached_connection_t;
+
+#endif /* __MEMCACHED_CONSTANTS_H__ */
diff --git a/libmemcached/delete.c b/libmemcached/delete.c
new file mode 100644 (file)
index 0000000..32d946b
--- /dev/null
@@ -0,0 +1,211 @@
+#include "common.h"
+#include "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,
+                                               uint8_t flush);
+
+memcached_return_t memcached_delete_by_key(memcached_st *ptr,
+                                           const char *master_key, size_t master_key_length,
+                                           const char *key, size_t key_length,
+                                           time_t expiration)
+{
+  uint8_t to_write;
+  size_t send_length;
+  memcached_return_t rc;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+  uint32_t server_key;
+  memcached_server_instance_st *instance;
+
+  LIBMEMCACHED_MEMCACHED_DELETE_START();
+
+  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(ptr, master_key, master_key_length);
+  instance= memcached_server_instance_fetch(ptr, server_key);
+
+  to_write= (uint8_t)((ptr->flags.buffer_requests) ? 0 : 1);
+
+  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
+  {
+    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= 1;
+                if (no_reply)
+                   memcached_server_response_increment(instance);
+                no_reply= false;
+             }
+          }
+          send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                                         "delete %s%.*s %u%s\r\n",
+                                         ptr->prefix_key,
+                                         (int) key_length, key,
+                                         (uint32_t)expiration,
+                                         no_reply ? " noreply" :"" );
+       }
+    }
+    else
+       send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                                      "delete %s%.*s%s\r\n",
+                                      ptr->prefix_key,
+                                      (int)key_length, key, no_reply ? " noreply" :"");
+
+    if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
+    {
+      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, 1);
+    }
+
+    rc= memcached_do(instance, buffer, 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,
+                                               uint8_t flush)
+{
+  memcached_server_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);
+  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+  request.message.header.request.bodylen= htonl((uint32_t) key_length);
+
+  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, 1);
+  }
+
+  memcached_return_t rc= MEMCACHED_SUCCESS;
+
+  if ((memcached_do(instance, request.bytes,
+                    sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
+      (memcached_io_write(instance, key,
+                          key_length, (char) flush) == -1))
+  {
+    memcached_io_reset(instance);
+    rc= MEMCACHED_WRITE_FAILURE;
+  }
+
+  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_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_do(replica, (const char*)request.bytes,
+                        sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
+          (memcached_io_write(replica, key, key_length, (char) flush) == -1))
+      {
+        memcached_io_reset(replica);
+      }
+      else
+      {
+        memcached_server_response_decrement(replica);
+      }
+    }
+  }
+
+  return rc;
+}
diff --git a/libmemcached/do.c b/libmemcached/do.c
new file mode 100644 (file)
index 0000000..d673f18
--- /dev/null
@@ -0,0 +1,34 @@
+#include "common.h"
+
+memcached_return_t memcached_do(memcached_server_st *ptr, const void *command, 
+                                size_t command_length, uint8_t 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, 1);
+
+  sent_length= memcached_io_write(ptr, command, command_length, (char) 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;
+}
diff --git a/libmemcached/dump.c b/libmemcached/dump.c
new file mode 100644 (file)
index 0000000..0e556e6
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+  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];
+  size_t send_length;
+  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_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++)
+    {
+      send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                                     "stats cachedump %u 0 0\r\n", x);
+
+      rc= memcached_do(instance, buffer, send_length, 1);
+
+      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)
+{
+  /* No support for Binary protocol yet */
+  if (ptr->flags.binary_protocol)
+    return MEMCACHED_FAILURE;
+
+  return ascii_dump(ptr, callback, context, number_of_callbacks);
+}
diff --git a/libmemcached/dump.h b/libmemcached/dump.h
new file mode 100644 (file)
index 0000000..3b3d11d
--- /dev/null
@@ -0,0 +1,27 @@
+/* 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: Simple method for dumping data from Memcached.
+ *
+ */
+
+#ifndef __MEMCACHED_DUMP_H__
+#define __MEMCACHED_DUMP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_API
+memcached_return_t memcached_dump(memcached_st *ptr, memcached_dump_fn *function, void *context, uint32_t number_of_callbacks);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_DUMP_H__ */
diff --git a/libmemcached/fetch.c b/libmemcached/fetch.c
new file mode 100644 (file)
index 0000000..7baac54
--- /dev/null
@@ -0,0 +1,105 @@
+#include "common.h"
+
+char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length, 
+                      size_t *value_length, 
+                      uint32_t *flags,
+                      memcached_return_t *error)
+{
+  memcached_result_st *result_buffer= &ptr->result;
+
+  unlikely (ptr->flags.use_udp)
+  {
+    *error= MEMCACHED_NOT_SUPPORTED;
+    return NULL;
+  }
+
+  result_buffer= memcached_fetch_result(ptr, result_buffer, error);
+
+  if (result_buffer == NULL || *error != MEMCACHED_SUCCESS)
+  {
+    WATCHPOINT_ASSERT(result_buffer == NULL);
+    *value_length= 0;
+    return NULL;
+  }
+
+  *value_length= memcached_string_length(&result_buffer->value);
+
+  if (key)
+  {
+    strncpy(key, result_buffer->key, result_buffer->key_length);
+    *key_length= result_buffer->key_length;
+  }
+
+  if (result_buffer->flags)
+    *flags= result_buffer->flags;
+  else
+    *flags= 0;
+
+  return memcached_string_c_copy(&result_buffer->value);
+}
+
+memcached_result_st *memcached_fetch_result(memcached_st *ptr,
+                                            memcached_result_st *result,
+                                            memcached_return_t *error)
+{
+  memcached_server_st *server;
+
+  unlikely (ptr->flags.use_udp)
+  {
+    *error= MEMCACHED_NOT_SUPPORTED;
+    return NULL;
+  }
+
+  if (result == NULL)
+    if ((result= memcached_result_create(ptr, NULL)) == NULL)
+      return NULL;
+
+  while ((server = memcached_io_get_readable_server(ptr)) != NULL) 
+  {
+    char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+    *error= memcached_response(server, buffer, sizeof(buffer), result);
+
+    if (*error == MEMCACHED_SUCCESS)
+      return result;
+    else if (*error == MEMCACHED_END)
+      memcached_server_response_reset(server);
+    else if (*error != MEMCACHED_NOTFOUND)
+      break;
+  }
+
+  /* We have completed reading data */
+  if (memcached_is_allocated(result))
+  {
+    memcached_result_free(result);
+  }
+  else
+  {
+    memcached_string_reset(&result->value);
+  }
+
+  return NULL;
+}
+
+memcached_return_t memcached_fetch_execute(memcached_st *ptr, 
+                                           memcached_execute_fn *callback,
+                                           void *context,
+                                           uint32_t number_of_callbacks)
+{
+  memcached_result_st *result= &ptr->result;
+  memcached_return_t rc= MEMCACHED_FAILURE;
+  unsigned int x;
+
+  while ((result= memcached_fetch_result(ptr, result, &rc)) != NULL) 
+  {
+    if (rc == MEMCACHED_SUCCESS)
+    {
+      for (x= 0; x < number_of_callbacks; x++)
+      {
+        rc= (*callback[x])(ptr, result, context);
+        if (rc != MEMCACHED_SUCCESS)
+          break;
+      }
+    }
+  }
+  return rc;
+}
diff --git a/libmemcached/flush.c b/libmemcached/flush.c
new file mode 100644 (file)
index 0000000..cb044b0
--- /dev/null
@@ -0,0 +1,103 @@
+#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;
+
+  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)
+{
+  unsigned int x;
+  size_t send_length;
+  memcached_return_t rc;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+  unlikely (memcached_server_count(ptr) == 0)
+    return MEMCACHED_NO_SERVERS;
+
+  for (x= 0; x < memcached_server_count(ptr); x++)
+  {
+    bool no_reply= ptr->flags.no_reply;
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    if (expiration)
+      send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
+                                     "flush_all %llu%s\r\n",
+                                     (unsigned long long)expiration, no_reply ? " noreply" : "");
+    else
+      send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
+                                     "flush_all%s\r\n", no_reply ? " noreply" : "");
+
+    rc= memcached_do(instance, buffer, send_length, 1);
+
+    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)
+{
+  uint32_t x;
+  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 (x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_server_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), 1) != MEMCACHED_SUCCESS) 
+    {
+      memcached_io_reset(instance);
+      return MEMCACHED_WRITE_FAILURE;
+    } 
+  }
+
+  for (x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_server_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_buffers.c b/libmemcached/flush_buffers.c
new file mode 100644 (file)
index 0000000..c037cb7
--- /dev/null
@@ -0,0 +1,26 @@
+#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_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, 1) == -1)
+        ret= MEMCACHED_SOME_ERRORS;
+    }
+  }
+
+  return ret;
+}
diff --git a/libmemcached/get.c b/libmemcached/get.c
new file mode 100644 (file)
index 0000000..97f1c29
--- /dev/null
@@ -0,0 +1,607 @@
+/* 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 *master_key,
+                                                     size_t master_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 *master_key,
+                           size_t master_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, master_key, master_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_master_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 *master_key,
+                                                     size_t master_key_length,
+                                                     const char * const *keys,
+                                                     const size_t *key_length,
+                                                     size_t number_of_keys,
+                                                     bool mget_mode)
+{
+  unsigned int x;
+  memcached_return_t rc= MEMCACHED_NOTFOUND;
+  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_master_key_set= false;
+
+  unlikely (ptr->flags.use_udp)
+    return MEMCACHED_NOT_SUPPORTED;
+
+  LIBMEMCACHED_MEMCACHED_MGET_START();
+
+  if (number_of_keys == 0)
+    return MEMCACHED_NOTFOUND;
+
+  if (memcached_server_count(ptr) == 0)
+    return MEMCACHED_NO_SERVERS;
+
+  if (ptr->flags.verify_key && (memcached_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED))
+    return MEMCACHED_BAD_KEY_PROVIDED;
+
+  if (master_key && master_key_length)
+  {
+    if (ptr->flags.verify_key && (memcached_key_test((const char * const *)&master_key, &master_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+      return MEMCACHED_BAD_KEY_PROVIDED;
+    master_server_key= memcached_generate_hash(ptr, master_key, master_key_length);
+    is_master_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 (x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_server_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, 1);
+
+      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_master_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.
+  */
+  for (x= 0; x < number_of_keys; x++)
+  {
+    memcached_server_instance_st *instance;
+    uint32_t server_key;
+
+    if (is_master_key_set)
+    {
+      server_key= master_server_key;
+    }
+    else
+    {
+      server_key= memcached_generate_hash(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;
+
+      if ((memcached_io_write(instance, get_command, get_command_length, 0)) == -1)
+      {
+        rc= MEMCACHED_SOME_ERRORS;
+        continue;
+      }
+      WATCHPOINT_ASSERT(instance->cursor_active == 0);
+      memcached_server_response_increment(instance);
+      WATCHPOINT_ASSERT(instance->cursor_active == 1);
+    }
+
+    /* Only called when we have a prefix key */
+    if (ptr->prefix_key[0] != 0)
+    {
+      if ((memcached_io_write(instance, ptr->prefix_key, ptr->prefix_key_length, 0)) == -1)
+      {
+        memcached_server_response_reset(instance);
+        rc= MEMCACHED_SOME_ERRORS;
+        continue;
+      }
+    }
+
+    if ((memcached_io_write(instance, keys[x], key_length[x], 0)) == -1)
+    {
+      memcached_server_response_reset(instance);
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+
+    if ((memcached_io_write(instance, " ", 1, 0)) == -1)
+    {
+      memcached_server_response_reset(instance);
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+  }
+
+  /*
+    Should we muddle on if some servers are dead?
+  */
+  for (x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_server_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, 1)) == -1)
+      {
+        rc= MEMCACHED_SOME_ERRORS;
+      }
+    }
+  }
+
+  LIBMEMCACHED_MEMCACHED_MGET_END();
+  return rc;
+}
+
+memcached_return_t memcached_mget_by_key(memcached_st *ptr,
+                                         const char *master_key,
+                                         size_t master_key_length,
+                                         const char * const *keys,
+                                         const size_t *key_length,
+                                         size_t number_of_keys)
+{
+  return memcached_mget_by_key_real(ptr, master_key, master_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 *master_key,
+                                                 size_t master_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, master_key, master_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_master_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;
+  uint32_t x;
+
+  int flush= number_of_keys == 1;
+
+  /*
+    If a server fails we warn about errors and start all over with sending keys
+    to the server.
+  */
+  for (x= 0; x < number_of_keys; x++)
+  {
+    uint32_t server_key;
+    memcached_server_instance_st *instance;
+
+    if (is_master_key_set)
+    {
+      server_key= master_server_key;
+    }
+    else
+    {
+      server_key= memcached_generate_hash(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]);
+    request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
+    request.message.header.request.bodylen= htonl((uint32_t) key_length[x]);
+
+    if ((memcached_io_write(instance, request.bytes,
+                            sizeof(request.bytes), 0) == -1) ||
+        (memcached_io_write(instance, keys[x],
+                            key_length[x], (char) 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 (x= 0; x < memcached_server_count(ptr); x++)
+    {
+      memcached_server_instance_st *instance=
+        memcached_server_instance_fetch(ptr, x);
+
+      if (memcached_server_response_count(instance))
+      {
+        if (memcached_io_write(instance, NULL, 0, 1) == -1)
+        {
+          memcached_server_response_reset(instance);
+          memcached_io_reset(instance);
+          rc= MEMCACHED_SOME_ERRORS;
+        }
+
+        if (memcached_io_write(instance, request.bytes,
+                               sizeof(request.bytes), 1) == -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 x, 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 (x= 0; x < number_of_keys; ++x)
+    {
+      memcached_server_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]),
+          .datatype= PROTOCOL_BINARY_RAW_BYTES,
+          .bodylen= htonl((uint32_t)key_length[x])
+        }
+      };
+
+      /*
+       * 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_
+     */
+      if ((memcached_io_write(instance, request.bytes,
+                              sizeof(request.bytes), 0) == -1) ||
+          (memcached_io_write(instance, keys[x],
+                              key_length[x], 1) == -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_master_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_master_key_set,
+                           keys, key_length, number_of_keys, mget_mode);
+  }
+  else
+  {
+    uint32_t* hash;
+    bool* dead_servers;
+
+    hash= ptr->call_malloc(ptr, sizeof(uint32_t) * number_of_keys);
+    dead_servers= ptr->call_calloc(ptr, memcached_server_count(ptr), sizeof(bool));
+
+    if (hash == NULL || dead_servers == NULL)
+    {
+      ptr->call_free(ptr, hash);
+      ptr->call_free(ptr, dead_servers);
+      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+    }
+
+    if (is_master_key_set)
+      for (unsigned int x= 0; x < number_of_keys; x++)
+        hash[x]= master_server_key;
+    else
+      for (unsigned int x= 0; x < number_of_keys; x++)
+        hash[x]= memcached_generate_hash(ptr, keys[x], key_length[x]);
+
+    rc= replication_binary_mget(ptr, hash, dead_servers, keys,
+                                key_length, number_of_keys);
+
+    ptr->call_free(ptr, hash);
+    ptr->call_free(ptr, dead_servers);
+
+    return MEMCACHED_SUCCESS;
+  }
+
+  return rc;
+}
diff --git a/libmemcached/get.h b/libmemcached/get.h
new file mode 100644 (file)
index 0000000..2e5b2f9
--- /dev/null
@@ -0,0 +1,86 @@
+/* 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
+ *
+ */
+
+#ifndef LIBMEMCACHED_MEMCACHED_GET_H
+#define LIBMEMCACHED_MEMCACHED_GET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Public defines */
+LIBMEMCACHED_API
+char *memcached_get(memcached_st *ptr,
+                    const char *key, size_t key_length,
+                    size_t *value_length,
+                    uint32_t *flags,
+                    memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_mget(memcached_st *ptr,
+                                  const char * const *keys,
+                                  const size_t *key_length,
+                                  size_t number_of_keys);
+
+LIBMEMCACHED_API
+char *memcached_get_by_key(memcached_st *ptr,
+                           const char *master_key, size_t master_key_length,
+                           const char *key, size_t key_length,
+                           size_t *value_length,
+                           uint32_t *flags,
+                           memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_mget_by_key(memcached_st *ptr,
+                                         const char *master_key,
+                                         size_t master_key_length,
+                                         const char * const *keys,
+                                         const size_t *key_length,
+                                         const size_t number_of_keys);
+
+LIBMEMCACHED_API
+char *memcached_fetch(memcached_st *ptr,
+                      char *key,
+                      size_t *key_length,
+                      size_t *value_length,
+                      uint32_t *flags,
+                      memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_result_st *memcached_fetch_result(memcached_st *ptr,
+                                            memcached_result_st *result,
+                                            memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_mget_execute(memcached_st *ptr,
+                                          const char * const *keys,
+                                          const size_t *key_length,
+                                          const size_t number_of_keys,
+                                          memcached_execute_fn *callback,
+                                          void *context,
+                                          const uint32_t number_of_callbacks);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_mget_execute_by_key(memcached_st *ptr,
+                                                 const char *master_key,
+                                                 size_t master_key_length,
+                                                 const char * const *keys,
+                                                 const size_t *key_length,
+                                                 size_t number_of_keys,
+                                                 memcached_execute_fn *callback,
+                                                 void *context,
+                                                 const uint32_t number_of_callbacks);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBMEMCACHED_MEMCACHED_GET_H */
diff --git a/libmemcached/hash.c b/libmemcached/hash.c
new file mode 100644 (file)
index 0000000..6ead8d4
--- /dev/null
@@ -0,0 +1,239 @@
+#include "common.h"
+
+
+/* Defines */
+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;
+
+/* Prototypes */
+static uint32_t internal_generate_hash(const char *key, size_t key_length);
+static uint32_t internal_generate_md5(const char *key, size_t key_length);
+
+uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm)
+{
+  uint32_t hash= 1; /* Just here to remove compile warning */
+  uint32_t x= 0;
+
+  switch (hash_algorithm)
+  {
+  case MEMCACHED_HASH_DEFAULT:
+    hash= internal_generate_hash(key, key_length);
+    break;
+  case MEMCACHED_HASH_MD5:
+    hash= internal_generate_md5(key, key_length);
+    break;
+  case MEMCACHED_HASH_CRC:
+    hash= ((hash_crc32(key, key_length) >> 16) & 0x7fff);
+    if (hash == 0)
+      hash= 1;
+    break;
+    /* FNV hash'es lifted from Dustin Sallings work */
+  case MEMCACHED_HASH_FNV1_64:
+    {
+      /* Thanks to pierre@demartines.com for the pointer */
+      uint64_t temp_hash;
+
+      temp_hash= FNV_64_INIT;
+      for (x= 0; x < key_length; x++)
+      {
+        temp_hash *= FNV_64_PRIME;
+        temp_hash ^= (uint64_t)key[x];
+      }
+      hash= (uint32_t)temp_hash;
+    }
+    break;
+  case MEMCACHED_HASH_FNV1A_64:
+    {
+      hash= (uint32_t) FNV_64_INIT;
+      for (x= 0; x < key_length; x++)
+      {
+        uint32_t val= (uint32_t)key[x];
+        hash ^= val;
+        hash *= (uint32_t) FNV_64_PRIME;
+      }
+    }
+    break;
+  case MEMCACHED_HASH_FNV1_32:
+    {
+      hash= FNV_32_INIT;
+      for (x= 0; x < key_length; x++)
+      {
+        uint32_t val= (uint32_t)key[x];
+        hash *= FNV_32_PRIME;
+        hash ^= val;
+      }
+    }
+    break;
+  case MEMCACHED_HASH_FNV1A_32:
+    {
+      hash= FNV_32_INIT;
+      for (x= 0; x < key_length; x++)
+      {
+        uint32_t val= (uint32_t)key[x];
+        hash ^= val;
+        hash *= FNV_32_PRIME;
+      }
+    }
+    break;
+    case MEMCACHED_HASH_HSIEH:
+    {
+#ifdef HAVE_HSIEH_HASH
+      hash= hsieh_hash(key, key_length);
+#endif
+      break;
+    }
+    case MEMCACHED_HASH_MURMUR:
+    {
+      hash= murmur_hash(key, key_length);
+      break;
+    }
+    case MEMCACHED_HASH_JENKINS:
+    {
+      hash= jenkins_hash(key, key_length, 13);
+      break;
+    }
+    case MEMCACHED_HASH_MAX:
+    default:
+    {
+      WATCHPOINT_ASSERT(0);
+      break;
+    }
+  }
+
+  return hash;
+}
+
+uint32_t generate_hash(memcached_st *ptr, const char *key, size_t key_length)
+{
+  uint32_t hash= 1; /* Just here to remove compile warning */
+
+
+  WATCHPOINT_ASSERT(memcached_server_count(ptr));
+
+  if (memcached_server_count(ptr) == 1)
+    return 0;
+
+  hash= memcached_generate_hash_value(key, key_length, ptr->hash);
+  WATCHPOINT_ASSERT(hash);
+  return hash;
+}
+
+static uint32_t dispatch_host(memcached_st *ptr, uint32_t hash)
+{
+  switch (ptr->distribution)
+  {
+  case MEMCACHED_DISTRIBUTION_CONSISTENT:
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
+  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
+    {
+      uint32_t num= ptr->continuum_points_counter;
+      WATCHPOINT_ASSERT(ptr->continuum);
+
+      hash= hash;
+      memcached_continuum_item_st *begin, *end, *left, *right, *middle;
+      begin= left= ptr->continuum;
+      end= right= ptr->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_CONSISTENT_MAX:
+  default:
+    WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
+    return hash % memcached_server_count(ptr);
+  }
+  /* NOTREACHED */
+}
+
+/*
+  One day make this public, and have it return the actual memcached_server_st
+  to the calling application.
+*/
+uint32_t memcached_generate_hash(memcached_st *ptr, const char *key, size_t key_length)
+{
+  uint32_t hash= 1; /* Just here to remove compile warning */
+
+  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= ptr->prefix_key_length + key_length;
+    char temp[temp_length];
+
+    if (temp_length > MEMCACHED_MAX_KEY -1)
+      return 0;
+
+    strncpy(temp, ptr->prefix_key, ptr->prefix_key_length);
+    strncpy(temp + ptr->prefix_key_length, key, key_length);
+    hash= generate_hash(ptr, temp, temp_length);
+  }
+  else
+  {
+    hash= generate_hash(ptr, key, key_length);
+  }
+
+  WATCHPOINT_ASSERT(hash);
+
+  if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS) && ptr->next_distribution_rebuild)
+  {
+    struct timeval now;
+
+    if (gettimeofday(&now, NULL) == 0 &&
+        now.tv_sec > ptr->next_distribution_rebuild)
+    {
+      run_distribution(ptr);
+    }
+  }
+
+  return dispatch_host(ptr, hash);
+}
+
+static uint32_t internal_generate_hash(const char *key, size_t key_length)
+{
+  const char *ptr= key;
+  uint32_t value= 0;
+
+  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 == 0 ? 1 : (uint32_t) value;
+}
+
+static uint32_t internal_generate_md5(const char *key, size_t key_length)
+{
+  unsigned char results[16];
+
+  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/libmemcached/hosts.c b/libmemcached/hosts.c
new file mode 100644 (file)
index 0000000..1cbc803
--- /dev/null
@@ -0,0 +1,505 @@
+#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_instance_st *instance;
+
+    qsort(memcached_server_list(ptr), memcached_server_count(ptr), sizeof(memcached_server_instance_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:
+    return update_continuum(ptr);
+  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 */
+  }
+
+  ptr->last_disconnected_server = NULL;
+
+  return MEMCACHED_SUCCESS;
+}
+
+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_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 host_index;
+  uint32_t continuum_index= 0;
+  uint32_t value;
+  memcached_server_instance_st *list;
+  uint32_t pointer_index;
+  uint32_t pointer_counter= 0;
+  uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
+  uint32_t pointer_per_hash= 1;
+  uint64_t total_weight= 0;
+  uint64_t is_ketama_weighted= 0;
+  uint64_t is_auto_ejecting= 0;
+  uint32_t points_per_server= 0;
+  uint32_t live_servers= 0;
+  struct timeval now;
+
+  if (gettimeofday(&now, NULL) != 0)
+  {
+    ptr->cached_errno = errno;
+    return MEMCACHED_ERRNO;
+  }
+
+  list = memcached_server_list(ptr);
+
+  /* count live servers (those without a retry delay set) */
+  is_auto_ejecting= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS);
+  if (is_auto_ejecting)
+  {
+    live_servers= 0;
+    ptr->next_distribution_rebuild= 0;
+    for (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->next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->next_distribution_rebuild)
+          ptr->next_distribution_rebuild= list[host_index].next_retry;
+      }
+    }
+  }
+  else
+  {
+    live_servers= memcached_server_count(ptr);
+  }
+
+  is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
+  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->continuum_count)
+  {
+    memcached_continuum_item_st *new_ptr;
+
+    new_ptr= ptr->call_realloc(ptr, ptr->continuum,
+                               sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server);
+
+    if (new_ptr == 0)
+      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+    ptr->continuum= new_ptr;
+    ptr->continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION;
+  }
+
+  if (is_ketama_weighted)
+  {
+    for (host_index = 0; host_index < memcached_server_count(ptr); ++host_index)
+    {
+      if (list[host_index].weight == 0)
+      {
+        list[host_index].weight = 1;
+      }
+      if (!is_auto_ejecting || list[host_index].next_retry <= now.tv_sec)
+        total_weight += list[host_index].weight;
+    }
+  }
+
+  for (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 (pointer_index= 0;
+           pointer_index < pointer_per_server / pointer_per_hash;
+           pointer_index++)
+      {
+        char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
+        size_t sort_host_length;
+
+        // Spymemcached ketema key format is: hostname/ip:port-index
+        // If hostname is not available then: /ip:port-index
+        sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+                                            "/%s:%u-%u",
+                                            list[host_index].hostname,
+                                            (uint32_t)list[host_index].port,
+                                            pointer_index);
+#ifdef DEBUG
+        printf("update_continuum: key is %s\n", sort_host);
+#endif
+
+        WATCHPOINT_ASSERT(sort_host_length);
+
+        if (is_ketama_weighted)
+        {
+          unsigned int i;
+          for (i = 0; i < pointer_per_hash; i++)
+          {
+             value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
+             ptr->continuum[continuum_index].index= host_index;
+             ptr->continuum[continuum_index++].value= value;
+          }
+        }
+        else
+        {
+          value= memcached_generate_hash_value(sort_host, sort_host_length, ptr->distribution_hash);
+          ptr->continuum[continuum_index].index= host_index;
+          ptr->continuum[continuum_index++].value= value;
+        }
+      }
+    }
+    else
+    {
+      for (pointer_index= 1;
+           pointer_index <= pointer_per_server / pointer_per_hash;
+           pointer_index++)
+      {
+        char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
+        size_t sort_host_length;
+
+        if (list[host_index].port == MEMCACHED_DEFAULT_PORT)
+        {
+          sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+                                              "%s-%u",
+                                              list[host_index].hostname,
+                                              pointer_index - 1);
+        }
+        else
+        {
+          sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
+                                              "%s:%u-%u",
+                                              list[host_index].hostname,
+                                              (uint32_t)list[host_index].port,
+                                              pointer_index - 1);
+        }
+
+        WATCHPOINT_ASSERT(sort_host_length);
+
+        if (is_ketama_weighted)
+        {
+          unsigned int i;
+          for (i = 0; i < pointer_per_hash; i++)
+          {
+             value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
+             ptr->continuum[continuum_index].index= host_index;
+             ptr->continuum[continuum_index++].value= value;
+          }
+        }
+        else
+        {
+          value= memcached_generate_hash_value(sort_host, sort_host_length, ptr->distribution_hash);
+          ptr->continuum[continuum_index].index= host_index;
+          ptr->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->continuum_points_counter= pointer_counter;
+  qsort(ptr->continuum, ptr->continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);
+
+#ifdef DEBUG
+  for (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, memcached_server_st *list)
+{
+  uint32_t x;
+  uint32_t count;
+  memcached_server_st *new_host_list;
+
+  if (! list)
+    return MEMCACHED_SUCCESS;
+
+  count= memcached_servers_count(list);
+  new_host_list= ptr->call_realloc(ptr, memcached_server_list(ptr),
+                                   sizeof(memcached_server_instance_st) * (count + memcached_server_count(ptr)));
+
+  if (! new_host_list)
+    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+  memcached_server_list_set(ptr, new_host_list);
+
+  for (x= 0; x < count; x++)
+  {
+    memcached_server_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));
+
+    memcached_server_create(ptr, instance);
+    /* TODO check return type */
+    (void)memcached_server_create_with(ptr, instance, list[x].hostname,
+                                       list[x].port, list[x].weight, list[x].type);
+    ptr->number_of_hosts++;
+  }
+
+  // Provides backwards compatibility with server list.
+  {
+    memcached_server_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_instance_st *new_host_list;
+  memcached_server_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= ptr->call_realloc(ptr, memcached_server_list(ptr),
+                                   sizeof(memcached_server_instance_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_remove(memcached_server_st *st_ptr)
+{
+  uint32_t x, host_index;
+  memcached_st *ptr= st_ptr->root;
+  memcached_server_st *list= memcached_server_list(ptr);
+
+  for (x= 0, host_index= 0; x < memcached_server_count(ptr); x++)
+  {
+    if (strncmp(list[x].hostname, st_ptr->hostname, MEMCACHED_MAX_HOST_LENGTH) != 0 || list[x].port != st_ptr->port)
+    {
+      if (host_index != x)
+        memcpy(list+host_index, list+x, sizeof(memcached_server_st));
+      host_index++;
+    }
+  }
+  ptr->number_of_hosts= host_index;
+
+  if (st_ptr->address_info)
+  {
+    freeaddrinfo(st_ptr->address_info);
+    st_ptr->address_info= NULL;
+  }
+  run_distribution(ptr);
+
+  return MEMCACHED_SUCCESS;
+}
+
+memcached_server_st *memcached_server_list_append(memcached_server_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);
+}
+
+memcached_server_st *memcached_server_list_append_with_weight(memcached_server_st *ptr,
+                                                              const char *hostname, in_port_t port,
+                                                              uint32_t weight,
+                                                              memcached_return_t *error)
+{
+  unsigned int count;
+  memcached_server_instance_st *new_host_list;
+
+  if (hostname == NULL || error == NULL)
+    return NULL;
+
+  if (! port)
+    port= MEMCACHED_DEFAULT_PORT;
+
+  /* Increment count for hosts */
+  count= 1;
+  if (ptr != NULL)
+  {
+    count+= memcached_servers_count(ptr);
+  }
+
+  new_host_list= (memcached_server_instance_st *)realloc(ptr, sizeof(memcached_server_instance_st) * count);
+  if (!new_host_list)
+  {
+    *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+    return NULL;
+  }
+
+  /* TODO: Check return type */
+  memcached_server_create_with(NULL, &new_host_list[count-1], hostname, port, weight, MEMCACHED_CONNECTION_TCP);
+
+  /* Backwards compatibility hack */
+  memcached_servers_set_count(new_host_list, count);
+
+  *error= MEMCACHED_SUCCESS;
+  return new_host_list;
+}
diff --git a/libmemcached/include.am b/libmemcached/include.am
new file mode 100644 (file)
index 0000000..41c5c59
--- /dev/null
@@ -0,0 +1,152 @@
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+
+EXTRA_DIST+= \
+            libmemcached/configure.h.in \
+            libmemcached/libmemcached_probes.d \
+            libmemcached/memcached/README.txt
+
+noinst_HEADERS+= \
+                libmemcached/byteorder.h \
+                libmemcached/common.h \
+                libmemcached/internal.h \
+                libmemcached/io.h \
+                libmemcached/libmemcached_probes.h \
+                libmemcached/protocol/ascii_handler.h \
+                libmemcached/protocol/binary_handler.h \
+                libmemcached/protocol/common.h \
+                libmemcached/response.h
+
+nobase_include_HEADERS+= \
+                        libmemcached/analyze.h \
+                        libmemcached/auto.h \
+                        libmemcached/behavior.h \
+                        libmemcached/callback.h \
+                        libmemcached/configure.h \
+                        libmemcached/constants.h \
+                        libmemcached/dump.h \
+                        libmemcached/exception.hpp \
+                        libmemcached/get.h \
+                        libmemcached/memcached.h \
+                        libmemcached/memcached.hpp \
+                        libmemcached/memcached/protocol_binary.h \
+                        libmemcached/protocol/cache.h \
+                        libmemcached/protocol/callback.h \
+                        libmemcached/protocol_handler.h \
+                        libmemcached/result.h \
+                        libmemcached/server.h \
+                        libmemcached/stats.h \
+                        libmemcached/storage.h \
+                        libmemcached/string.h \
+                        libmemcached/types.h \
+                        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_LDFLAGS= ${AM_LDFLAGS} -version-info 0:0:0 
+
+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/string.c
+
+lib_LTLIBRARIES+= libmemcached/libmemcached.la
+libmemcached_libmemcached_la_CFLAGS= ${AM_CFLAGS} ${NO_CONVERSION}
+libmemcached_libmemcached_la_SOURCES = \
+                                      libmemcached/allocators.c \
+                                      libmemcached/analyze.c \
+                                      libmemcached/auto.c \
+                                      libmemcached/behavior.c \
+                                      libmemcached/connect.c \
+                                      libmemcached/crc.c \
+                                      libmemcached/delete.c \
+                                      libmemcached/do.c \
+                                      libmemcached/dump.c \
+                                      libmemcached/fetch.c \
+                                      libmemcached/flush.c \
+                                      libmemcached/flush_buffers.c \
+                                      libmemcached/get.c \
+                                      libmemcached/hash.c \
+                                      libmemcached/hosts.c \
+                                      libmemcached/io.c \
+                                      libmemcached/jenkins_hash.c \
+                                      libmemcached/key.c \
+                                      libmemcached/md5.c \
+                                      libmemcached/memcached.c \
+                                      libmemcached/murmur_hash.c \
+                                      libmemcached/parse.c \
+                                      libmemcached/purge.c \
+                                      libmemcached/quit.c \
+                                      libmemcached/response.c \
+                                      libmemcached/result.c \
+                                      libmemcached/server.c \
+                                      libmemcached/stats.c \
+                                      libmemcached/storage.c \
+                                      libmemcached/strerror.c \
+                                      libmemcached/verbosity.c \
+                                      libmemcached/version.c
+
+
+if INCLUDE_HSIEH_SRC
+libmemcached_libmemcached_la_SOURCES += libmemcached/hsieh_hash.c
+endif
+
+libmemcached_libmemcached_la_DEPENDENCIES= libmemcached/libmemcachedcallbacks.la libmemcached/libmemcachedinternal.la
+libmemcached_libmemcached_la_LIBADD= $(LIBM) libmemcached/libmemcachedcallbacks.la libmemcached/libmemcachedinternal.la
+libmemcached_libmemcached_la_LDFLAGS= ${AM_LDFLAGS} -version-info ${MEMCACHED_LIBRARY_VERSION}
+
+if BUILD_LIBMEMCACHEDUTIL
+nobase_include_HEADERS+= \
+                        libmemcached/memcached_util.h \
+                        libmemcached/util/pool.h
+lib_LTLIBRARIES+= libmemcached/libmemcachedutil.la
+endif
+
+libmemcached_libmemcachedutil_la_SOURCES= libmemcached/util/pool.c
+libmemcached_libmemcachedutil_la_LIBADD= libmemcached/libmemcached.la
+libmemcached_libmemcachedutil_la_LDFLAGS= ${AM_LDFLAGS} -version-info 0:0:0
+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_DTRACE
+BUILT_SOURCES+= libmemcached/dtrace_probes.h
+libmemcached_libmemcached_la_SOURCES += libmemcached/libmemcached_probes.d
+endif
+
+if DTRACE_NEEDS_OBJECTS
+libmemcached_libmemcached_la_DEPENDENCIES += libmemcached/libmemcached_probes.o
+endif
+
+SUFFIXES+= .d
+
+libmemcached/dtrace_probes.h: libmemcached/libmemcached_probes.d
+       $(DTRACE) $(DTRACEFLAGS) -h -o libmemcached/dtrace_probes.h -s libmemcached/libmemcached_probes.d
+
+libmemcached/libmemcached_probes.o: libmemcached/libmemcached_probes.d $(libmemcached_libmemcached_la_OBJECTS)
+       $(DTRACE) $(DTRACEFLAGS) -o libmemcached/.libs/libmemcached_probes.o -G -s libmemcached/libmemcached_probes.d `grep '^pic_object' *.lo | cut -f 2 -d\'`
+       $(DTRACE) $(DTRACEFLAGS) -o libmemcached/libmemcached_probes.o -G -s libmemcached/libmemcached_probes.d `grep non_pic_object *.lo | cut -f 2 -d\' `
+
diff --git a/libmemcached/internal.h b/libmemcached/internal.h
new file mode 100644 (file)
index 0000000..2a15151
--- /dev/null
@@ -0,0 +1,35 @@
+/* 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: Internal functions used by the library. Not for public use!
+ *
+ */
+
+#ifndef LIBMEMCACHED_MEMCACHED_INTERNAL_H
+#define LIBMEMCACHED_MEMCACHED_INTERNAL_H
+
+#if defined(BUILDING_LIBMEMCACHED)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBMEMCACHED_LOCAL
+void libmemcached_free(memcached_st *ptr, void *mem);
+LIBMEMCACHED_LOCAL
+void *libmemcached_malloc(memcached_st *ptr, const size_t size);
+LIBMEMCACHED_LOCAL
+void *libmemcached_realloc(memcached_st *ptr, void *mem, const size_t size);
+LIBMEMCACHED_LOCAL
+void *libmemcached_calloc(memcached_st *ptr, size_t nelem, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BUILDING_LIBMEMCACHED */
+#endif /* LIBMEMCACHED_MEMCACHED_INTERNAL_H */
diff --git a/libmemcached/io.c b/libmemcached/io.c
new file mode 100644 (file)
index 0000000..5102d95
--- /dev/null
@@ -0,0 +1,699 @@
+/* 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: Server IO, Not public!
+ *
+ */
+
+
+#include "common.h"
+#include <sys/select.h>
+#include <poll.h>
+
+typedef enum {
+  MEM_READ,
+  MEM_WRITE
+} memc_read_or_write;
+
+static ssize_t io_flush(memcached_server_instance_st *ptr, memcached_return_t *error);
+static void increment_udp_message_id(memcached_server_instance_st *ptr);
+
+static memcached_return_t io_wait(memcached_server_instance_st *ptr,
+                                  memc_read_or_write read_or_write)
+{
+  struct pollfd fds= {
+    .fd= ptr->fd,
+    .events = POLLIN
+  };
+  int error;
+
+  unlikely (read_or_write == MEM_WRITE) /* write */
+    fds.events= POLLOUT;
+
+  /*
+   ** 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;
+  }
+
+  int timeout= ptr->root->poll_timeout;
+  if (ptr->root->flags.no_block == false)
+    timeout= -1;
+
+  error= poll(&fds, 1, timeout);
+
+  if (error == 1)
+    return MEMCACHED_SUCCESS;
+  else if (error == 0)
+    return MEMCACHED_TIMEOUT;
+
+  /* Imposssible for anything other then -1 */
+  WATCHPOINT_ASSERT(error == -1);
+  memcached_quit_server(ptr, 1);
+
+  return MEMCACHED_FAILURE;
+}
+
+/**
+ * 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_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= read(ptr->fd,
+                     ptr->read_ptr + ptr->read_data_length,
+                     MEMCACHED_MAX_BUFFER - ptr->read_data_length);
+
+    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_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;
+
+    ptr->root->options.is_processing_input= true;
+
+    char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+    memcached_return_t error;
+    error= memcached_response(ptr, buffer, sizeof(buffer),
+                              &ptr->root->result);
+
+    ptr->root->options.is_processing_input = false;
+
+    if (error == MEMCACHED_SUCCESS)
+    {
+      for (unsigned int x= 0; x < cb.number_of_callback; x++)
+      {
+        error= (*cb.callback[x])(ptr->root, &ptr->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;
+}
+
+static inline void memcached_io_cork_push(memcached_server_st *ptr)
+{
+#ifdef CORK
+  if (ptr->root->flags.cork == false || ptr->state.is_corked)
+    return;
+
+  ptr->state.is_corked=
+    cork_switch(ptr, true) == MEM_TRUE ? true : false;
+
+  WATCHPOINT_ASSERT(ptr->state.is_corked == true);
+#else
+  (void)ptr;
+#endif
+}
+
+static inline void memcached_io_cork_pop(memcached_server_st *ptr)
+{
+#ifdef CORK
+  if (ptr->root->flags.cork == false || ptr->state.is_corked == false)
+    return;
+
+  ptr->state.is_corked=
+    cork_switch(ptr, false) == MEM_FALSE ? false : true;
+
+  WATCHPOINT_ASSERT(ptr->state.is_corked == false);
+#else
+  (void)ptr;
+#endif
+}
+
+#ifdef UNUSED
+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= read(ptr->hosts[x].fd,
+                      ptr->hosts[x].read_ptr + ptr->hosts[x].read_data_length,
+                      MEMCACHED_MAX_BUFFER - ptr->hosts[x].read_data_length);
+      if (data_read == -1)
+        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_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= read(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER);
+        if (data_read > 0)
+          break;
+        else if (data_read == -1)
+        {
+          ptr->cached_errno= errno;
+          memcached_return_t rc= MEMCACHED_UNKNOWN_READ_FAILURE;
+          switch (errno)
+          {
+          case EAGAIN:
+          case EINTR:
+            if ((rc= io_wait(ptr, MEM_READ)) == MEMCACHED_SUCCESS)
+              continue;
+            /* fall through */
+
+          default:
+            {
+              memcached_quit_server(ptr, 1);
+              *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.
+          */
+          memcached_quit_server(ptr, 1);
+          *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;
+}
+
+ssize_t memcached_io_write(memcached_server_instance_st *ptr,
+                           const void *buffer, size_t length, char with_flush)
+{
+  size_t original_length;
+  const char* buffer_ptr;
+
+  WATCHPOINT_ASSERT(ptr->fd != -1);
+
+  original_length= length;
+  buffer_ptr= buffer;
+
+  /* more writable data is coming if a flush isn't required, so delay send */
+  if (! with_flush)
+  {
+    memcached_io_cork_push(ptr);
+  }
+
+  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 != -1);
+      sent_length= io_flush(ptr, &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 != -1);
+    if (io_flush(ptr, &rc) == -1)
+    {
+      return -1;
+    }
+
+    memcached_io_cork_pop(ptr);
+  }
+
+  return (ssize_t) original_length;
+}
+
+memcached_return_t memcached_io_close(memcached_server_instance_st *ptr)
+{
+  if (ptr->fd == -1)
+  {
+    return MEMCACHED_SUCCESS;
+  }
+
+  /* in case of death shutdown to avoid blocking at close() */
+  if (shutdown(ptr->fd, SHUT_RDWR) == -1 && errno != ENOTCONN)
+  {
+    WATCHPOINT_NUMBER(ptr->fd);
+    WATCHPOINT_ERRNO(errno);
+    WATCHPOINT_ASSERT(errno);
+  }
+
+  if (close(ptr->fd) == -1)
+  {
+    WATCHPOINT_ERRNO(errno);
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+memcached_server_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_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_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:
+    memc->cached_errno = errno;
+    /* 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_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_instance_st *ptr,
+                        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 != -1);
+    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 != -1);
+
+  // 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 != -1);
+    WATCHPOINT_ASSERT(write_length > 0);
+    sent_length= 0;
+    if (ptr->type == MEMCACHED_CONNECTION_UDP)
+      increment_udp_message_id(ptr);
+    sent_length= write(ptr->fd, local_write_ptr, write_length);
+
+    if (sent_length == -1)
+    {
+      ptr->cached_errno= errno;
+      switch (errno)
+      {
+      case ENOBUFS:
+        continue;
+      case EAGAIN:
+        {
+          /*
+           * 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, 1);
+          return -1;
+        }
+      default:
+        memcached_quit_server(ptr, 1);
+        *error= MEMCACHED_ERRNO;
+        return -1;
+      }
+    }
+
+    if (ptr->type == MEMCACHED_CONNECTION_UDP &&
+        (size_t)sent_length != write_length)
+    {
+      memcached_quit_server(ptr, 1);
+      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_instance_st *ptr)
+{
+  memcached_quit_server(ptr, 1);
+}
+
+/**
+ * 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_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_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_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_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.h b/libmemcached/io.h
new file mode 100644 (file)
index 0000000..df7708c
--- /dev/null
@@ -0,0 +1,82 @@
+/* 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: Server IO, Not public!
+ *
+ */
+
+#ifndef LIBMEMCACHED_MEMCACHED_IO_H
+#define LIBMEMCACHED_MEMCACHED_IO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(BUILDING_LIBMEMCACHED)
+
+#include "libmemcached/memcached.h"
+
+#define MAX_UDP_DATAGRAM_LENGTH 1400
+#define UDP_DATAGRAM_HEADER_LENGTH 8
+#define UDP_REQUEST_ID_MSG_SIG_DIGITS 10
+#define UDP_REQUEST_ID_THREAD_MASK 0xFFFF << UDP_REQUEST_ID_MSG_SIG_DIGITS
+#define get_udp_datagram_request_id(A) ntohs((A)->request_id)
+#define get_udp_datagram_seq_num(A) ntohs((A)->sequence_number)
+#define get_udp_datagram_num_datagrams(A) ntohs((A)->num_datagrams)
+#define get_msg_num_from_request_id(A) ( (A) & (~(UDP_REQUEST_ID_THREAD_MASK)) )
+#define get_thread_id_from_request_id(A) ( (A) & (UDP_REQUEST_ID_THREAD_MASK) ) >> UDP_REQUEST_ID_MSG_SIG_DIGITS
+#define generate_udp_request_thread_id(A) (A) << UDP_REQUEST_ID_MSG_SIG_DIGITS
+#define UDP_REQUEST_ID_MAX_THREAD_ID get_thread_id_from_request_id(0xFFFF)
+
+struct udp_datagram_header_st
+{
+  uint16_t request_id;
+  uint16_t sequence_number;
+  uint16_t num_datagrams;
+  uint16_t reserved;
+};
+
+LIBMEMCACHED_LOCAL
+ssize_t memcached_io_write(memcached_server_instance_st *ptr,
+                           const void *buffer, size_t length, char with_flush);
+
+LIBMEMCACHED_LOCAL
+void memcached_io_reset(memcached_server_instance_st *ptr);
+
+LIBMEMCACHED_LOCAL
+memcached_return_t memcached_io_read(memcached_server_instance_st *ptr,
+                                     void *buffer, size_t length, ssize_t *nread);
+
+/* Read a line (terminated by '\n') into the buffer */
+LIBMEMCACHED_LOCAL
+memcached_return_t memcached_io_readline(memcached_server_instance_st *ptr,
+                                         char *buffer_ptr,
+                                         size_t size);
+
+LIBMEMCACHED_LOCAL
+memcached_return_t memcached_io_close(memcached_server_instance_st *ptr);
+
+/* Read n bytes of data from the server and store them in dta */
+LIBMEMCACHED_LOCAL
+memcached_return_t memcached_safe_read(memcached_server_instance_st *ptr,
+                                       void *dta,
+                                       size_t size);
+
+LIBMEMCACHED_LOCAL
+memcached_return_t memcached_io_init_udp_header(memcached_server_instance_st *ptr,
+                                                uint16_t thread_id);
+
+LIBMEMCACHED_LOCAL
+memcached_server_instance_st *memcached_io_get_readable_server(memcached_st *memc);
+
+#endif /* BUILDING_LIBMEMCACHED */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBMEMCACHED_MEMCACHED_IO_H */
index e84cf3edefc0af9c829f792e933e4dfe60611cd4..e4aa4f19da0b4535535260516ed0c670c43679a5 100644 (file)
@@ -63,7 +63,7 @@ uint32_t jenkins_hash(const void *key, size_t length, uint32_t initval)
   a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
 
   u.ptr = key;
-#ifdef BYTEORDER_LITTLE_ENDIAN
+#ifndef WORDS_BIGENDIAN
   if ((u.i & 0x3) == 0)
   {
     const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
@@ -202,7 +202,7 @@ uint32_t jenkins_hash(const void *key, size_t length, uint32_t initval)
     case 0 : return c;
     default : return c;
     }
-#ifdef BYTEORDER_LITTLE_ENDIAN
+#ifndef WORDS_BIGENDIAN
   }
 #endif
 
diff --git a/libmemcached/key.c b/libmemcached/key.c
new file mode 100644 (file)
index 0000000..76a7d8e
--- /dev/null
@@ -0,0 +1,27 @@
+#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/libmemcached.ver b/libmemcached/libmemcached.ver
deleted file mode 100644 (file)
index 38b5cab..0000000
+++ /dev/null
@@ -1 +0,0 @@
-libmemcached_3 { global: *; };
index b441a04738000f55fe4d83f81138d1fbc5b07cfd..ddc9ef4793198b587f55177c34117d680974d440 100644 (file)
@@ -1,3 +1,14 @@
+/* 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:
+ *
+ */
+
 /*
  * This file contains the definition of the various probes supported by
  * libmemcached. Currently it only support DTRACE, but just create an
index 4e8ec062bcf4f979f92d7aa86404baa640240ee6..027ef20acbacc3a5260dbecbffc76e5ae409aeb4 100644 (file)
@@ -5,43 +5,92 @@
 
 memcached_st *memcached_create(memcached_st *ptr)
 {
-  memcached_result_st *result_ptr;
-
   if (ptr == NULL)
   {
     ptr= (memcached_st *)calloc(1, sizeof(memcached_st));
 
-    if (!ptr)
+    if (! ptr)
+    {
       return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
+    }
 
-    ptr->is_allocated= true;
+    ptr->options.is_allocated= true;
   }
   else
   {
     memset(ptr, 0, sizeof(memcached_st));
   }
 
+  ptr->options.is_initialized= true;
+  ptr->options.is_purging= false;
+  ptr->options.is_processing_input= false;
+
   memcached_set_memory_allocators(ptr, NULL, NULL, NULL, NULL);
 
-  result_ptr= memcached_result_create(ptr, &ptr->result);
-  WATCHPOINT_ASSERT(result_ptr);
+  if (! memcached_result_create(ptr, &ptr->result))
+  {
+    memcached_free(ptr);
+    return NULL;
+  }
   ptr->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
   ptr->connect_timeout= MEMCACHED_DEFAULT_TIMEOUT;
   ptr->retry_timeout= 0;
   ptr->distribution= MEMCACHED_DISTRIBUTION_MODULA;
 
+
+  ptr->send_size= -1;
+  ptr->recv_size= -1;
+
   /* TODO, Document why we picked these defaults */
   ptr->io_msg_watermark= 500;
   ptr->io_bytes_watermark= 65 * 1024;
 
+  WATCHPOINT_ASSERT_INITIALIZED(&ptr->result);
+
   return ptr;
 }
 
+void server_list_free(memcached_st *ptr, memcached_server_st *servers)
+{
+  uint32_t x;
+
+  if (servers == NULL)
+    return;
+
+  for (x= 0; x < memcached_servers_count(servers); x++)
+  {
+    if (servers[x].address_info)
+    {
+      freeaddrinfo(servers[x].address_info);
+      servers[x].address_info= NULL;
+    }
+  }
+
+  if (ptr)
+  {
+    ptr->call_free(ptr, servers);
+  }
+  else
+  {
+    free(servers);
+  }
+}
+
+void memcached_servers_reset(memcached_st *ptr)
+{
+  server_list_free(ptr, memcached_server_list(ptr));
+
+  memcached_server_list_set(ptr, NULL);
+  ptr->number_of_hosts= 0;
+  ptr->last_disconnected_server= NULL;
+  ptr->server_failure_limit= 0;
+}
+
 void memcached_free(memcached_st *ptr)
 {
   /* If we have anything open, lets close it now */
   memcached_quit(ptr);
-  server_list_free(ptr, ptr->hosts);
+  server_list_free(ptr, memcached_server_list(ptr));
   memcached_result_free(&ptr->result);
 
   if (ptr->on_cleanup)
@@ -50,10 +99,14 @@ void memcached_free(memcached_st *ptr)
   if (ptr->continuum)
     ptr->call_free(ptr, ptr->continuum);
 
-  if (ptr->is_allocated)
+  if (memcached_is_allocated(ptr))
+  {
     ptr->call_free(ptr, ptr);
+  }
   else
-    memset(ptr, 0, sizeof(memcached_st));
+  {
+    ptr->options.is_initialized= false;
+  }
 }
 
 /*
@@ -63,13 +116,13 @@ void memcached_free(memcached_st *ptr)
 */
 memcached_st *memcached_clone(memcached_st *clone, memcached_st *source)
 {
-  memcached_return rc= MEMCACHED_SUCCESS;
+  memcached_return_t rc= MEMCACHED_SUCCESS;
   memcached_st *new_clone;
 
   if (source == NULL)
     return memcached_create(clone);
 
-  if (clone && clone->is_allocated)
+  if (clone && memcached_is_allocated(clone))
   {
     return NULL;
   }
@@ -87,7 +140,7 @@ memcached_st *memcached_clone(memcached_st *clone, memcached_st *source)
   new_clone->retry_timeout= source->retry_timeout;
   new_clone->distribution= source->distribution;
   new_clone->hash= source->hash;
-  new_clone->hash_continuum= source->hash_continuum;
+  new_clone->distribution_hash= source->distribution_hash;
   new_clone->user_data= source->user_data;
 
   new_clone->snd_timeout= source->snd_timeout;
@@ -107,8 +160,8 @@ memcached_st *memcached_clone(memcached_st *clone, memcached_st *source)
   new_clone->io_key_prefetch= source->io_key_prefetch;
   new_clone->number_of_replicas= source->number_of_replicas;
 
-  if (source->hosts)
-    rc= memcached_server_push(new_clone, source->hosts);
+  if (memcached_server_list(source))
+    rc= memcached_server_push(new_clone, memcached_server_list(source));
 
   if (rc != MEMCACHED_SUCCESS)
   {
@@ -125,6 +178,7 @@ memcached_st *memcached_clone(memcached_st *clone, memcached_st *source)
   }
 
   rc= run_distribution(new_clone);
+
   if (rc != MEMCACHED_SUCCESS)
   {
     memcached_free(new_clone);
@@ -137,6 +191,7 @@ memcached_st *memcached_clone(memcached_st *clone, memcached_st *source)
 
   return new_clone;
 }
+
 void *memcached_get_user_data(memcached_st *ptr)
 {
   return ptr->user_data;
@@ -146,5 +201,6 @@ void *memcached_set_user_data(memcached_st *ptr, void *data)
 {
   void *ret= ptr->user_data;
   ptr->user_data= data;
+
   return ret;
 }
index 722da814d6df773e9b2a24435ad9305fa1c75193..d86f9bc9f74cdfa5cddce68c33c2b6c71827bb50 100644 (file)
@@ -1,10 +1,13 @@
-/*
+/* 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: interface for memcached server
  * Description: main include file for libmemcached
  *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Brian Aker
  */
 
 #ifndef __MEMCACHED_H__
 
 #include <stdlib.h>
 #include <inttypes.h>
+
 #if !defined(__cplusplus)
 # include <stdbool.h>
 #endif
+
 #include <sys/types.h>
 #include <netinet/in.h>
 
 #include <libmemcached/visibility.h>
-#include <libmemcached/memcached_configure.h>
-#include <libmemcached/memcached_constants.h>
-#include <libmemcached/memcached_types.h>
-#include <libmemcached/memcached_get.h>
-#include <libmemcached/memcached_server.h>
-#include <libmemcached/memcached_string.h>
-#include <libmemcached/memcached_result.h>
-#include <libmemcached/memcached_storage.h>
+#include <libmemcached/configure.h>
+#include <libmemcached/constants.h>
+#include <libmemcached/types.h>
+#include <libmemcached/string.h>
+#include <libmemcached/stats.h>
+// Everything above this line must be in the order specified.
+#include <libmemcached/analyze.h>
+#include <libmemcached/auto.h>
+#include <libmemcached/behavior.h>
+#include <libmemcached/callback.h>
+#include <libmemcached/dump.h>
+#include <libmemcached/get.h>
+#include <libmemcached/result.h>
+#include <libmemcached/server.h>
+#include <libmemcached/storage.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#define MEMCACHED_VERSION_STRING_LENGTH 24
-#define LIBMEMCACHED_VERSION_STRING "0.35"
-
-struct memcached_analysis_st {
-  uint32_t average_item_size;
-  uint32_t longest_uptime;
-  uint32_t least_free_server;
-  uint32_t most_consumed_server;
-  uint32_t oldest_server;
-  double pool_hit_ratio;
-  uint64_t most_used_bytes;
-  uint64_t least_remaining_bytes;
-};
-
-struct memcached_stat_st {
-  uint32_t connection_structures;
-  uint32_t curr_connections;
-  uint32_t curr_items;
-  uint32_t pid;
-  uint32_t pointer_size;
-  uint32_t rusage_system_microseconds;
-  uint32_t rusage_system_seconds;
-  uint32_t rusage_user_microseconds;
-  uint32_t rusage_user_seconds;
-  uint32_t threads;
-  uint32_t time;
-  uint32_t total_connections;
-  uint32_t total_items;
-  uint32_t uptime;
-  uint64_t bytes;
-  uint64_t bytes_read;
-  uint64_t bytes_written;
-  uint64_t cmd_get;
-  uint64_t cmd_set;
-  uint64_t evictions;
-  uint64_t get_hits;
-  uint64_t get_misses;
-  uint64_t limit_maxbytes;
-  char version[MEMCACHED_VERSION_STRING_LENGTH];
-};
-
 struct memcached_st {
-  uint8_t purging;
-  bool is_allocated;
-  uint8_t distribution;
-  uint8_t hash;
-  uint32_t continuum_points_counter;
-  memcached_server_st *hosts;
+  struct {
+    bool is_allocated:1;
+    bool is_initialized:1;
+    bool is_purging:1;
+    bool is_processing_input:1;
+  } options;
+  memcached_server_distribution_t distribution;
+  memcached_hash_t hash;
+  uint32_t continuum_points_counter; // Ketama
+  memcached_server_st *servers;
   memcached_server_st *last_disconnected_server;
   int32_t snd_timeout;
   int32_t rcv_timeout;
@@ -88,36 +63,64 @@ struct memcached_st {
   uint32_t io_bytes_watermark;
   uint32_t io_key_prefetch;
   uint32_t number_of_hosts;
-  uint32_t cursor_server;
   int cached_errno;
-  uint32_t flags;
+  /**
+    @note these are static and should not change without a call to behavior.
+  */
+  struct {
+    bool auto_eject_hosts:1;
+    bool binary_protocol:1;
+    bool buffer_requests:1;
+    bool hash_with_prefix_key:1;
+    bool ketama_weighted:1;
+    bool no_block:1;
+    bool no_reply:1;
+    bool randomize_replica_read:1;
+    bool reuse_memory:1;
+    bool support_cas:1;
+    bool tcp_nodelay:1;
+    bool use_cache_lookups:1;
+    bool use_sort_hosts:1;
+    bool use_udp:1;
+    bool verify_key:1;
+    bool cork:1;
+  } flags;
   int32_t poll_timeout;
   int32_t connect_timeout;
   int32_t retry_timeout;
-  uint32_t continuum_count;
+  uint32_t continuum_count; // Ketama
   int send_size;
   int recv_size;
   void *user_data;
-  time_t next_distribution_rebuild;
+  time_t next_distribution_rebuild; // Ketama
   size_t prefix_key_length;
-  memcached_hash hash_continuum;
-  memcached_result_st result;
-  memcached_continuum_item_st *continuum;
-  memcached_clone_func on_clone;
-  memcached_cleanup_func on_cleanup;
-  memcached_free_function call_free;
-  memcached_malloc_function call_malloc;
-  memcached_realloc_function call_realloc;
-  memcached_calloc_function call_calloc;
-  memcached_trigger_key get_key_failure;
-  memcached_trigger_delete_key delete_trigger;
-  char prefix_key[MEMCACHED_PREFIX_KEY_MAX_SIZE];
   uint32_t number_of_replicas;
+  memcached_hash_t distribution_hash;
+  memcached_result_st result;
+  memcached_continuum_item_st *continuum; // Ketama
+  memcached_clone_fn on_clone;
+  memcached_cleanup_fn on_cleanup;
+  memcached_free_fn call_free;
+  memcached_malloc_fn call_malloc;
+  memcached_realloc_fn call_realloc;
+  memcached_calloc_fn call_calloc;
+  memcached_trigger_key_fn get_key_failure;
+  memcached_trigger_delete_key_fn delete_trigger;
   memcached_callback_st *callbacks;
+  char prefix_key[MEMCACHED_PREFIX_KEY_MAX_SIZE];
 };
 
 LIBMEMCACHED_API
-memcached_return memcached_version(memcached_st *ptr);
+memcached_return_t memcached_version(memcached_st *ptr);
+
+LIBMEMCACHED_API
+void memcached_servers_reset(memcached_st *ptr);
+
+// Local Only Inline
+static inline memcached_server_st *memcached_server_instance_fetch(memcached_st *ptr, uint32_t server_key)
+{
+  return &ptr->servers[server_key];
+}
 
 /* Public API */
 
@@ -132,198 +135,124 @@ LIBMEMCACHED_API
 memcached_st *memcached_clone(memcached_st *clone, memcached_st *ptr);
 
 LIBMEMCACHED_API
-memcached_return memcached_delete(memcached_st *ptr, const char *key, size_t key_length,
+memcached_return_t memcached_delete(memcached_st *ptr, const char *key, size_t key_length,
                                   time_t expiration);
+
 LIBMEMCACHED_API
-memcached_return memcached_increment(memcached_st *ptr,
-                                     const char *key, size_t key_length,
-                                     uint32_t offset,
-                                     uint64_t *value);
-LIBMEMCACHED_API
-memcached_return memcached_decrement(memcached_st *ptr,
-                                     const char *key, size_t key_length,
-                                     uint32_t offset,
-                                     uint64_t *value);
-
-LIBMEMCACHED_API
-memcached_return memcached_increment_by_key(memcached_st *ptr, 
-                                            const char *master_key, size_t master_key_length,
-                                            const char *key, size_t key_length,
-                                            uint64_t offset,
-                                            uint64_t *value);
-
-LIBMEMCACHED_API
-memcached_return memcached_decrement_by_key(memcached_st *ptr, 
-                                            const char *master_key, size_t master_key_length,
-                                            const char *key, size_t key_length,
-                                            uint64_t offset,
-                                            uint64_t *value);
-
-LIBMEMCACHED_API
-memcached_return 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);
-LIBMEMCACHED_API
-memcached_return 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);
-LIBMEMCACHED_API
-memcached_return memcached_increment_with_initial_by_key(memcached_st *ptr,
-                                                         const char *master_key,
-                                                         size_t master_key_length,
-                                                         const char *key,
-                                                         size_t key_length,
-                                                         uint64_t offset,
-                                                         uint64_t initial,
-                                                         time_t expiration,
-                                                         uint64_t *value);
-LIBMEMCACHED_API
-memcached_return memcached_decrement_with_initial_by_key(memcached_st *ptr,
-                                                         const char *master_key,
-                                                         size_t master_key_length,
-                                                         const char *key,
-                                                         size_t key_length,
-                                                         uint64_t offset,
-                                                         uint64_t initial,
-                                                         time_t expiration,
-                                                         uint64_t *value);
-LIBMEMCACHED_API
-void memcached_stat_free(memcached_st *, memcached_stat_st *);
-LIBMEMCACHED_API
-memcached_stat_st *memcached_stat(memcached_st *ptr, char *args, memcached_return *error);
-LIBMEMCACHED_API
-memcached_return memcached_stat_servername(memcached_stat_st *memc_stat, char *args,
-                                           char *hostname, unsigned int port);
-LIBMEMCACHED_API
-memcached_return memcached_flush(memcached_st *ptr, time_t expiration);
-LIBMEMCACHED_API
-memcached_return memcached_verbosity(memcached_st *ptr, unsigned int verbosity);
-LIBMEMCACHED_API
-void memcached_quit(memcached_st *ptr);
+memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration);
+
 LIBMEMCACHED_API
-const char *memcached_strerror(memcached_st *ptr, memcached_return rc);
+memcached_return_t memcached_verbosity(memcached_st *ptr, unsigned int verbosity);
+
 LIBMEMCACHED_API
-memcached_return memcached_behavior_set(memcached_st *ptr, memcached_behavior flag, uint64_t data);
+void memcached_quit(memcached_st *ptr);
+
 LIBMEMCACHED_API
-uint64_t memcached_behavior_get(memcached_st *ptr, memcached_behavior flag);
+const char *memcached_strerror(memcached_st *ptr, memcached_return_t rc);
 
 /* The two public hash bits */
 LIBMEMCACHED_API
-uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash hash_algorithm);
+uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm);
+
 LIBMEMCACHED_API
 uint32_t memcached_generate_hash(memcached_st *ptr, const char *key, size_t key_length);
 
 LIBMEMCACHED_API
-memcached_return memcached_flush_buffers(memcached_st *mem);
+memcached_return_t memcached_flush_buffers(memcached_st *mem);
 
 /* Server Public functions */
 
 LIBMEMCACHED_API
-memcached_return memcached_server_add_udp(memcached_st *ptr,
-                                          const char *hostname,
-                                          unsigned int port);
+memcached_return_t memcached_server_add_udp(memcached_st *ptr,
+                                            const char *hostname,
+                                            in_port_t port);
 LIBMEMCACHED_API
-memcached_return memcached_server_add_unix_socket(memcached_st *ptr,
-                                                  const char *filename);
+memcached_return_t memcached_server_add_unix_socket(memcached_st *ptr,
+                                                    const char *filename);
 LIBMEMCACHED_API
-memcached_return memcached_server_add(memcached_st *ptr, const char *hostname,
-                                      unsigned int port);
+memcached_return_t memcached_server_add(memcached_st *ptr,
+                                        const char *hostname, in_port_t port);
 
 LIBMEMCACHED_API
-memcached_return memcached_server_add_udp_with_weight(memcached_st *ptr,
-                                                      const char *hostname,
-                                                      unsigned int port,
-                                                      uint32_t weight);
+memcached_return_t memcached_server_add_udp_with_weight(memcached_st *ptr,
+                                                        const char *hostname,
+                                                        in_port_t port,
+                                                        uint32_t weight);
 LIBMEMCACHED_API
-memcached_return memcached_server_add_unix_socket_with_weight(memcached_st *ptr,
-                                                              const char *filename,
-                                                              uint32_t weight);
+memcached_return_t memcached_server_add_unix_socket_with_weight(memcached_st *ptr,
+                                                                const char *filename,
+                                                                uint32_t weight);
 LIBMEMCACHED_API
-memcached_return memcached_server_add_with_weight(memcached_st *ptr, const char *hostname,
-                                                  unsigned int port,
-                                                  uint32_t weight);
+memcached_return_t memcached_server_add_with_weight(memcached_st *ptr, const char *hostname,
+                                                    in_port_t port,
+                                                    uint32_t weight);
 LIBMEMCACHED_API
 void memcached_server_list_free(memcached_server_st *ptr);
+
 LIBMEMCACHED_API
-memcached_return memcached_server_push(memcached_st *ptr, memcached_server_st *list);
+memcached_return_t memcached_server_push(memcached_st *ptr, memcached_server_st *list);
 
 LIBMEMCACHED_API
 memcached_server_st *memcached_server_list_append(memcached_server_st *ptr,
                                                   const char *hostname,
-                                                  unsigned int port,
-                                                  memcached_return *error);
+                                                  in_port_t port,
+                                                  memcached_return_t *error);
 LIBMEMCACHED_API
 memcached_server_st *memcached_server_list_append_with_weight(memcached_server_st *ptr,
                                                               const char *hostname,
-                                                              unsigned int port,
+                                                              in_port_t port,
                                                               uint32_t weight,
-                                                              memcached_return *error);
+                                                              memcached_return_t *error);
 LIBMEMCACHED_API
 unsigned int memcached_server_list_count(memcached_server_st *ptr);
+
 LIBMEMCACHED_API
 memcached_server_st *memcached_servers_parse(const char *server_strings);
 
 LIBMEMCACHED_API
 char *memcached_stat_get_value(memcached_st *ptr, memcached_stat_st *memc_stat,
-                               const char *key, memcached_return *error);
+                               const char *key, memcached_return_t *error);
 LIBMEMCACHED_API
 char ** memcached_stat_get_keys(memcached_st *ptr, memcached_stat_st *memc_stat,
-                                memcached_return *error);
+                                memcached_return_t *error);
 
 LIBMEMCACHED_API
-memcached_return memcached_delete_by_key(memcached_st *ptr,
-                                         const char *master_key, size_t master_key_length,
-                                         const char *key, size_t key_length,
-                                         time_t expiration);
+memcached_return_t memcached_delete_by_key(memcached_st *ptr,
+                                           const char *master_key, size_t master_key_length,
+                                           const char *key, size_t key_length,
+                                           time_t expiration);
 
 LIBMEMCACHED_API
-memcached_return memcached_fetch_execute(memcached_st *ptr,
-                                             memcached_execute_function *callback,
-                                             void *context,
-                                             unsigned int number_of_callbacks);
+memcached_return_t memcached_fetch_execute(memcached_st *ptr,
+                                           memcached_execute_fn *callback,
+                                           void *context,
+                                           unsigned int number_of_callbacks);
 
 LIBMEMCACHED_API
-memcached_return memcached_callback_set(memcached_st *ptr,
-                                        memcached_callback flag,
-                                        void *data);
-LIBMEMCACHED_API
-void *memcached_callback_get(memcached_st *ptr,
-                             memcached_callback flag,
-                             memcached_return *error);
-
-LIBMEMCACHED_API
-memcached_return memcached_dump(memcached_st *ptr, memcached_dump_func *function, void *context, uint32_t number_of_callbacks);
-
-
-LIBMEMCACHED_API
-memcached_return memcached_set_memory_allocators(memcached_st *ptr,
-                                                 memcached_malloc_function mem_malloc,
-                                                 memcached_free_function mem_free,
-                                                 memcached_realloc_function mem_realloc,
-                                                 memcached_calloc_function mem_calloc);
+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);
 
 LIBMEMCACHED_API
 void memcached_get_memory_allocators(memcached_st *ptr,
-                                     memcached_malloc_function *mem_malloc,
-                                     memcached_free_function *mem_free,
-                                     memcached_realloc_function *mem_realloc,
-                                     memcached_calloc_function *mem_calloc);
+                                     memcached_malloc_fn *mem_malloc,
+                                     memcached_free_fn *mem_free,
+                                     memcached_realloc_fn *mem_realloc,
+                                     memcached_calloc_fn *mem_calloc);
 
 LIBMEMCACHED_API
 void *memcached_get_user_data(memcached_st *ptr);
 LIBMEMCACHED_API
 void *memcached_set_user_data(memcached_st *ptr, void *data);
 
-LIBMEMCACHED_API
-memcached_return run_distribution(memcached_st *ptr);
+LIBMEMCACHED_LOCAL
+memcached_return_t run_distribution(memcached_st *ptr);
+
+#define memcached_is_allocated(__object) ((__object)->options.is_allocated)
+#define memcached_is_initialized(__object) ((__object)->options.is_initialized)
+
 #ifdef __cplusplus
 }
 #endif
index d7086b4ce301ea11a876fdcb3a20f8b0831a009a..a8463e1bef89de3ad632bcbdf3b1b508a616b86d 100644 (file)
@@ -36,8 +36,8 @@ class Memcache
 {
 public:
 
-  Memcache() 
-    : 
+  Memcache()
+    :
       servers_list(),
       memc(),
       servers(NULL),
@@ -59,7 +59,7 @@ public:
   }
 
   Memcache(const std::string &hostname,
-           unsigned int port)
+           in_port_t port)
     :
       servers_list(),
       memc(),
@@ -76,8 +76,8 @@ public:
     memcached_server_push(&memc, servers);
   }
 
-  Memcache(memcached_st *clone) 
-    : 
+  Memcache(memcached_st *clone)
+    :
       servers_list(),
       memc(),
       servers(NULL),
@@ -134,15 +134,27 @@ public:
   /**
    * Return an error string for the given return structure.
    *
-   * @param[in] rc a memcached_return structure
+   * @param[in] rc a memcached_return_t structure
    * @return error string corresponding to given return code in the library.
    */
-  const std::string getError(memcached_return rc) const
+  const std::string getError(memcached_return_t rc) const
   {
     /* first parameter to strerror is unused */
     return memcached_strerror(NULL, rc);
   }
 
+
+  bool setBehavior(memcached_behavior_t flag, uint64_t data)
+  {
+    memcached_return_t rc;
+    rc= memcached_behavior_set(&memc, flag, data);
+    return (rc == MEMCACHED_SUCCESS);
+  }
+
+  uint64_t getBehavior(memcached_behavior_t flag) {
+    return memcached_behavior_get(&memc, flag);
+  }
+
   /**
    * Return the string which contains the list of memcached servers being
    * used.
@@ -175,9 +187,9 @@ public:
    * @param[in] port port number of server to add
    * @return true on success; false otherwise
    */
-  bool addServer(const std::string &server_name, unsigned int port)
+  bool addServer(const std::string &server_name, in_port_t port)
   {
-    memcached_return rc;
+    memcached_return_t rc;
     std::ostringstream strstm;
     servers_list.append(",");
     servers_list.append(server_name);
@@ -199,7 +211,7 @@ public:
    * @param[in] port port number of server to remove
    * @return true on success; false otherwise
    */
-  bool removeServer(const std::string &server_name, size_t port)
+  bool removeServer(const std::string &server_name, in_port_t port)
   {
     std::string tmp_str;
     std::ostringstream strstm;
@@ -209,7 +221,7 @@ public:
     strstm << port;
     tmp_str.append(strstm.str());
     memcached_server_st *server= memcached_servers_parse(tmp_str.c_str());
-    memcached_return rc= memcached_server_remove(server);
+    memcached_return_t rc= memcached_server_remove(server);
     return (rc == MEMCACHED_SUCCESS);
   }
 
@@ -221,13 +233,13 @@ public:
    * @param[out] ret_val store returned object in this vector
    * @return a memcached return structure
    */
-  memcached_return fetch(std::string &key, 
+  memcached_return_t fetch(std::string &key,
                          std::vector<char> &ret_val)
   {
     char ret_key[MEMCACHED_MAX_KEY];
     size_t value_length= 0;
     size_t key_length= 0;
-    memcached_return rc;
+    memcached_return_t rc;
     uint32_t flags= 0;
     char *value= memcached_fetch(&memc, ret_key, &key_length,
                                  &value_length, &flags, &rc);
@@ -254,11 +266,11 @@ public:
    *                     this vector
    * @return true on success; false otherwise
    */
-  bool get(const std::string &key, 
+  bool get(const std::string &key,
            std::vector<char> &ret_val) throw (Error)
   {
     uint32_t flags= 0;
-    memcached_return rc;
+    memcached_return_t rc;
     size_t value_length= 0;
 
     if (key.empty())
@@ -280,7 +292,7 @@ public:
   /**
    * Fetches an individual from a server which is specified by
    * the master_key parameter that is used for determining which
-   * server an object was stored in if key partitioning was 
+   * server an object was stored in if key partitioning was
    * used for storage.
    *
    * @param[in] master_key key that specifies server object is stored on
@@ -289,12 +301,12 @@ public:
    *                     this vector
    * @return true on success; false otherwise
    */
-  bool getByKey(const std::string &master_key, 
-                const std::string &key, 
+  bool getByKey(const std::string &master_key,
+                const std::string &key,
                 std::vector<char> &ret_val) throw(Error)
   {
     uint32_t flags= 0;
-    memcached_return rc;
+    memcached_return_t rc;
     size_t value_length= 0;
 
     if (master_key.empty() || key.empty())
@@ -345,12 +357,12 @@ public:
     }
 
     /*
-     * If the std::vector of keys is empty then we cannot 
+     * If the std::vector of keys is empty then we cannot
      * call memcached_mget as we will get undefined behavior.
      */
     if (! real_keys.empty())
     {
-      memcached_return rc= memcached_mget(&memc, &real_keys[0], &key_len[0], 
+      memcached_return_t rc= memcached_mget(&memc, &real_keys[0], &key_len[0],
                                           real_keys.size());
       return (rc == MEMCACHED_SUCCESS);
     }
@@ -378,7 +390,7 @@ public:
     {
       throw(Error("the key or value supplied is empty!", false));
     }
-    memcached_return rc= memcached_set(&memc,
+    memcached_return_t rc= memcached_set(&memc,
                                        key.c_str(), key.length(),
                                        &value[0], value.size(),
                                        expiration, flags);
@@ -396,8 +408,8 @@ public:
    * @param[in] flags flags to store with the object
    * @return true on succcess; false otherwise
    */
-  bool setByKey(const std::string &master_key, 
-                const std::string &key, 
+  bool setByKey(const std::string &master_key,
+                const std::string &key,
                 const std::vector<char> &value,
                 time_t expiration,
                 uint32_t flags) throw(Error)
@@ -408,7 +420,7 @@ public:
     {
       throw(Error("the key or value supplied is empty!", false));
     }
-    memcached_return rc= memcached_set_by_key(&memc, master_key.c_str(), 
+    memcached_return_t rc= memcached_set_by_key(&memc, master_key.c_str(),
                                               master_key.length(),
                                               key.c_str(), key.length(),
                                               &value[0], value.size(),
@@ -502,7 +514,7 @@ public:
     {
       throw(Error("the key supplied is empty!", false));
     }
-    memcached_return rc= memcached_increment(&memc, key.c_str(), key.length(),
+    memcached_return_t rc= memcached_increment(&memc, key.c_str(), key.length(),
                                              offset, value);
     return (rc == MEMCACHED_SUCCESS);
   }
@@ -524,7 +536,7 @@ public:
     {
       throw(Error("the key supplied is empty!", false));
     }
-    memcached_return rc= memcached_decrement(&memc, key.c_str(), 
+    memcached_return_t rc= memcached_decrement(&memc, key.c_str(),
                                              key.length(),
                                              offset, value);
     return (rc == MEMCACHED_SUCCESS);
@@ -546,7 +558,7 @@ public:
     {
       throw(Error("the key or value supplied is empty!", false));
     }
-    memcached_return rc= memcached_add(&memc, key.c_str(), key.length(), 
+    memcached_return_t rc= memcached_add(&memc, key.c_str(), key.length(),
                                        &value[0], value.size(), 0, 0);
     return (rc == MEMCACHED_SUCCESS);
   }
@@ -561,22 +573,22 @@ public:
    * @param[in] value of object to add
    * @return true on success; false otherwise
    */
-  bool addByKey(const std::string &master_key, 
-                const std::string &key, 
+  bool addByKey(const std::string &master_key,
+                const std::string &key,
                 const std::vector<char> &value) throw(Error)
   {
     if (master_key.empty() ||
-        key.empty() || 
+        key.empty() ||
         value.empty())
     {
       throw(Error("the master key or key supplied is empty!", false));
     }
-    memcached_return rc= memcached_add_by_key(&memc, 
+    memcached_return_t rc= memcached_add_by_key(&memc,
                                               master_key.c_str(),
                                               master_key.length(),
                                               key.c_str(),
                                               key.length(),
-                                              &value[0], 
+                                              &value[0],
                                               value.size(),
                                               0, 0);
     return (rc == MEMCACHED_SUCCESS);
@@ -597,7 +609,7 @@ public:
     {
       throw(Error("the key or value supplied is empty!", false));
     }
-    memcached_return rc= memcached_replace(&memc, key.c_str(), key.length(),
+    memcached_return_t rc= memcached_replace(&memc, key.c_str(), key.length(),
                                            &value[0], value.size(),
                                            0, 0);
     return (rc == MEMCACHED_SUCCESS);
@@ -613,8 +625,8 @@ public:
    * @param[in[ value value to replace object with
    * @return true on success; false otherwise
    */
-  bool replaceByKey(const std::string &master_key, 
-                    const std::string &key, 
+  bool replaceByKey(const std::string &master_key,
+                    const std::string &key,
                     const std::vector<char> &value)
   {
     if (master_key.empty() ||
@@ -623,13 +635,13 @@ public:
     {
       throw(Error("the master key or key supplied is empty!", false));
     }
-    memcached_return rc= memcached_replace_by_key(&memc, 
-                                                  master_key.c_str(), 
+    memcached_return_t rc= memcached_replace_by_key(&memc,
+                                                  master_key.c_str(),
                                                   master_key.length(),
-                                                  key.c_str(), 
+                                                  key.c_str(),
                                                   key.length(),
-                                                  &value[0], 
-                                                  value.size(), 
+                                                  &value[0],
+                                                  value.size(),
                                                   0, 0);
     return (rc == MEMCACHED_SUCCESS);
   }
@@ -648,7 +660,7 @@ public:
     {
       throw(Error("the key or value supplied is empty!", false));
     }
-    memcached_return rc= memcached_prepend(&memc, key.c_str(), key.length(),
+    memcached_return_t rc= memcached_prepend(&memc, key.c_str(), key.length(),
                                            &value[0], value.size(), 0, 0);
     return (rc == MEMCACHED_SUCCESS);
   }
@@ -663,8 +675,8 @@ public:
    * @param[in] value data to prepend to object's value
    * @return true on success; false otherwise
    */
-  bool prependByKey(const std::string &master_key, 
-                    const std::string &key, 
+  bool prependByKey(const std::string &master_key,
+                    const std::string &key,
                     const std::vector<char> &value)
       throw(Error)
   {
@@ -674,7 +686,7 @@ public:
     {
       throw(Error("the master key or key supplied is empty!", false));
     }
-    memcached_return rc= memcached_prepend_by_key(&memc,
+    memcached_return_t rc= memcached_prepend_by_key(&memc,
                                                   master_key.c_str(),
                                                   master_key.length(),
                                                   key.c_str(),
@@ -700,7 +712,7 @@ public:
     {
       throw(Error("the key or value supplied is empty!", false));
     }
-    memcached_return rc= memcached_append(&memc,
+    memcached_return_t rc= memcached_append(&memc,
                                           key.c_str(),
                                           key.length(),
                                           &value[0],
@@ -730,13 +742,13 @@ public:
     {
       throw(Error("the master key or key supplied is empty!", false));
     }
-    memcached_return rc= memcached_append_by_key(&memc,
-                                                 master_key.c_str(), 
+    memcached_return_t rc= memcached_append_by_key(&memc,
+                                                 master_key.c_str(),
                                                  master_key.length(),
-                                                 key.c_str(), 
+                                                 key.c_str(),
                                                  key.length(),
-                                                 &value[0], 
-                                                 value.size(), 
+                                                 &value[0],
+                                                 value.size(),
                                                  0, 0);
     return (rc == MEMCACHED_SUCCESS);
   }
@@ -749,16 +761,16 @@ public:
    * @param[in] value value to store for object in server
    * @param[in] cas_arg "cas" value
    */
-  bool cas(const std::string &key, 
-           const std::vector<char> &value, 
+  bool cas(const std::string &key,
+           const std::vector<char> &value,
            uint64_t cas_arg) throw(Error)
   {
     if (key.empty() || value.empty())
     {
       throw(Error("the key or value supplied is empty!", false));
     }
-    memcached_return rc= memcached_cas(&memc, key.c_str(), key.length(),
-                                       &value[0], value.size(), 
+    memcached_return_t rc= memcached_cas(&memc, key.c_str(), key.length(),
+                                       &value[0], value.size(),
                                        0, 0, cas_arg);
     return (rc == MEMCACHED_SUCCESS);
   }
@@ -773,9 +785,9 @@ public:
    * @param[in] value value to store for object in server
    * @param[in] cas_arg "cas" value
    */
-  bool casByKey(const std::string &master_key, 
-                const std::string &key, 
-                const std::vector<char> &value, 
+  bool casByKey(const std::string &master_key,
+                const std::string &key,
+                const std::vector<char> &value,
                 uint64_t cas_arg) throw(Error)
   {
     if (master_key.empty() ||
@@ -784,12 +796,12 @@ public:
     {
       throw(Error("the master key, key or value supplied is empty!", false));
     }
-    memcached_return rc= memcached_cas_by_key(&memc,
-                                              master_key.c_str(), 
+    memcached_return_t rc= memcached_cas_by_key(&memc,
+                                              master_key.c_str(),
                                               master_key.length(),
-                                              key.c_str(), 
+                                              key.c_str(),
                                               key.length(),
-                                              &value[0], 
+                                              &value[0],
                                               value.size(),
                                               0, 0, cas_arg);
     return (rc == MEMCACHED_SUCCESS);
@@ -807,7 +819,7 @@ public:
     {
       throw(Error("the key supplied is empty!", false));
     }
-    memcached_return rc= memcached_delete(&memc, key.c_str(), key.length(), 0);
+    memcached_return_t rc= memcached_delete(&memc, key.c_str(), key.length(), 0);
     return (rc == MEMCACHED_SUCCESS);
   }
 
@@ -825,7 +837,7 @@ public:
     {
       throw(Error("the key supplied is empty!", false));
     }
-    memcached_return rc= memcached_delete(&memc,
+    memcached_return_t rc= memcached_delete(&memc,
                                           key.c_str(),
                                           key.length(),
                                           expiration);
@@ -833,7 +845,7 @@ public:
   }
 
   /**
-   * Delete an object from the server specified by the key given. 
+   * Delete an object from the server specified by the key given.
    *
    * @param[in] master_key specifies server to remove object from
    * @param[in] key key of object to delete
@@ -846,7 +858,7 @@ public:
     {
       throw(Error("the master key or key supplied is empty!", false));
     }
-    memcached_return rc= memcached_delete_by_key(&memc,
+    memcached_return_t rc= memcached_delete_by_key(&memc,
                                                  master_key.c_str(),
                                                  master_key.length(),
                                                  key.c_str(),
@@ -856,14 +868,14 @@ public:
   }
 
   /**
-   * Delete an object from the server specified by the key given. 
+   * Delete an object from the server specified by the key given.
    *
    * @param[in] master_key specifies server to remove object from
    * @param[in] key key of object to delete
    * @param[in] expiration time to delete the object after
    * @return true on success; false otherwise
    */
-  bool removeByKey(const std::string &master_key, 
+  bool removeByKey(const std::string &master_key,
                    const std::string &key,
                    time_t expiration) throw(Error)
   {
@@ -871,11 +883,11 @@ public:
     {
       throw(Error("the master key or key supplied is empty!", false));
     }
-    memcached_return rc= memcached_delete_by_key(&memc, 
-                                                 master_key.c_str(), 
+    memcached_return_t rc= memcached_delete_by_key(&memc,
+                                                 master_key.c_str(),
                                                  master_key.length(),
-                                                 key.c_str(), 
-                                                 key.length(), 
+                                                 key.c_str(),
+                                                 key.length(),
                                                  expiration);
     return (rc == MEMCACHED_SUCCESS);
   }
@@ -889,7 +901,7 @@ public:
    */
   bool flush(time_t expiration)
   {
-    memcached_return rc= memcached_flush(&memc, expiration);
+    memcached_return_t rc= memcached_flush(&memc, expiration);
     return (rc == MEMCACHED_SUCCESS);
   }
 
@@ -903,11 +915,11 @@ public:
    * @param[in] num_of_callbacks number of callback functions
    * @return true on success; false otherwise
    */
-  bool fetchExecute(memcached_execute_function *callback,
+  bool fetchExecute(memcached_execute_fn *callback,
                     void *context,
-                    unsigned int num_of_callbacks)
+                    uint32_t num_of_callbacks)
   {
-    memcached_return rc= memcached_fetch_execute(&memc,
+    memcached_return_t rc= memcached_fetch_execute(&memc,
                                                  callback,
                                                  context,
                                                  num_of_callbacks);
@@ -936,7 +948,7 @@ public:
   bool getStats(std::map< std::string, std::map<std::string, std::string> >
                 &stats_map)
   {
-    memcached_return rc;
+    memcached_return_t rc;
     memcached_stat_st *stats= memcached_stat(&memc, NULL, &rc);
 
     if (rc != MEMCACHED_SUCCESS &&
@@ -970,7 +982,7 @@ public:
         server_stats[*ptr]= value;
         free(value);
       }
-      
+     
       stats_map[server_name]= server_stats;
       free(list);
     }
index b28094062bc24815cfb965f4f51ca30b0f4032c9..e5226b5bf467f0821e2ad874b6acfe49b588dcf1 100644 (file)
@@ -29,7 +29,7 @@
  *
  * Copy: See Copyright for the status of this software.
  *
- * Author: Trond Norbye <trond.norbye@sun.com>
+ * Author: Trond Norbye <trond.norbye@gmail.com>
  */
 
 #ifndef PROTOCOL_BINARY_H
diff --git a/libmemcached/memcached_allocators.c b/libmemcached/memcached_allocators.c
deleted file mode 100644 (file)
index bf57e35..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-#include "common.h"
-
-void libmemcached_free(memcached_st *ptr, void *mem)
-{
-  (void) ptr;
-  free(mem);
-}
-
-void *libmemcached_malloc(memcached_st *ptr, size_t size)
-{
-  (void) ptr;
-  return malloc(size);
-}
-
-void *libmemcached_realloc(memcached_st *ptr, void *mem, size_t size)
-{
-  (void) ptr;
-  return realloc(mem, size);
-}
-
-void *libmemcached_calloc(memcached_st *ptr, size_t nelem, size_t size)
-{
-  if (ptr->call_malloc != libmemcached_malloc)
-  {
-     void *ret = libmemcached_malloc(ptr, nelem * size);
-     if (ret != NULL) 
-       memset(ret, 0, nelem * size);
-
-     return ret;
-  }
-
-  return calloc(nelem, size);
-}
-
-memcached_return memcached_set_memory_allocators(memcached_st *ptr,
-                                                 memcached_malloc_function mem_malloc,
-                                                 memcached_free_function mem_free,
-                                                 memcached_realloc_function mem_realloc,
-                                                 memcached_calloc_function mem_calloc)
-{
-  /* All should be set, or none should be set */
-  if (mem_malloc == NULL && mem_free == NULL && mem_realloc == NULL && mem_calloc == NULL) 
-  {
-    ptr->call_malloc= libmemcached_malloc;
-    ptr->call_free= libmemcached_free;
-    ptr->call_realloc= libmemcached_realloc;
-    ptr->call_calloc= libmemcached_calloc;
-  }
-  else if (mem_malloc == NULL || mem_free == NULL || mem_realloc == NULL || mem_calloc == NULL)
-    return MEMCACHED_FAILURE;
-  else
-  {
-    ptr->call_malloc= mem_malloc;
-    ptr->call_free= mem_free;
-    ptr->call_realloc= mem_realloc;
-    ptr->call_calloc= mem_calloc;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-void memcached_get_memory_allocators(memcached_st *ptr,
-                                     memcached_malloc_function *mem_malloc,
-                                     memcached_free_function *mem_free,
-                                     memcached_realloc_function *mem_realloc,
-                                     memcached_calloc_function *mem_calloc)
-{
-   *mem_malloc= ptr->call_malloc;
-   *mem_free= ptr->call_free;
-   *mem_realloc= ptr->call_realloc;
-   *mem_calloc= ptr->call_calloc;
-}
diff --git a/libmemcached/memcached_analyze.c b/libmemcached/memcached_analyze.c
deleted file mode 100644 (file)
index 61cea33..0000000
+++ /dev/null
@@ -1,100 +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 *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(memc->number_of_hosts,
-                                         sizeof(memcached_analysis_st));
-
-  if (!result)
-  {
-    *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-    return NULL;
-  }
-
-  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;
-}
diff --git a/libmemcached/memcached_auto.c b/libmemcached/memcached_auto.c
deleted file mode 100644 (file)
index 207c4e5..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-#include "common.h"
-
-static memcached_return memcached_auto(memcached_st *ptr,
-                                       const char *verb,
-                                       const char *master_key, size_t master_key_length,
-                                       const char *key, size_t key_length,
-                                       uint64_t offset,
-                                       uint64_t *value)
-{
-  size_t send_length;
-  memcached_return rc;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  unsigned int server_key;
-  bool no_reply= (ptr->flags & MEM_NOREPLY);
-
-  unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
-    return MEMCACHED_NO_SERVERS;
-
-  if ((ptr->flags & MEM_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(ptr, master_key, master_key_length);
-
-  send_length= (size_t)snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                                "%s %s%.*s %" PRIu64 "%s\r\n", verb,
-                                ptr->prefix_key,
-                                (int)key_length, key,
-                                offset, no_reply ? " noreply" : "");
-  unlikely (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
-    return MEMCACHED_WRITE_FAILURE;
-
-  rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, 1);
-  if (no_reply || rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  rc= memcached_response(&ptr->hosts[server_key], 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, "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 binary_incr_decr(memcached_st *ptr, uint8_t cmd,
-                                         const char *master_key, size_t master_key_length,
-                                         const char *key, size_t key_length,
-                                         uint64_t offset, uint64_t initial,
-                                         uint32_t expiration,
-                                         uint64_t *value)
-{
-  unsigned int server_key;
-  bool no_reply= (ptr->flags & MEM_NOREPLY);
-
-  unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
-    return MEMCACHED_NO_SERVERS;
-
-  server_key= memcached_generate_hash(ptr, master_key, master_key_length);
-
-  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);
-  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 + 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);
-
-  if ((memcached_do(&ptr->hosts[server_key], request.bytes,
-                    sizeof(request.bytes), 0)!=MEMCACHED_SUCCESS) ||
-      (memcached_io_write(&ptr->hosts[server_key], key, key_length, 1) == -1))
-  {
-    memcached_io_reset(&ptr->hosts[server_key]);
-    return MEMCACHED_WRITE_FAILURE;
-  }
-
-  if (no_reply)
-    return MEMCACHED_SUCCESS;
-  return memcached_response(&ptr->hosts[server_key], (char*)value, sizeof(*value), NULL);
-}
-
-memcached_return memcached_increment(memcached_st *ptr,
-                                     const char *key, size_t key_length,
-                                     uint32_t offset,
-                                     uint64_t *value)
-{
-  return memcached_increment_by_key(ptr, key, key_length, key, key_length, offset, value);
-}
-
-memcached_return memcached_decrement(memcached_st *ptr,
-                                     const char *key, size_t key_length,
-                                     uint32_t offset,
-                                     uint64_t *value)
-{
-  return memcached_decrement_by_key(ptr, key, key_length, key, key_length, offset, value);
-}
-
-memcached_return memcached_increment_by_key(memcached_st *ptr,
-                                            const char *master_key, size_t master_key_length,
-                                            const char *key, size_t key_length,
-                                            uint64_t offset,
-                                            uint64_t *value)
-{
-  memcached_return rc= memcached_validate_key_length(key_length, ptr->flags & MEM_BINARY_PROTOCOL);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  LIBMEMCACHED_MEMCACHED_INCREMENT_START();
-  if (ptr->flags & MEM_BINARY_PROTOCOL)
-    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
-                         master_key, master_key_length, key, key_length,
-                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
-                         value);
-  else
-     rc= memcached_auto(ptr, "incr", master_key, master_key_length, key, key_length, offset, value);
-
-  LIBMEMCACHED_MEMCACHED_INCREMENT_END();
-
-  return rc;
-}
-
-memcached_return memcached_decrement_by_key(memcached_st *ptr,
-                                            const char *master_key, size_t master_key_length,
-                                            const char *key, size_t key_length,
-                                            uint64_t offset,
-                                            uint64_t *value)
-{
-  memcached_return rc= memcached_validate_key_length(key_length, ptr->flags & MEM_BINARY_PROTOCOL);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  LIBMEMCACHED_MEMCACHED_DECREMENT_START();
-  if (ptr->flags & MEM_BINARY_PROTOCOL)
-    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
-                         master_key, master_key_length, key, key_length,
-                         (uint64_t)offset, 0, MEMCACHED_EXPIRATION_NOT_ADD,
-                         value);
-  else
-    rc= memcached_auto(ptr, "decr", master_key, master_key_length, key, key_length, offset, value);
-
-  LIBMEMCACHED_MEMCACHED_DECREMENT_END();
-
-  return rc;
-}
-
-memcached_return 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)
-{
-  return memcached_increment_with_initial_by_key(ptr, key, key_length,
-                                                 key, key_length,
-                                                 offset, initial, expiration, value);
-}
-
-memcached_return memcached_increment_with_initial_by_key(memcached_st *ptr,
-                                                         const char *master_key,
-                                                         size_t master_key_length,
-                                                         const char *key,
-                                                         size_t key_length,
-                                                         uint64_t offset,
-                                                         uint64_t initial,
-                                                         time_t expiration,
-                                                         uint64_t *value)
-{
-  memcached_return rc= memcached_validate_key_length(key_length, ptr->flags & MEM_BINARY_PROTOCOL);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
-  if (ptr->flags & MEM_BINARY_PROTOCOL)
-    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_INCREMENT,
-                         master_key, master_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 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)
-{
-  return memcached_decrement_with_initial_by_key(ptr, key, key_length,
-                                                 key, key_length,
-                                                 offset, initial, expiration, value);
-}
-
-memcached_return memcached_decrement_with_initial_by_key(memcached_st *ptr,
-                                                         const char *master_key,
-                                                         size_t master_key_length,
-                                                         const char *key,
-                                                         size_t key_length,
-                                                         uint64_t offset,
-                                                         uint64_t initial,
-                                                         time_t expiration,
-                                                         uint64_t *value)
-{
-  memcached_return rc= memcached_validate_key_length(key_length, ptr->flags & MEM_BINARY_PROTOCOL);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  LIBMEMCACHED_MEMCACHED_INCREMENT_WITH_INITIAL_START();
-  if (ptr->flags & MEM_BINARY_PROTOCOL)
-    rc= binary_incr_decr(ptr, PROTOCOL_BINARY_CMD_DECREMENT,
-                         master_key, master_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/memcached_behavior.c b/libmemcached/memcached_behavior.c
deleted file mode 100644 (file)
index 72b0d5c..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-#include "common.h"
-#include <time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/tcp.h>
-
-/*
-  This function is used to modify the behavior of running client.
-
-  We quit all connections so we can reset the sockets.
-*/
-
-static void set_behavior_flag(memcached_st *ptr, memcached_flags temp_flag, uint64_t data)
-{
-  if (data)
-    ptr->flags|= temp_flag;
-  else
-    ptr->flags&= ~temp_flag;
-}
-
-memcached_return memcached_behavior_set(memcached_st *ptr,
-                                        memcached_behavior 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_SERVER_FAILURE_LIMIT:
-    ptr->server_failure_limit= (uint32_t)data;
-    break;
-  case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
-    if (data)
-        set_behavior_flag(ptr, MEM_VERIFY_KEY, 0);
-    set_behavior_flag(ptr, MEM_BINARY_PROTOCOL, data);
-    break;
-  case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
-    set_behavior_flag(ptr, MEM_SUPPORT_CAS, data);
-    break;
-  case MEMCACHED_BEHAVIOR_NO_BLOCK:
-    set_behavior_flag(ptr, MEM_NO_BLOCK, data);
-    memcached_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
-    set_behavior_flag(ptr, MEM_BUFFER_REQUESTS, data);
-    memcached_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_USE_UDP:
-    if (ptr->number_of_hosts)
-      return MEMCACHED_FAILURE;
-    set_behavior_flag(ptr, MEM_USE_UDP, data);
-    if (data)
-      set_behavior_flag(ptr,MEM_NOREPLY,data);
-    break;
-  case MEMCACHED_BEHAVIOR_TCP_NODELAY:
-    set_behavior_flag(ptr, MEM_TCP_NODELAY, data);
-    memcached_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_DISTRIBUTION:
-    {
-      ptr->distribution= (memcached_server_distribution)(data);
-      if (ptr->distribution == MEMCACHED_DISTRIBUTION_RANDOM)
-      {
-        srandom((uint32_t) time(NULL));
-      }
-      run_distribution(ptr);
-      break;
-    }
-  case MEMCACHED_BEHAVIOR_KETAMA:
-    {
-      if (data)
-      {
-        ptr->hash= MEMCACHED_HASH_MD5;
-        ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA;
-      }
-      else
-      {
-        ptr->hash= 0;
-        ptr->distribution= 0;
-      }
-      run_distribution(ptr);
-      break;
-    }
-  case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
-    {
-      ptr->hash= MEMCACHED_HASH_MD5;
-      ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA;
-      set_behavior_flag(ptr, MEM_KETAMA_WEIGHTED, data);
-      run_distribution(ptr);
-      break;
-    }
-  case MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE:
-    switch (data)
-    {
-    case MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED:
-      ptr->hash= MEMCACHED_HASH_MD5;
-      ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA;
-      break;
-    case MEMCACHED_KETAMA_COMPAT_SPY:
-      ptr->hash= MEMCACHED_HASH_MD5;
-      ptr->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY;
-      break;
-    default:
-       return MEMCACHED_FAILURE;
-    }
-    run_distribution(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_HASH:
-#ifndef HAVE_HSIEH_HASH
-    if ((memcached_hash)(data) == MEMCACHED_HASH_HSIEH)
-      return MEMCACHED_FAILURE;
-#endif
-    ptr->hash= (memcached_hash)(data);
-    break;
-  case MEMCACHED_BEHAVIOR_KETAMA_HASH:
-    ptr->hash_continuum= (memcached_hash)(data);
-    run_distribution(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
-    set_behavior_flag(ptr, MEM_USE_CACHE_LOOKUPS, data);
-    memcached_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_VERIFY_KEY:
-    if (ptr->flags & MEM_BINARY_PROTOCOL)
-        break;
-    set_behavior_flag(ptr, MEM_VERIFY_KEY, data);
-    break;
-  case MEMCACHED_BEHAVIOR_SORT_HOSTS:
-    {
-      set_behavior_flag(ptr, MEM_USE_SORT_HOSTS, 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;
-    memcached_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
-    ptr->recv_size= (int32_t)data;
-    memcached_quit(ptr);
-    break;
-  case MEMCACHED_BEHAVIOR_USER_DATA:
-    return MEMCACHED_FAILURE;
-  case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
-    set_behavior_flag(ptr, MEM_HASH_WITH_PREFIX_KEY, data);
-    break;
-  case MEMCACHED_BEHAVIOR_NOREPLY:
-    set_behavior_flag(ptr, MEM_NOREPLY, data);
-    break;
-  case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
-    set_behavior_flag(ptr, MEM_AUTO_EJECT_HOSTS, data);
-    break;
-  default:
-    /* Shouldn't get here */
-    WATCHPOINT_ASSERT(flag);
-    break;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-uint64_t memcached_behavior_get(memcached_st *ptr,
-                                memcached_behavior flag)
-{
-  memcached_flags temp_flag= MEM_NO_BLOCK;
-
-  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:
-    temp_flag= MEM_BINARY_PROTOCOL;
-    break;
-  case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
-    temp_flag= MEM_SUPPORT_CAS;
-    break;
-  case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
-    temp_flag= MEM_USE_CACHE_LOOKUPS;
-    break;
-  case MEMCACHED_BEHAVIOR_NO_BLOCK:
-    temp_flag= MEM_NO_BLOCK;
-    break;
-  case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
-    temp_flag= MEM_BUFFER_REQUESTS;
-    break;
-  case MEMCACHED_BEHAVIOR_USE_UDP:
-    temp_flag= MEM_USE_UDP;
-    break;
-  case MEMCACHED_BEHAVIOR_TCP_NODELAY:
-    temp_flag= MEM_TCP_NODELAY;
-    break;
-  case MEMCACHED_BEHAVIOR_VERIFY_KEY:
-    temp_flag= MEM_VERIFY_KEY;
-    break;
-  case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
-    temp_flag= MEM_KETAMA_WEIGHTED;
-    break;
-  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_KETAMA_COMPAT_MODE:
-    switch (ptr->distribution)
-    {
-    case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
-      return MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED;
-    case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
-      return MEMCACHED_KETAMA_COMPAT_SPY;
-    default:
-      return (uint64_t)-1;
-    }
-    /* NOTREACHED */
-  case MEMCACHED_BEHAVIOR_HASH:
-    return ptr->hash;
-  case MEMCACHED_BEHAVIOR_KETAMA_HASH:
-    return ptr->hash_continuum;
-  case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
-    return ptr->server_failure_limit;
-  case MEMCACHED_BEHAVIOR_SORT_HOSTS:
-    temp_flag= MEM_USE_SORT_HOSTS;
-    break;
-  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_SOCKET_SEND_SIZE:
-    {
-      int sock_size;
-      socklen_t sock_length= sizeof(int);
-
-      /* REFACTOR */
-      /* We just try the first host, and if it is down we return zero */
-      if ((memcached_connect(&ptr->hosts[0])) != MEMCACHED_SUCCESS)
-        return 0;
-
-      if (getsockopt(ptr->hosts[0].fd, SOL_SOCKET,
-                     SO_SNDBUF, &sock_size, &sock_length))
-        return 0; /* Zero means error */
-
-      return (uint64_t) sock_size;
-    }
-  case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
-    {
-      int sock_size;
-      socklen_t sock_length= sizeof(int);
-
-      /* REFACTOR */
-      /* We just try the first host, and if it is down we return zero */
-      if ((memcached_connect(&ptr->hosts[0])) != MEMCACHED_SUCCESS)
-        return 0;
-
-      if (getsockopt(ptr->hosts[0].fd, SOL_SOCKET,
-                     SO_RCVBUF, &sock_size, &sock_length))
-        return 0; /* Zero means error */
-
-      return (uint64_t) sock_size;
-    }
-  case MEMCACHED_BEHAVIOR_USER_DATA:
-    return MEMCACHED_FAILURE;
-  case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
-    temp_flag= MEM_HASH_WITH_PREFIX_KEY;
-    break;
-  case MEMCACHED_BEHAVIOR_NOREPLY:
-    temp_flag= MEM_NOREPLY;
-    break;
-  case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
-    temp_flag= MEM_AUTO_EJECT_HOSTS;
-    break;
-  default:
-    WATCHPOINT_ASSERT(flag);
-    break;
-  }
-
-  WATCHPOINT_ASSERT(temp_flag); /* Programming mistake if it gets this far */
-  if (ptr->flags & temp_flag)
-    return 1;
-  else
-    return 0;
-}
diff --git a/libmemcached/memcached_callback.c b/libmemcached/memcached_callback.c
deleted file mode 100644 (file)
index ea59f84..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-#include "common.h" 
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/tcp.h>
-
-/* 
-  These functions provide data and function callback support
-*/
-
-memcached_return memcached_callback_set(memcached_st *ptr, 
-                                        memcached_callback flag, 
-                                        void *data)
-{
-  switch (flag)
-  {
-  case MEMCACHED_CALLBACK_PREFIX_KEY:
-    {
-      char *key= (char *)data;
-
-      if (key)
-      {
-        size_t key_length= strlen(key);
-
-        if (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED)
-        {
-          return MEMCACHED_BAD_KEY_PROVIDED;
-        }
-
-        if ((key_length > MEMCACHED_PREFIX_KEY_MAX_SIZE -1)
-            || (strcpy(ptr->prefix_key, key) == NULL))
-        {
-          ptr->prefix_key_length= 0;
-          return MEMCACHED_BAD_KEY_PROVIDED;
-        }
-        else
-        {
-          ptr->prefix_key_length= key_length;
-        }
-      }
-      else
-      {
-        memset(ptr->prefix_key, 0, MEMCACHED_PREFIX_KEY_MAX_SIZE);
-        ptr->prefix_key_length= 0;
-      }
-
-      break;
-    }
-  case MEMCACHED_CALLBACK_USER_DATA:
-    {
-      ptr->user_data= data;
-      break;
-    }
-  case MEMCACHED_CALLBACK_CLEANUP_FUNCTION:
-    {
-      memcached_cleanup_func func= *(memcached_cleanup_func *)&data;
-      ptr->on_cleanup= func;
-      break;
-    }
-  case MEMCACHED_CALLBACK_CLONE_FUNCTION:
-    {
-      memcached_clone_func func= *(memcached_clone_func *)&data;
-      ptr->on_clone= func;
-      break;
-    }
-#ifdef MEMCACHED_ENABLE_DEPRECATED
-  case MEMCACHED_CALLBACK_MALLOC_FUNCTION:
-    {
-      memcached_malloc_function func= *(memcached_malloc_function *)&data;
-      ptr->call_malloc= func;
-      break;
-    }
-  case MEMCACHED_CALLBACK_REALLOC_FUNCTION:
-    {
-      memcached_realloc_function func= *(memcached_realloc_function *)&data;
-      ptr->call_realloc= func;
-      break;
-    }
-  case MEMCACHED_CALLBACK_FREE_FUNCTION:
-    {
-      memcached_free_function func= *(memcached_free_function *)&data;
-      ptr->call_free= func;
-      break;
-    }
-#endif
-  case MEMCACHED_CALLBACK_GET_FAILURE:
-    {
-      memcached_trigger_key func= *(memcached_trigger_key *)&data;
-      ptr->get_key_failure= func;
-      break;
-    }
-  case MEMCACHED_CALLBACK_DELETE_TRIGGER:
-    {
-      memcached_trigger_delete_key func= *(memcached_trigger_delete_key *)&data;
-      ptr->delete_trigger= func;
-      break;
-    }
-  default:
-    return MEMCACHED_FAILURE;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-void *memcached_callback_get(memcached_st *ptr, 
-                             memcached_callback flag,
-                             memcached_return *error)
-{
-  memcached_return local_error;
-
-  if (!error)
-    error = &local_error;
-
-  switch (flag)
-  {
-  case MEMCACHED_CALLBACK_PREFIX_KEY:
-    {
-      if (ptr->prefix_key[0] == 0)
-      {
-        *error= MEMCACHED_FAILURE;
-        return NULL;
-      }
-      else
-      {
-        *error= MEMCACHED_SUCCESS;
-        return (void *)ptr->prefix_key;
-      }
-    }
-  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;
-    }
-  default:
-      WATCHPOINT_ASSERT(0);
-      *error= MEMCACHED_FAILURE;
-      return NULL;
-  }
-}
diff --git a/libmemcached/memcached_configure.h.in b/libmemcached/memcached_configure.h.in
deleted file mode 100644 (file)
index d3af270..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Summary: Preprocessor symbols set from configure we need install-time
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Trond Norbye
- */
-
-#ifndef MEMCACHED_CONFIGURE_H
-#define MEMCACHED_CONFIGURE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-@DEPRECATED@
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* MEMCACHED_CONFIGURE_H */
diff --git a/libmemcached/memcached_connect.c b/libmemcached/memcached_connect.c
deleted file mode 100644 (file)
index f3ee148..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-#include "common.h"
-#include <netdb.h>
-#include <poll.h>
-#include <sys/time.h>
-
-static memcached_return set_hostinfo(memcached_server_st *server)
-{
-  struct addrinfo *ai;
-  struct addrinfo hints;
-  int e;
-  char str_port[NI_MAXSERV];
-
-  sprintf(str_port, "%u", server->port);
-
-  memset(&hints, 0, sizeof(hints));
-
- // hints.ai_family= AF_INET;
-  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;
-  }
-
-  e= getaddrinfo(server->hostname, str_port, &hints, &ai);
-  if (e != 0)
-  {
-    WATCHPOINT_STRING(server->hostname);
-    WATCHPOINT_STRING(gai_strerror(e));
-    return MEMCACHED_HOST_LOOKUP_FAILURE;
-  }
-
-  if (server->address_info)
-  {
-    freeaddrinfo(server->address_info);
-    server->address_info= NULL;
-  }
-  server->address_info= ai;
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return 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);
-  }
-#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);
-  }
-#endif
-
-  if (ptr->root->flags & MEM_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 (ptr->root->flags & MEM_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 (ptr->root->send_size)
-  {
-    int error;
-
-    error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF,
-                      &ptr->root->send_size, (socklen_t)sizeof(int));
-    WATCHPOINT_ASSERT(error == 0);
-  }
-
-  if (ptr->root->recv_size)
-  {
-    int error;
-
-    error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVBUF,
-                      &ptr->root->recv_size, (socklen_t)sizeof(int));
-    WATCHPOINT_ASSERT(error == 0);
-  }
-
-  /* libmemcached will always use nonblocking IO to avoid write deadlocks */
-  int flags;
-
-  do
-    flags= fcntl(ptr->fd, F_GETFL, 0);
-  while (flags == -1 && (errno == EINTR || errno == EAGAIN));
-
-  unlikely (flags == -1)
-    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)
-      return MEMCACHED_CONNECTION_FAILURE;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return unix_socket_connect(memcached_server_st *ptr)
-{
-  struct sockaddr_un servAddr;
-  socklen_t addrlen;
-
-  if (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;
-    strcpy(servAddr.sun_path, ptr->hostname); /* Copy filename */
-
-    addrlen= (socklen_t) (strlen(servAddr.sun_path) + sizeof(servAddr.sun_family));
-
-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;
-}
-
-static memcached_return network_connect(memcached_server_st *ptr)
-{
-  if (ptr->fd == -1)
-  {
-    struct addrinfo *use;
-
-    if (!ptr->sockaddr_inited ||
-        (!(ptr->root->flags & MEM_USE_CACHE_LOOKUPS)))
-    {
-      memcached_return rc;
-
-      rc= set_hostinfo(ptr);
-      if (rc != MEMCACHED_SUCCESS)
-        return rc;
-      ptr->sockaddr_inited= true;
-    }
-
-    use= ptr->address_info;
-    /* Create the socket */
-    while (use != NULL)
-    {
-      /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
-      if (ptr->type == MEMCACHED_CONNECTION_UDP && use->ai_family != AF_INET)
-      {
-        use= use->ai_next;
-        continue;
-      }
-
-      if ((ptr->fd= socket(use->ai_family,
-                           use->ai_socktype,
-                           use->ai_protocol)) < 0)
-      {
-        ptr->cached_errno= errno;
-        WATCHPOINT_ERRNO(errno);
-        return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
-      }
-
-      (void)set_socket_options(ptr);
-
-      /* connect to server */
-      while (ptr->fd != -1 &&
-             connect(ptr->fd, use->ai_addr, use->ai_addrlen) < 0)
-      {
-        ptr->cached_errno= errno;
-        if (errno == EINPROGRESS || /* nonblocking mode - first return, */
-            errno == EALREADY) /* nonblocking mode - subsequent returns */
-        {
-          struct pollfd fds[1];
-          fds[0].fd = ptr->fd;
-          fds[0].events = POLLOUT;
-          int error= poll(fds, 1, ptr->root->connect_timeout);
-
-          if (error != 1 || fds[0].revents & POLLERR)
-          {
-            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) ? errno : err;
-            }
-
-            (void)close(ptr->fd);
-            ptr->fd= -1;
-          }
-        }
-        else if (errno == EISCONN) /* we are connected :-) */
-        {
-          break;
-        }
-        else if (errno != EINTR)
-        {
-          (void)close(ptr->fd);
-          ptr->fd= -1;
-          break;
-        }
-      }
-
-      if (ptr->fd != -1)
-      {
-        WATCHPOINT_ASSERT(ptr->cursor_active == 0);
-        ptr->server_failure_counter= 0;
-        return MEMCACHED_SUCCESS;
-      }
-      use = use->ai_next;
-    }
-  }
-
-  if (ptr->fd == -1)
-  {
-    /* 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;
-    }
-    ptr->server_failure_counter++;
-    if (ptr->cached_errno == 0)
-      return MEMCACHED_TIMEOUT;
-
-    return MEMCACHED_ERRNO; /* The last error should be from connect() */
-  }
-
-  ptr->server_failure_counter= 0;
-  return MEMCACHED_SUCCESS; /* The last error should be from connect() */
-}
-
-
-memcached_return memcached_connect(memcached_server_st *ptr)
-{
-  memcached_return rc= MEMCACHED_NO_SERVERS;
-  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->root->server_failure_limit)
-  {
-    struct timeval curr_time;
-
-    gettimeofday(&curr_time, NULL);
-
-    /* if we've had too many consecutive errors on this server, mark it dead. */
-    if (ptr->server_failure_counter >= ptr->root->server_failure_limit)
-    {
-      ptr->next_retry= curr_time.tv_sec + ptr->root->retry_timeout;
-      ptr->server_failure_counter= 0;
-    }
-
-    if (curr_time.tv_sec < ptr->next_retry)
-    {
-      if (memcached_behavior_get(ptr->root, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS))
-        run_distribution(ptr->root);
-
-      ptr->root->last_disconnected_server = ptr;
-      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);
-    break;
-  case MEMCACHED_CONNECTION_UNIX_SOCKET:
-    rc= unix_socket_connect(ptr);
-    break;
-  default:
-    WATCHPOINT_ASSERT(0);
-  }
-
-  unlikely ( rc != MEMCACHED_SUCCESS) ptr->root->last_disconnected_server = ptr;
-
-  LIBMEMCACHED_MEMCACHED_CONNECT_END();
-
-  return rc;
-}
diff --git a/libmemcached/memcached_constants.h b/libmemcached/memcached_constants.h
deleted file mode 100644 (file)
index 7399d6c..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Summary: Constants for libmemcached
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Brian Aker
- */
-
-#ifndef __MEMCACHED_CONSTANTS_H__
-#define __MEMCACHED_CONSTANTS_H__
-
-/* Public defines */
-#define MEMCACHED_DEFAULT_PORT 11211
-#define MEMCACHED_MAX_KEY 251 /* We add one to have it null terminated */
-#define MEMCACHED_MAX_BUFFER 8196
-#define MEMCACHED_MAX_HOST_LENGTH 64
-#define MEMCACHED_MAX_HOST_SORT_LENGTH 86 /* Used for Ketama */
-#define MEMCACHED_POINTS_PER_SERVER 100
-#define MEMCACHED_POINTS_PER_SERVER_KETAMA 160
-#define MEMCACHED_CONTINUUM_SIZE MEMCACHED_POINTS_PER_SERVER*100 /* This would then set max hosts to 100 */
-#define MEMCACHED_STRIDE 4
-#define MEMCACHED_DEFAULT_TIMEOUT 1000
-#define MEMCACHED_CONTINUUM_ADDITION 10 /* How many extra slots we should build for in the continuum */
-#define MEMCACHED_PREFIX_KEY_MAX_SIZE 128
-#define MEMCACHED_EXPIRATION_NOT_ADD 0xffffffffU
-
-typedef enum {
-  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_MAXIMUM_RETURN /* Always add new error code before */
-} memcached_return;
-
-typedef enum {
-  MEMCACHED_DISTRIBUTION_MODULA,
-  MEMCACHED_DISTRIBUTION_CONSISTENT,
-  MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA,
-  MEMCACHED_DISTRIBUTION_RANDOM,
-  MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY
-} memcached_server_distribution;
-
-typedef enum {
-  MEMCACHED_BEHAVIOR_NO_BLOCK,
-  MEMCACHED_BEHAVIOR_TCP_NODELAY,
-  MEMCACHED_BEHAVIOR_HASH,
-  MEMCACHED_BEHAVIOR_KETAMA,
-  MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE,
-  MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE,
-  MEMCACHED_BEHAVIOR_CACHE_LOOKUPS,
-  MEMCACHED_BEHAVIOR_SUPPORT_CAS,
-  MEMCACHED_BEHAVIOR_POLL_TIMEOUT,
-  MEMCACHED_BEHAVIOR_DISTRIBUTION,
-  MEMCACHED_BEHAVIOR_BUFFER_REQUESTS,
-  MEMCACHED_BEHAVIOR_USER_DATA,
-  MEMCACHED_BEHAVIOR_SORT_HOSTS,
-  MEMCACHED_BEHAVIOR_VERIFY_KEY,
-  MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT,
-  MEMCACHED_BEHAVIOR_RETRY_TIMEOUT,
-  MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED,
-  MEMCACHED_BEHAVIOR_KETAMA_HASH,
-  MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
-  MEMCACHED_BEHAVIOR_SND_TIMEOUT,
-  MEMCACHED_BEHAVIOR_RCV_TIMEOUT,
-  MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT,
-  MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK,
-  MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK,
-  MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH,
-  MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY,
-  MEMCACHED_BEHAVIOR_NOREPLY,
-  MEMCACHED_BEHAVIOR_USE_UDP,
-  MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS,
-  MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS,
-  MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE
-} memcached_behavior;
-
-#define MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED 0
-#define MEMCACHED_KETAMA_COMPAT_SPY 1
-
-typedef enum {
-  MEMCACHED_CALLBACK_PREFIX_KEY = 0,
-  MEMCACHED_CALLBACK_USER_DATA = 1,
-  MEMCACHED_CALLBACK_CLEANUP_FUNCTION = 2,
-  MEMCACHED_CALLBACK_CLONE_FUNCTION = 3,
-#ifdef MEMCACHED_ENABLE_DEPRECATED
-  MEMCACHED_CALLBACK_MALLOC_FUNCTION = 4,
-  MEMCACHED_CALLBACK_REALLOC_FUNCTION = 5,
-  MEMCACHED_CALLBACK_FREE_FUNCTION = 6,
-#endif
-  MEMCACHED_CALLBACK_GET_FAILURE = 7,
-  MEMCACHED_CALLBACK_DELETE_TRIGGER = 8
-} memcached_callback;
-
-typedef enum {
-  MEMCACHED_HASH_DEFAULT= 0,
-  MEMCACHED_HASH_MD5,
-  MEMCACHED_HASH_CRC,
-  MEMCACHED_HASH_FNV1_64,
-  MEMCACHED_HASH_FNV1A_64,
-  MEMCACHED_HASH_FNV1_32,
-  MEMCACHED_HASH_FNV1A_32,
-  MEMCACHED_HASH_HSIEH,
-  MEMCACHED_HASH_MURMUR,
-  MEMCACHED_HASH_JENKINS
-} memcached_hash;
-
-typedef enum {
-  MEMCACHED_CONNECTION_UNKNOWN,
-  MEMCACHED_CONNECTION_TCP,
-  MEMCACHED_CONNECTION_UDP,
-  MEMCACHED_CONNECTION_UNIX_SOCKET
-} memcached_connection;
-
-#endif /* __MEMCACHED_CONSTANTS_H__ */
diff --git a/libmemcached/memcached_delete.c b/libmemcached/memcached_delete.c
deleted file mode 100644 (file)
index bba3c19..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-#include "common.h"
-#include "memcached/protocol_binary.h"
-
-memcached_return 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 binary_delete(memcached_st *ptr,
-                                             unsigned int server_key,
-                                             const char *key,
-                                             size_t key_length,
-                                            uint8_t flush);
-
-memcached_return memcached_delete_by_key(memcached_st *ptr,
-                                         const char *master_key, size_t master_key_length,
-                                         const char *key, size_t key_length,
-                                         time_t expiration)
-{
-  uint8_t to_write;
-  size_t send_length;
-  memcached_return rc;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  unsigned int server_key;
-
-  LIBMEMCACHED_MEMCACHED_DELETE_START();
-
-  rc= memcached_validate_key_length(key_length,
-                                    ptr->flags & MEM_BINARY_PROTOCOL);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  unlikely (ptr->hosts == NULL || ptr->number_of_hosts == 0)
-    return MEMCACHED_NO_SERVERS;
-
-  server_key= memcached_generate_hash(ptr, master_key, master_key_length);
-  to_write= (uint8_t)((ptr->flags & MEM_BUFFER_REQUESTS) ? 0 : 1);
-  bool no_reply= (ptr->flags & MEM_NOREPLY);
-
-  if (ptr->flags & MEM_BINARY_PROTOCOL)
-  {
-    likely (!expiration)
-      rc= binary_delete(ptr, server_key, key, key_length, to_write);
-    else
-      rc= MEMCACHED_INVALID_ARGUMENTS;
-  }
-  else
-  {
-    unlikely (expiration)
-    {
-       if ((ptr->hosts[server_key].major_version == 1 &&
-            ptr->hosts[server_key].minor_version > 2) ||
-           ptr->hosts[server_key].major_version > 1)
-       {
-         rc= MEMCACHED_INVALID_ARGUMENTS;
-         goto error;
-       }
-       else
-       {
-          if (ptr->hosts[server_key].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= 1;
-                if (no_reply)
-                   memcached_server_response_increment(&ptr->hosts[server_key]);
-                no_reply= false;
-             }
-          }
-          send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                                         "delete %s%.*s %u%s\r\n",
-                                         ptr->prefix_key,
-                                         (int) key_length, key,
-                                         (uint32_t)expiration,
-                                         no_reply ? " noreply" :"" );
-       }
-    }
-    else
-       send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
-                                      "delete %s%.*s%s\r\n",
-                                      ptr->prefix_key,
-                                      (int)key_length, key, no_reply ? " noreply" :"");
-
-    if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
-    {
-      rc= MEMCACHED_WRITE_FAILURE;
-      goto error;
-    }
-
-    if (ptr->flags & MEM_USE_UDP && !to_write)
-    {
-      if (send_length > MAX_UDP_DATAGRAM_LENGTH - UDP_DATAGRAM_HEADER_LENGTH)
-        return MEMCACHED_WRITE_FAILURE;
-      if (send_length + ptr->hosts[server_key].write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
-        memcached_io_write(&ptr->hosts[server_key], NULL, 0, 1);
-    }
-
-    rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, to_write);
-  }
-
-  if (rc != MEMCACHED_SUCCESS)
-    goto error;
-
-  if (!to_write)
-    rc= MEMCACHED_BUFFERED;
-  else if (!no_reply)
-  {
-    rc= memcached_response(&ptr->hosts[server_key], 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 binary_delete(memcached_st *ptr,
-                                             unsigned int server_key,
-                                             const char *key,
-                                            size_t key_length,
-                                            uint8_t flush)
-{
-  protocol_binary_request_delete request= {.bytes= {0}};
-
-  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
-  if (ptr->flags & MEM_NOREPLY)
-    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);
-  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-  request.message.header.request.bodylen= htonl((uint32_t) key_length);
-
-  if (ptr->flags & MEM_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 + ptr->hosts[server_key].write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
-      memcached_io_write(&ptr->hosts[server_key], NULL, 0, 1);
-  }
-
-  memcached_return rc= MEMCACHED_SUCCESS;
-
-  if ((memcached_do(&ptr->hosts[server_key], request.bytes,
-                    sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
-      (memcached_io_write(&ptr->hosts[server_key], key,
-                          key_length, (char) flush) == -1))
-  {
-    memcached_io_reset(&ptr->hosts[server_key]);
-    rc= MEMCACHED_WRITE_FAILURE;
-  }
-
-  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)
-    {
-      ++server_key;
-      if (server_key == ptr->number_of_hosts)
-        server_key= 0;
-
-      memcached_server_st* server= &ptr->hosts[server_key];
-      if ((memcached_do(server, (const char*)request.bytes,
-                        sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
-          (memcached_io_write(server, key, key_length, (char) flush) == -1))
-        memcached_io_reset(server);
-      else
-        memcached_server_response_decrement(server);
-    }
-  }
-
-  return rc;
-}
diff --git a/libmemcached/memcached_do.c b/libmemcached/memcached_do.c
deleted file mode 100644 (file)
index 46ca79b..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "common.h"
-
-memcached_return memcached_do(memcached_server_st *ptr, const void *command, 
-                              size_t command_length, uint8_t with_flush)
-{
-  memcached_return 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, 1);
-
-  sent_length= memcached_io_write(ptr, command, command_length, (char) with_flush);
-
-  if (sent_length == -1 || (size_t)sent_length != command_length)
-    rc= MEMCACHED_WRITE_FAILURE;
-  else if ((ptr->root->flags & MEM_NOREPLY) == 0)
-    memcached_server_response_increment(ptr);
-
-  return rc;
-}
diff --git a/libmemcached/memcached_dump.c b/libmemcached/memcached_dump.c
deleted file mode 100644 (file)
index 5872aa4..0000000
+++ /dev/null
@@ -1,91 +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 ascii_dump(memcached_st *ptr, memcached_dump_func *callback, void *context, uint32_t number_of_callbacks)
-{
-  memcached_return rc= 0;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  size_t send_length;
-  uint32_t server_key;
-  uint32_t x;
-
-  unlikely (ptr->number_of_hosts == 0)
-    return MEMCACHED_NO_SERVERS;
-
-  for (server_key= 0; server_key < ptr->number_of_hosts; server_key++)
-  {
-    /* 256 I BELIEVE is the upper limit of slabs */
-    for (x= 0; x < 256; x++)
-    {
-      send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
-                                     "stats cachedump %u 0 0\r\n", x);
-
-      rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, 1);
-
-      unlikely (rc != MEMCACHED_SUCCESS)
-        goto error;
-
-      while (1)
-      {
-        uint32_t callback_counter;
-        rc= memcached_response(&ptr->hosts[server_key], 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 memcached_dump(memcached_st *ptr, memcached_dump_func *callback, void *context, uint32_t number_of_callbacks)
-{
-  /* No support for Binary protocol yet */
-  if (ptr->flags & MEM_BINARY_PROTOCOL)
-    return MEMCACHED_FAILURE;
-
-  return ascii_dump(ptr, callback, context, number_of_callbacks);
-}
-
diff --git a/libmemcached/memcached_fetch.c b/libmemcached/memcached_fetch.c
deleted file mode 100644 (file)
index 9c31e2b..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-#include "common.h"
-#include "memcached_io.h"
-
-char *memcached_fetch(memcached_st *ptr, char *key, size_t *key_length, 
-                      size_t *value_length, 
-                      uint32_t *flags,
-                      memcached_return *error)
-{
-  memcached_result_st *result_buffer= &ptr->result;
-
-  unlikely (ptr->flags & MEM_USE_UDP)
-  {
-    *error= MEMCACHED_NOT_SUPPORTED;
-    return NULL;
-  }
-
-  result_buffer= memcached_fetch_result(ptr, result_buffer, error);
-
-  if (result_buffer == NULL || *error != MEMCACHED_SUCCESS)
-  {
-    WATCHPOINT_ASSERT(result_buffer == NULL);
-    *value_length= 0;
-    return NULL;
-  }
-
-  *value_length= memcached_string_length(&result_buffer->value);
-
-  if (key)
-  {
-    strncpy(key, result_buffer->key, result_buffer->key_length);
-    *key_length= result_buffer->key_length;
-  }
-
-  if (result_buffer->flags)
-    *flags= result_buffer->flags;
-  else
-    *flags= 0;
-
-  return memcached_string_c_copy(&result_buffer->value);
-}
-
-memcached_result_st *memcached_fetch_result(memcached_st *ptr,
-                                            memcached_result_st *result,
-                                            memcached_return *error)
-{
-  memcached_server_st *server;
-
-  unlikely (ptr->flags & MEM_USE_UDP)
-  {
-    *error= MEMCACHED_NOT_SUPPORTED;
-    return NULL;
-  }
-
-  if (result == NULL)
-    if ((result= memcached_result_create(ptr, NULL)) == NULL)
-      return NULL;
-
-  while ((server = memcached_io_get_readable_server(ptr)) != NULL) 
-  {
-    char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-    *error= memcached_response(server, buffer, sizeof(buffer), result);
-
-    if (*error == MEMCACHED_SUCCESS)
-      return result;
-    else if (*error == MEMCACHED_END)
-      memcached_server_response_reset(server);
-    else if (*error != MEMCACHED_NOTFOUND)
-      break;
-  }
-
-  /* We have completed reading data */
-  if (result->is_allocated)
-    memcached_result_free(result);
-  else
-    memcached_string_reset(&result->value);
-
-  return NULL;
-}
-
-memcached_return memcached_fetch_execute(memcached_st *ptr, 
-                                         memcached_execute_function *callback,
-                                         void *context,
-                                         unsigned int number_of_callbacks)
-{
-  memcached_result_st *result= &ptr->result;
-  memcached_return rc= MEMCACHED_FAILURE;
-  unsigned int x;
-
-  while ((result= memcached_fetch_result(ptr, result, &rc)) != NULL) 
-  {
-    if (rc == MEMCACHED_SUCCESS)
-    {
-      for (x= 0; x < number_of_callbacks; x++)
-      {
-        rc= (*callback[x])(ptr, result, context);
-        if (rc != MEMCACHED_SUCCESS)
-          break;
-      }
-    }
-  }
-  return rc;
-}
diff --git a/libmemcached/memcached_flush.c b/libmemcached/memcached_flush.c
deleted file mode 100644 (file)
index 1011b3f..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-#include "common.h"
-
-static memcached_return memcached_flush_binary(memcached_st *ptr, 
-                                               time_t expiration);
-static memcached_return memcached_flush_textual(memcached_st *ptr, 
-                                                time_t expiration);
-
-memcached_return memcached_flush(memcached_st *ptr, time_t expiration)
-{
-  memcached_return rc;
-
-  LIBMEMCACHED_MEMCACHED_FLUSH_START();
-  if (ptr->flags & MEM_BINARY_PROTOCOL)
-    rc= memcached_flush_binary(ptr, expiration);
-  else
-    rc= memcached_flush_textual(ptr, expiration);
-  LIBMEMCACHED_MEMCACHED_FLUSH_END();
-  return rc;
-}
-
-static memcached_return memcached_flush_textual(memcached_st *ptr, 
-                                                time_t expiration)
-{
-  unsigned int x;
-  size_t send_length;
-  memcached_return rc;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
-  unlikely (ptr->number_of_hosts == 0)
-    return MEMCACHED_NO_SERVERS;
-
-  for (x= 0; x < ptr->number_of_hosts; x++)
-  {
-    bool no_reply= (ptr->flags & MEM_NOREPLY);
-    if (expiration)
-      send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
-                                     "flush_all %llu%s\r\n",
-                                     (unsigned long long)expiration, no_reply ? " noreply" : "");
-    else
-      send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
-                                     "flush_all%s\r\n", no_reply ? " noreply" : "");
-
-    rc= memcached_do(&ptr->hosts[x], buffer, send_length, 1);
-
-    if (rc == MEMCACHED_SUCCESS && !no_reply)
-      (void)memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return memcached_flush_binary(memcached_st *ptr, 
-                                               time_t expiration)
-{
-  unsigned int x;
-  protocol_binary_request_flush request= {.bytes= {0}};
-
-  unlikely (ptr->number_of_hosts == 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 (x= 0; x < ptr->number_of_hosts; x++)
-  {
-    if (ptr->flags & MEM_NOREPLY)
-      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ;
-    else
-      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
-    if (memcached_do(&ptr->hosts[x], request.bytes, 
-                     sizeof(request.bytes), 1) != MEMCACHED_SUCCESS) 
-    {
-      memcached_io_reset(&ptr->hosts[x]);
-      return MEMCACHED_WRITE_FAILURE;
-    } 
-  }
-
-  for (x= 0; x < ptr->number_of_hosts; x++)
-  {
-    if (memcached_server_response_count(&ptr->hosts[x]) > 0)
-       (void)memcached_response(&ptr->hosts[x], NULL, 0, NULL);
-  }
-
-  return MEMCACHED_SUCCESS;
-}
diff --git a/libmemcached/memcached_flush_buffers.c b/libmemcached/memcached_flush_buffers.c
deleted file mode 100644 (file)
index bbf0954..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "common.h"
-#include "memcached_io.h"
-
-memcached_return memcached_flush_buffers(memcached_st *mem)
-{
-  memcached_return ret= MEMCACHED_SUCCESS;
-
-  for (uint32_t x= 0; x < mem->number_of_hosts; ++x)
-    if (mem->hosts[x].write_buffer_offset != 0) 
-    {
-      if (mem->hosts[x].fd == -1 &&
-          (ret= memcached_connect(&mem->hosts[x])) != MEMCACHED_SUCCESS)
-      {
-        WATCHPOINT_ERROR(ret);
-        return ret;
-      }
-      if (memcached_io_write(&mem->hosts[x], NULL, 0, 1) == -1)
-        ret= MEMCACHED_SOME_ERRORS;
-    }
-
-  return ret;
-}
diff --git a/libmemcached/memcached_get.c b/libmemcached/memcached_get.c
deleted file mode 100644 (file)
index 3436186..0000000
+++ /dev/null
@@ -1,554 +0,0 @@
-#include "common.h"
-#include "memcached_io.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 *error)
-{
-  return memcached_get_by_key(ptr, NULL, 0, key, key_length, value_length, 
-                              flags, error);
-}
-
-static memcached_return memcached_mget_by_key_real(memcached_st *ptr, 
-                                                   const char *master_key, 
-                                                   size_t master_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 *master_key, 
-                           size_t master_key_length, 
-                           const char *key, size_t key_length,
-                           size_t *value_length, 
-                           uint32_t *flags,
-                           memcached_return *error)
-{
-  char *value;
-  size_t dummy_length;
-  uint32_t dummy_flags;
-  memcached_return dummy_error;
-
-  unlikely (ptr->flags & MEM_USE_UDP)
-  {
-    *error= MEMCACHED_NOT_SUPPORTED;
-    return NULL;
-  }
-
-  /* Request the key */
-  *error= memcached_mget_by_key_real(ptr, master_key, master_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 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 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 binary_mget_by_key(memcached_st *ptr,
-                                           unsigned int master_server_key,
-                                           bool is_master_key_set,
-                                           const char * const *keys, 
-                                           const size_t *key_length,
-                                           size_t number_of_keys,
-                                          bool mget_mode);
-
-static memcached_return memcached_mget_by_key_real(memcached_st *ptr, 
-                                                   const char *master_key, 
-                                                   size_t master_key_length,
-                                                   const char * const *keys, 
-                                                   const size_t *key_length, 
-                                                   size_t number_of_keys,
-                                                   bool mget_mode)
-{
-  unsigned int x;
-  memcached_return rc= MEMCACHED_NOTFOUND;
-  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_master_key_set= false;
-
-   unlikely (ptr->flags & MEM_USE_UDP)
-    return MEMCACHED_NOT_SUPPORTED;
-
-  LIBMEMCACHED_MEMCACHED_MGET_START();
-  ptr->cursor_server= 0;
-
-  if (number_of_keys == 0)
-    return MEMCACHED_NOTFOUND;
-
-  if (ptr->number_of_hosts == 0)
-    return MEMCACHED_NO_SERVERS;
-
-  if ((ptr->flags & MEM_VERIFY_KEY) && (memcached_key_test(keys, key_length, number_of_keys) == MEMCACHED_BAD_KEY_PROVIDED))
-    return MEMCACHED_BAD_KEY_PROVIDED;
-
-  if (master_key && master_key_length)
-  {
-    if ((ptr->flags & MEM_VERIFY_KEY) && (memcached_key_test((const char * const *)&master_key, &master_key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
-      return MEMCACHED_BAD_KEY_PROVIDED;
-    master_server_key= memcached_generate_hash(ptr, master_key, master_key_length);
-    is_master_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 (x= 0; x < ptr->number_of_hosts; x++)
-  {
-    if (memcached_server_response_count(&ptr->hosts[x]))
-    {
-      char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
-      if (ptr->flags & MEM_NO_BLOCK)
-        (void)memcached_io_write(&ptr->hosts[x], NULL, 0, 1);
-
-      while(memcached_server_response_count(&ptr->hosts[x]))
-        (void)memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, &ptr->result);
-    }
-  }
-  
-  if (ptr->flags & MEM_BINARY_PROTOCOL)
-    return binary_mget_by_key(ptr, master_server_key, is_master_key_set, keys, 
-                              key_length, number_of_keys, mget_mode);
-
-  if (ptr->flags & MEM_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.
-  */
-  for (x= 0; x < number_of_keys; x++)
-  {
-    unsigned int server_key;
-
-    if (is_master_key_set)
-      server_key= master_server_key;
-    else
-      server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
-
-    if (memcached_server_response_count(&ptr->hosts[server_key]) == 0)
-    {
-      rc= memcached_connect(&ptr->hosts[server_key]);
-
-      if (rc != MEMCACHED_SUCCESS)
-        continue;
-
-      if ((memcached_io_write(&ptr->hosts[server_key], get_command, get_command_length, 0)) == -1)
-      {
-        rc= MEMCACHED_SOME_ERRORS;
-        continue;
-      }
-      WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 0);
-      memcached_server_response_increment(&ptr->hosts[server_key]);
-      WATCHPOINT_ASSERT(ptr->hosts[server_key].cursor_active == 1);
-    }
-
-    /* Only called when we have a prefix key */
-    if (ptr->prefix_key[0] != 0)
-    {
-      if ((memcached_io_write(&ptr->hosts[server_key], ptr->prefix_key, ptr->prefix_key_length, 0)) == -1)
-      {
-        memcached_server_response_reset(&ptr->hosts[server_key]);
-        rc= MEMCACHED_SOME_ERRORS;
-        continue;
-      }
-    }
-
-    if ((memcached_io_write(&ptr->hosts[server_key], keys[x], key_length[x], 0)) == -1)
-    {
-      memcached_server_response_reset(&ptr->hosts[server_key]);
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-
-    if ((memcached_io_write(&ptr->hosts[server_key], " ", 1, 0)) == -1)
-    {
-      memcached_server_response_reset(&ptr->hosts[server_key]);
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-  }
-
-  /*
-    Should we muddle on if some servers are dead?
-  */
-  for (x= 0; x < ptr->number_of_hosts; x++)
-  {
-    if (memcached_server_response_count(&ptr->hosts[x]))
-    {
-      /* We need to do something about non-connnected hosts in the future */
-      if ((memcached_io_write(&ptr->hosts[x], "\r\n", 2, 1)) == -1)
-      {
-        rc= MEMCACHED_SOME_ERRORS;
-      }
-    }
-  }
-
-  LIBMEMCACHED_MEMCACHED_MGET_END();
-  return rc;
-}
-
-memcached_return memcached_mget_by_key(memcached_st *ptr, 
-                                       const char *master_key, 
-                                       size_t master_key_length,
-                                       const char * const *keys, 
-                                       const size_t *key_length, 
-                                       size_t number_of_keys)
-{
-  return memcached_mget_by_key_real(ptr, master_key, master_key_length, keys, 
-                                    key_length, number_of_keys, true);
-}
-
-memcached_return memcached_mget_execute(memcached_st *ptr,
-                                        const char * const *keys,
-                                        const size_t *key_length,
-                                        size_t number_of_keys,
-                                        memcached_execute_function *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 memcached_mget_execute_by_key(memcached_st *ptr,
-                                               const char *master_key,
-                                               size_t master_key_length,
-                                               const char * const *keys,
-                                               const size_t *key_length,
-                                               size_t number_of_keys,
-                                               memcached_execute_function *callback,
-                                               void *context,
-                                               unsigned int number_of_callbacks)
-{
-  if ((ptr->flags & MEM_BINARY_PROTOCOL) == 0)
-    return MEMCACHED_NOT_SUPPORTED;
-
-  memcached_return 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, master_key, master_key_length, keys,
-                            key_length, number_of_keys);
-  ptr->callbacks= original_callbacks;
-  return rc;
-}
-
-static memcached_return simple_binary_mget(memcached_st *ptr,
-                                           unsigned int master_server_key,
-                                           bool is_master_key_set,
-                                           const char * const *keys, 
-                                           const size_t *key_length, 
-                                           size_t number_of_keys, bool mget_mode)
-{
-  memcached_return rc= MEMCACHED_NOTFOUND;
-  uint32_t x;
-
-  int flush= number_of_keys == 1;
-
-  /* 
-    If a server fails we warn about errors and start all over with sending keys
-    to the server.
-  */
-  for (x= 0; x < number_of_keys; x++) 
-  {
-    unsigned int server_key;
-
-    if (is_master_key_set)
-      server_key= master_server_key;
-    else
-      server_key= memcached_generate_hash(ptr, keys[x], key_length[x]);
-
-    if (memcached_server_response_count(&ptr->hosts[server_key]) == 0) 
-    {
-      rc= memcached_connect(&ptr->hosts[server_key]);
-      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 vk;
-    vk= memcached_validate_key_length(key_length[x],
-                                      ptr->flags & MEM_BINARY_PROTOCOL);
-    unlikely (vk != MEMCACHED_SUCCESS)
-    {
-      if (x > 0)
-        memcached_io_reset(&ptr->hosts[server_key]);
-      return vk;
-    }
-
-    request.message.header.request.keylen= htons((uint16_t)key_length[x]);
-    request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
-    request.message.header.request.bodylen= htonl((uint32_t) key_length[x]);
-    
-    if ((memcached_io_write(&ptr->hosts[server_key], request.bytes,
-                            sizeof(request.bytes), 0) == -1) ||
-        (memcached_io_write(&ptr->hosts[server_key], keys[x], 
-                            key_length[x], (char) flush) == -1)) 
-    {
-      memcached_server_response_reset(&ptr->hosts[server_key]);
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-    
-    /* We just want one pending response per server */
-    memcached_server_response_reset(&ptr->hosts[server_key]); 
-    memcached_server_response_increment(&ptr->hosts[server_key]);    
-    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 (x= 0; x < ptr->number_of_hosts; x++)
-      if (memcached_server_response_count(&ptr->hosts[x])) 
-      {
-        if (memcached_io_write(&ptr->hosts[x], NULL, 0, 1) == -1) 
-        {
-          memcached_server_response_reset(&ptr->hosts[x]);
-          memcached_io_reset(&ptr->hosts[x]);
-          rc= MEMCACHED_SOME_ERRORS;
-        }
-
-        if (memcached_io_write(&ptr->hosts[x], request.bytes, 
-                              sizeof(request.bytes), 1) == -1) 
-        {
-          memcached_server_response_reset(&ptr->hosts[x]);
-          memcached_io_reset(&ptr->hosts[x]);
-          rc= MEMCACHED_SOME_ERRORS;
-        }
-      }
-    }
-
-
-  return rc;
-}
-
-static memcached_return 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 rc= MEMCACHED_NOTFOUND;
-  uint32_t x;
-
-  for (uint32_t replica= 0; replica <= ptr->number_of_replicas; ++replica)
-  {
-    bool success= true;    
-
-    for (x= 0; x < number_of_keys; ++x)
-    {
-      if (hash[x] == ptr->number_of_hosts)
-        continue; /* Already successfully sent */
-
-      uint32_t server= hash[x] + replica;
-      while (server >= ptr->number_of_hosts)
-        server -= ptr->number_of_hosts;
-
-      if (dead_servers[server])
-        continue;
-
-      if (memcached_server_response_count(&ptr->hosts[server]) == 0)
-      {
-        rc= memcached_connect(&ptr->hosts[server]);
-        if (rc != MEMCACHED_SUCCESS)
-        {
-          memcached_io_reset(&ptr->hosts[server]);
-          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]),
-          .datatype= PROTOCOL_BINARY_RAW_BYTES,
-          .bodylen= htonl((uint32_t)key_length[x])
-        }
-      };
-
-      /*
-       * 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_
-       */
-      if ((memcached_io_write(&ptr->hosts[server], request.bytes,
-                              sizeof(request.bytes), 0) == -1) ||
-          (memcached_io_write(&ptr->hosts[server], keys[x],
-                              key_length[x], 1) == -1))
-      {
-        memcached_io_reset(&ptr->hosts[server]);
-        dead_servers[server]= true;
-        success= false;
-        continue;
-      }
-
-      memcached_server_response_increment(&ptr->hosts[server]);
-      hash[x]= ptr->number_of_hosts;
-    }
-
-    if (success)
-      break;
-  }
-
-  return rc;
-}
-
-static memcached_return binary_mget_by_key(memcached_st *ptr,
-                                           unsigned int master_server_key,
-                                           bool is_master_key_set,
-                                           const char * const *keys, 
-                                           const size_t *key_length,
-                                           size_t number_of_keys, 
-                                           bool mget_mode)
-{
-  memcached_return rc;
-
-  if (ptr->number_of_replicas == 0) 
-  {
-    rc= simple_binary_mget(ptr, master_server_key, is_master_key_set,
-                           keys, key_length, number_of_keys, mget_mode);
-  } 
-  else 
-  {
-    uint32_t* hash;
-    bool* dead_servers;
-
-    hash= ptr->call_malloc(ptr, sizeof(uint32_t) * number_of_keys);
-    dead_servers= ptr->call_calloc(ptr, ptr->number_of_hosts, sizeof(bool));
-
-    if (hash == NULL || dead_servers == NULL)
-    {
-      ptr->call_free(ptr, hash);
-      ptr->call_free(ptr, dead_servers);
-      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-    }
-
-    if (is_master_key_set)
-      for (unsigned int x= 0; x < number_of_keys; x++)
-        hash[x]= master_server_key;
-    else
-      for (unsigned int x= 0; x < number_of_keys; x++)
-        hash[x]= memcached_generate_hash(ptr, keys[x], key_length[x]);
-
-    rc= replication_binary_mget(ptr, hash, dead_servers, keys, 
-                                key_length, number_of_keys);
-
-    ptr->call_free(ptr, hash);
-    ptr->call_free(ptr, dead_servers);
-
-    return MEMCACHED_SUCCESS;
-  }
-
-  return rc;
-}
diff --git a/libmemcached/memcached_get.h b/libmemcached/memcached_get.h
deleted file mode 100644 (file)
index bf3aeb5..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Summary: Get functions for libmemcached
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Brian Aker
- */
-
-#ifndef LIBMEMCACHED_MEMCACHED_GET_H
-#define LIBMEMCACHED_MEMCACHED_GET_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Public defines */
-LIBMEMCACHED_API
-char *memcached_get(memcached_st *ptr, 
-                    const char *key, size_t key_length,
-                    size_t *value_length, 
-                    uint32_t *flags,
-                    memcached_return *error);
-
-LIBMEMCACHED_API
-memcached_return memcached_mget(memcached_st *ptr, 
-                                const char * const *keys, 
-                                const size_t *key_length, 
-                                size_t number_of_keys);
-
-LIBMEMCACHED_API
-char *memcached_get_by_key(memcached_st *ptr, 
-                           const char *master_key, size_t master_key_length, 
-                           const char *key, size_t key_length, 
-                           size_t *value_length, 
-                           uint32_t *flags,
-                           memcached_return *error);
-
-LIBMEMCACHED_API
-memcached_return memcached_mget_by_key(memcached_st *ptr, 
-                                       const char *master_key, size_t 
-                                       master_key_length,
-                                       const char * const *keys, 
-                                       const size_t *key_length, 
-                                       size_t number_of_keys);
-
-LIBMEMCACHED_API
-char *memcached_fetch(memcached_st *ptr, 
-                      char *key, size_t *key_length, 
-                      size_t *value_length, uint32_t *flags, 
-                      memcached_return *error);
-
-LIBMEMCACHED_API
-memcached_result_st *memcached_fetch_result(memcached_st *ptr, 
-                                            memcached_result_st *result,
-                                            memcached_return *error);
-
-LIBMEMCACHED_API
-memcached_return memcached_mget_execute(memcached_st *ptr,
-                                        const char * const *keys,
-                                        const size_t *key_length,
-                                        size_t number_of_keys,
-                                        memcached_execute_function *callback,
-                                        void *context,
-                                        unsigned int number_of_callbacks);
-
-LIBMEMCACHED_API
-memcached_return memcached_mget_execute_by_key(memcached_st *ptr,
-                                               const char *master_key,
-                                               size_t master_key_length,
-                                               const char * const *keys,
-                                               const size_t *key_length,
-                                               size_t number_of_keys,
-                                               memcached_execute_function *callback,
-                                               void *context,
-                                               unsigned int number_of_callbacks);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBMEMCACHED_MEMCACHED_GET_H */
diff --git a/libmemcached/memcached_hash.c b/libmemcached/memcached_hash.c
deleted file mode 100644 (file)
index 959fc29..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-#include "common.h"
-
-
-/* Defines */
-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;
-
-/* Prototypes */
-static uint32_t internal_generate_hash(const char *key, size_t key_length);
-static uint32_t internal_generate_md5(const char *key, size_t key_length);
-
-uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash hash_algorithm)
-{
-  uint32_t hash= 1; /* Just here to remove compile warning */
-  uint32_t x= 0;
-
-  switch (hash_algorithm)
-  {
-  case MEMCACHED_HASH_DEFAULT:
-    hash= internal_generate_hash(key, key_length);
-    break;
-  case MEMCACHED_HASH_MD5:
-    hash= internal_generate_md5(key, key_length);
-    break;
-  case MEMCACHED_HASH_CRC:
-    hash= ((hash_crc32(key, key_length) >> 16) & 0x7fff);
-    if (hash == 0)
-      hash= 1;
-    break;
-    /* FNV hash'es lifted from Dustin Sallings work */
-  case MEMCACHED_HASH_FNV1_64:
-    {
-      /* Thanks to pierre@demartines.com for the pointer */
-      uint64_t temp_hash;
-
-      temp_hash= FNV_64_INIT;
-      for (x= 0; x < key_length; x++)
-      {
-        temp_hash *= FNV_64_PRIME;
-        temp_hash ^= (uint64_t)key[x];
-      }
-      hash= (uint32_t)temp_hash;
-    }
-    break;
-  case MEMCACHED_HASH_FNV1A_64:
-    {
-      hash= (uint32_t) FNV_64_INIT;
-      for (x= 0; x < key_length; x++)
-      {
-        uint32_t val= (uint32_t)key[x];
-        hash ^= val;
-        hash *= (uint32_t) FNV_64_PRIME;
-      }
-    }
-    break;
-  case MEMCACHED_HASH_FNV1_32:
-    {
-      hash= FNV_32_INIT;
-      for (x= 0; x < key_length; x++)
-      {
-        uint32_t val= (uint32_t)key[x];
-        hash *= FNV_32_PRIME;
-        hash ^= val;
-      }
-    }
-    break;
-  case MEMCACHED_HASH_FNV1A_32:
-    {
-      hash= FNV_32_INIT;
-      for (x= 0; x < key_length; x++)
-      {
-        uint32_t val= (uint32_t)key[x];
-        hash ^= val;
-        hash *= FNV_32_PRIME;
-      }
-    }
-    break;
-    case MEMCACHED_HASH_HSIEH:
-    {
-#ifdef HAVE_HSIEH_HASH
-      hash= hsieh_hash(key, key_length);
-#endif
-      break;
-    }
-    case MEMCACHED_HASH_MURMUR:
-    {
-      hash= murmur_hash(key, key_length);
-      break;
-    }
-    case MEMCACHED_HASH_JENKINS:
-    {
-      hash=jenkins_hash(key, key_length, 13);
-      break;
-    }
-    default:
-    {
-      WATCHPOINT_ASSERT(hash_algorithm);
-      break;
-    }
-  }
-  return hash;
-}
-
-uint32_t generate_hash(memcached_st *ptr, const char *key, size_t key_length)
-{
-  uint32_t hash= 1; /* Just here to remove compile warning */
-
-
-  WATCHPOINT_ASSERT(ptr->number_of_hosts);
-
-  if (ptr->number_of_hosts == 1)
-    return 0;
-
-  hash= memcached_generate_hash_value(key, key_length, ptr->hash);
-  WATCHPOINT_ASSERT(hash);
-  return hash;
-}
-
-static uint32_t dispatch_host(memcached_st *ptr, uint32_t hash)
-{
-  switch (ptr->distribution)
-  {
-  case MEMCACHED_DISTRIBUTION_CONSISTENT:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
-    {
-      uint32_t num= ptr->continuum_points_counter;
-      WATCHPOINT_ASSERT(ptr->continuum);
-
-      hash= hash;
-      memcached_continuum_item_st *begin, *end, *left, *right, *middle;
-      begin= left= ptr->continuum;
-      end= right= ptr->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 % ptr->number_of_hosts;
-  case MEMCACHED_DISTRIBUTION_RANDOM:
-    return (uint32_t) random() % ptr->number_of_hosts;
-  default:
-    WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
-    return hash % ptr->number_of_hosts;
-  }
-
-  /* NOTREACHED */
-}
-
-/*
-  One day make this public, and have it return the actual memcached_server_st
-  to the calling application.
-*/
-uint32_t memcached_generate_hash(memcached_st *ptr, const char *key, size_t key_length)
-{
-  uint32_t hash= 1; /* Just here to remove compile warning */
-
-  WATCHPOINT_ASSERT(ptr->number_of_hosts);
-
-  if (ptr->number_of_hosts == 1)
-    return 0;
-
-  if (ptr->flags & MEM_HASH_WITH_PREFIX_KEY)
-  {
-    size_t temp_length= ptr->prefix_key_length + key_length;
-    char temp[temp_length];
-
-    if (temp_length > MEMCACHED_MAX_KEY -1)
-      return 0;
-
-    strncpy(temp, ptr->prefix_key, ptr->prefix_key_length);
-    strncpy(temp + ptr->prefix_key_length, key, key_length);
-    hash= generate_hash(ptr, temp, temp_length);
-  }
-  else
-  {
-    hash= generate_hash(ptr, key, key_length);
-  }
-
-  WATCHPOINT_ASSERT(hash);
-
-  if (memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS) && ptr->next_distribution_rebuild) {
-    struct timeval now;
-
-    if (gettimeofday(&now, NULL) == 0 &&
-        now.tv_sec > ptr->next_distribution_rebuild)
-      run_distribution(ptr);
-  }
-
-  return dispatch_host(ptr, hash);
-}
-
-static uint32_t internal_generate_hash(const char *key, size_t key_length)
-{
-  const char *ptr= key;
-  uint32_t value= 0;
-
-  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 == 0 ? 1 : (uint32_t) value;
-}
-
-static uint32_t internal_generate_md5(const char *key, size_t key_length)
-{
-  unsigned char results[16];
-
-  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/libmemcached/memcached_hosts.c b/libmemcached/memcached_hosts.c
deleted file mode 100644 (file)
index d7f78de..0000000
+++ /dev/null
@@ -1,514 +0,0 @@
-#include "common.h"
-#include <math.h>
-
-/* Protoypes (static) */
-static memcached_return server_add(memcached_st *ptr, const char *hostname,
-                                   unsigned int port,
-                                   uint32_t weight,
-                                   memcached_connection type);
-memcached_return update_continuum(memcached_st *ptr);
-
-static int compare_servers(const void *p1, const void *p2)
-{
-  int return_value;
-  memcached_server_st *a= (memcached_server_st *)p1;
-  memcached_server_st *b= (memcached_server_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 (ptr->number_of_hosts)
-  {
-    qsort(ptr->hosts, ptr->number_of_hosts, sizeof(memcached_server_st), compare_servers);
-    ptr->hosts[0].count= (uint16_t) ptr->number_of_hosts;
-  }
-}
-
-
-memcached_return run_distribution(memcached_st *ptr)
-{
-  switch (ptr->distribution)
-  {
-  case MEMCACHED_DISTRIBUTION_CONSISTENT:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
-  case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
-    return update_continuum(ptr);
-  case MEMCACHED_DISTRIBUTION_MODULA:
-    if (ptr->flags & MEM_USE_SORT_HOSTS)
-      sort_hosts(ptr);
-    break;
-  case MEMCACHED_DISTRIBUTION_RANDOM:
-    break;
-  default:
-    WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
-  }
-
-  ptr->last_disconnected_server = NULL;
-
-  return MEMCACHED_SUCCESS;
-}
-
-void server_list_free(memcached_st *ptr, memcached_server_st *servers)
-{
-  unsigned int x;
-
-  if (servers == NULL)
-    return;
-
-  for (x= 0; x < servers->count; x++)
-    if (servers[x].address_info)
-    {
-      freeaddrinfo(servers[x].address_info);
-      servers[x].address_info= NULL;
-    }
-
-  if (ptr)
-    ptr->call_free(ptr, servers);
-  else
-    free(servers);
-}
-
-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_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;
-}
-
-memcached_return update_continuum(memcached_st *ptr)
-{
-  uint32_t host_index;
-  uint32_t continuum_index= 0;
-  uint32_t value;
-  memcached_server_st *list;
-  uint32_t pointer_index;
-  uint32_t pointer_counter= 0;
-  uint32_t pointer_per_server= MEMCACHED_POINTS_PER_SERVER;
-  uint32_t pointer_per_hash= 1;
-  uint64_t total_weight= 0;
-  uint64_t is_ketama_weighted= 0;
-  uint64_t is_auto_ejecting= 0;
-  uint32_t points_per_server= 0;
-  uint32_t live_servers= 0;
-  struct timeval now;
-
-  if (gettimeofday(&now, NULL) != 0)
-  {
-    ptr->cached_errno = errno;
-    return MEMCACHED_ERRNO;
-  }
-
-  list = ptr->hosts;
-
-  /* count live servers (those without a retry delay set) */
-  is_auto_ejecting= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS);
-  if (is_auto_ejecting)
-  {
-    live_servers= 0;
-    ptr->next_distribution_rebuild= 0;
-    for (host_index= 0; host_index < ptr->number_of_hosts; ++host_index)
-    {
-      if (list[host_index].next_retry <= now.tv_sec)
-        live_servers++;
-      else
-      {
-        if (ptr->next_distribution_rebuild == 0 || list[host_index].next_retry < ptr->next_distribution_rebuild)
-          ptr->next_distribution_rebuild= list[host_index].next_retry;
-      }
-    }
-  }
-  else
-    live_servers= ptr->number_of_hosts;
-
-  is_ketama_weighted= memcached_behavior_get(ptr, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
-  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->continuum_count)
-  {
-    memcached_continuum_item_st *new_ptr;
-
-    new_ptr= ptr->call_realloc(ptr, ptr->continuum,
-                               sizeof(memcached_continuum_item_st) * (live_servers + MEMCACHED_CONTINUUM_ADDITION) * points_per_server);
-
-    if (new_ptr == 0)
-      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-    ptr->continuum= new_ptr;
-    ptr->continuum_count= live_servers + MEMCACHED_CONTINUUM_ADDITION;
-  }
-
-  if (is_ketama_weighted)
-  {
-    for (host_index = 0; host_index < ptr->number_of_hosts; ++host_index)
-    {
-      if (list[host_index].weight == 0)
-      {
-        list[host_index].weight = 1;
-      }
-      if (!is_auto_ejecting || list[host_index].next_retry <= now.tv_sec)
-        total_weight += list[host_index].weight;
-    }
-  }
-
-  for (host_index = 0; host_index < ptr->number_of_hosts; ++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 (pointer_index= 0;
-           pointer_index < pointer_per_server / pointer_per_hash;
-           pointer_index++)
-      {
-        char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
-        size_t sort_host_length;
-
-        // Spymemcached ketema key format is: hostname/ip:port-index
-        // If hostname is not available then: /ip:port-index
-        sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
-                                            "/%s:%d-%d",
-                                            list[host_index].hostname,
-                                            list[host_index].port,
-                                            pointer_index);
-#ifdef DEBUG
-        printf("update_continuum: key is %s\n", sort_host);
-#endif
-
-        WATCHPOINT_ASSERT(sort_host_length);
-
-        if (is_ketama_weighted)
-        {
-          unsigned int i;
-          for (i = 0; i < pointer_per_hash; i++)
-          {
-             value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
-             ptr->continuum[continuum_index].index= host_index;
-             ptr->continuum[continuum_index++].value= value;
-          }
-        }
-        else
-        {
-          value= memcached_generate_hash_value(sort_host, sort_host_length, ptr->hash_continuum);
-          ptr->continuum[continuum_index].index= host_index;
-          ptr->continuum[continuum_index++].value= value;
-        }
-      }
-    }
-    else
-    {
-      for (pointer_index= 1;
-           pointer_index <= pointer_per_server / pointer_per_hash;
-           pointer_index++)
-      {
-        char sort_host[MEMCACHED_MAX_HOST_SORT_LENGTH]= "";
-        size_t sort_host_length;
-
-        if (list[host_index].port == MEMCACHED_DEFAULT_PORT)
-        {
-          sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
-                                              "%s-%d",
-                                              list[host_index].hostname,
-                                              pointer_index - 1);
-        }
-        else
-        {
-          sort_host_length= (size_t) snprintf(sort_host, MEMCACHED_MAX_HOST_SORT_LENGTH,
-                                              "%s:%d-%d",
-                                              list[host_index].hostname,
-                                              list[host_index].port, pointer_index - 1);
-        }
-
-        WATCHPOINT_ASSERT(sort_host_length);
-
-        if (is_ketama_weighted)
-        {
-          unsigned int i;
-          for (i = 0; i < pointer_per_hash; i++)
-          {
-             value= ketama_server_hash(sort_host, (uint32_t) sort_host_length, (int) i);
-             ptr->continuum[continuum_index].index= host_index;
-             ptr->continuum[continuum_index++].value= value;
-          }
-        }
-        else
-        {
-          value= memcached_generate_hash_value(sort_host, sort_host_length, ptr->hash_continuum);
-          ptr->continuum[continuum_index].index= host_index;
-          ptr->continuum[continuum_index++].value= value;
-        }
-      }
-    }
-
-    pointer_counter+= pointer_per_server;
-  }
-
-  WATCHPOINT_ASSERT(ptr);
-  WATCHPOINT_ASSERT(ptr->continuum);
-  WATCHPOINT_ASSERT(ptr->number_of_hosts * MEMCACHED_POINTS_PER_SERVER <= MEMCACHED_CONTINUUM_SIZE);
-  ptr->continuum_points_counter= pointer_counter;
-  qsort(ptr->continuum, ptr->continuum_points_counter, sizeof(memcached_continuum_item_st), continuum_item_cmp);
-
-#ifdef DEBUG
-  for (pointer_index= 0; ptr->number_of_hosts && 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 memcached_server_push(memcached_st *ptr, memcached_server_st *list)
-{
-  unsigned int x;
-  uint16_t count;
-  memcached_server_st *new_host_list;
-
-  if (!list)
-    return MEMCACHED_SUCCESS;
-
-  count= list[0].count;
-  new_host_list= ptr->call_realloc(ptr, ptr->hosts,
-                                   sizeof(memcached_server_st) * (count + ptr->number_of_hosts));
-
-  if (!new_host_list)
-    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-  ptr->hosts= new_host_list;
-
-  for (x= 0; x < count; x++)
-  {
-    if ((ptr->flags & MEM_USE_UDP && list[x].type != MEMCACHED_CONNECTION_UDP)
-            || ((list[x].type == MEMCACHED_CONNECTION_UDP)
-            && ! (ptr->flags & MEM_USE_UDP)) )
-      return MEMCACHED_INVALID_HOST_PROTOCOL;
-
-    WATCHPOINT_ASSERT(list[x].hostname[0] != 0);
-    memcached_server_create(ptr, &ptr->hosts[ptr->number_of_hosts]);
-    /* TODO check return type */
-    (void)memcached_server_create_with(ptr, &ptr->hosts[ptr->number_of_hosts], list[x].hostname,
-                                       list[x].port, list[x].weight, list[x].type);
-    ptr->number_of_hosts++;
-  }
-  ptr->hosts[0].count= (uint16_t) ptr->number_of_hosts;
-
-  return run_distribution(ptr);
-}
-
-memcached_return memcached_server_add_unix_socket(memcached_st *ptr,
-                                                  const char *filename)
-{
-  return memcached_server_add_unix_socket_with_weight(ptr, filename, 0);
-}
-
-memcached_return 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 memcached_server_add_udp(memcached_st *ptr,
-                                          const char *hostname,
-                                          unsigned int port)
-{
-  return memcached_server_add_udp_with_weight(ptr, hostname, port, 0);
-}
-
-memcached_return memcached_server_add_udp_with_weight(memcached_st *ptr,
-                                                      const char *hostname,
-                                                      unsigned int 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 memcached_server_add(memcached_st *ptr,
-                                      const char *hostname,
-                                      unsigned int port)
-{
-  return memcached_server_add_with_weight(ptr, hostname, port, 0);
-}
-
-memcached_return memcached_server_add_with_weight(memcached_st *ptr,
-                                                  const char *hostname,
-                                                  unsigned int 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 server_add(memcached_st *ptr, const char *hostname,
-                                   unsigned int port,
-                                   uint32_t weight,
-                                   memcached_connection type)
-{
-  memcached_server_st *new_host_list;
-
-  if ( (ptr->flags & MEM_USE_UDP && type != MEMCACHED_CONNECTION_UDP)
-      || ( (type == MEMCACHED_CONNECTION_UDP) && !(ptr->flags & MEM_USE_UDP) ) )
-    return MEMCACHED_INVALID_HOST_PROTOCOL;
-
-  new_host_list= ptr->call_realloc(ptr, ptr->hosts,
-                                   sizeof(memcached_server_st) * (ptr->number_of_hosts+1));
-
-  if (new_host_list == NULL)
-    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-  ptr->hosts= new_host_list;
-
-  /* TODO: Check return type */
-  (void)memcached_server_create_with(ptr, &ptr->hosts[ptr->number_of_hosts], hostname, port, weight, type);
-  ptr->number_of_hosts++;
-  ptr->hosts[0].count= (uint16_t) ptr->number_of_hosts;
-
-  return run_distribution(ptr);
-}
-
-memcached_return memcached_server_remove(memcached_server_st *st_ptr)
-{
-  uint32_t x, host_index;
-  memcached_st *ptr= st_ptr->root;
-  memcached_server_st *list= ptr->hosts;
-
-  for (x= 0, host_index= 0; x < ptr->number_of_hosts; x++)
-  {
-    if (strncmp(list[x].hostname, st_ptr->hostname, MEMCACHED_MAX_HOST_LENGTH) != 0 || list[x].port != st_ptr->port)
-    {
-      if (host_index != x)
-        memcpy(list+host_index, list+x, sizeof(memcached_server_st));
-      host_index++;
-    }
-  }
-  ptr->number_of_hosts= host_index;
-
-  if (st_ptr->address_info)
-  {
-    freeaddrinfo(st_ptr->address_info);
-    st_ptr->address_info= NULL;
-  }
-  run_distribution(ptr);
-
-  return MEMCACHED_SUCCESS;
-}
-
-memcached_server_st *memcached_server_list_append(memcached_server_st *ptr,
-                                                  const char *hostname, unsigned int port,
-                                                  memcached_return *error)
-{
-  return memcached_server_list_append_with_weight(ptr, hostname, port, 0, error);
-}
-
-memcached_server_st *memcached_server_list_append_with_weight(memcached_server_st *ptr,
-                                                              const char *hostname, unsigned int port,
-                                                              uint32_t weight,
-                                                              memcached_return *error)
-{
-  unsigned int count;
-  memcached_server_st *new_host_list;
-
-  if (hostname == NULL || error == NULL)
-    return NULL;
-
-  if (!port)
-    port= MEMCACHED_DEFAULT_PORT;
-
-  /* Increment count for hosts */
-  count= 1;
-  if (ptr != NULL)
-  {
-    count+= ptr[0].count;
-  }
-
-  new_host_list= (memcached_server_st *)realloc(ptr, sizeof(memcached_server_st) * count);
-  if (!new_host_list)
-  {
-    *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-    return NULL;
-  }
-
-  /* TODO: Check return type */
-  memcached_server_create_with(NULL, &new_host_list[count-1], hostname, port, weight, MEMCACHED_CONNECTION_TCP);
-
-  /* Backwards compatibility hack */
-  new_host_list[0].count= (uint16_t) count;
-
-  *error= MEMCACHED_SUCCESS;
-  return new_host_list;
-}
-
-unsigned int memcached_server_list_count(memcached_server_st *ptr)
-{
-  if (ptr == NULL)
-    return 0;
-
-  return ptr[0].count;
-}
-
-void memcached_server_list_free(memcached_server_st *ptr)
-{
-  server_list_free(NULL, ptr);
-}
diff --git a/libmemcached/memcached_internal.h b/libmemcached/memcached_internal.h
deleted file mode 100644 (file)
index 52fb4c1..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Summary: Internal functions used by the library. Not for public use!
- * Copy: See Copyright for the status of this software.
- *
- * Author: Trond Norbye
- */
-
-#ifndef LIBMEMCACHED_MEMCACHED_INTERNAL_H
-#define LIBMEMCACHED_MEMCACHED_INTERNAL_H
-
-#if defined(BUILDING_LIBMEMCACHED)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBMEMCACHED_LOCAL
-void libmemcached_free(memcached_st *ptr, void *mem);
-LIBMEMCACHED_LOCAL
-void *libmemcached_malloc(memcached_st *ptr, const size_t size);
-LIBMEMCACHED_LOCAL
-void *libmemcached_realloc(memcached_st *ptr, void *mem, const size_t size);
-LIBMEMCACHED_LOCAL
-void *libmemcached_calloc(memcached_st *ptr, size_t nelem, size_t size);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* BUILDING_LIBMEMCACHED */
-#endif /* LIBMEMCACHED_MEMCACHED_INTERNAL_H */
diff --git a/libmemcached/memcached_io.c b/libmemcached/memcached_io.c
deleted file mode 100644 (file)
index fdcdfdd..0000000
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
-  Basic socket buffered IO
-*/
-
-#include "common.h"
-#include "memcached_io.h"
-#include <sys/select.h>
-#include <poll.h>
-
-typedef enum {
-  MEM_READ,
-  MEM_WRITE
-} memc_read_or_write;
-
-static ssize_t io_flush(memcached_server_st *ptr, memcached_return *error);
-static void increment_udp_message_id(memcached_server_st *ptr);
-
-static memcached_return io_wait(memcached_server_st *ptr,
-                                memc_read_or_write read_or_write)
-{
-  struct pollfd fds= {
-     .fd= ptr->fd,
-     .events = POLLIN
-  };
-  int error;
-
-  unlikely (read_or_write == MEM_WRITE) /* write */
-    fds.events= POLLOUT;
-
-  /*
-  ** 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 rc= memcached_purge(ptr);
-    if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
-      return MEMCACHED_FAILURE;
-  }
-
-  int timeout= ptr->root->poll_timeout;
-  if ((ptr->root->flags & MEM_NO_BLOCK) == 0)
-    timeout= -1;
-
-  error= poll(&fds, 1, timeout);
-
-  if (error == 1)
-    return MEMCACHED_SUCCESS;
-  else if (error == 0)
-    return MEMCACHED_TIMEOUT;
-
-  /* Imposssible for anything other then -1 */
-  WATCHPOINT_ASSERT(error == -1);
-  memcached_quit_server(ptr, 1);
-
-  return MEMCACHED_FAILURE;
-}
-
-/**
- * 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_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= read(ptr->fd,
-                     ptr->read_ptr + ptr->read_data_length,
-                     MEMCACHED_MAX_BUFFER - ptr->read_data_length);
-
-    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_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 & MEM_USE_UDP) == 0)
-  {
-    /*
-     * We might have responses... try to read them out and fire
-     * callbacks
-     */
-    memcached_callback_st cb= *ptr->root->callbacks;
-
-    char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-    memcached_return error;
-    error= memcached_response(ptr, buffer, sizeof(buffer),
-                              &ptr->root->result);
-    if (error == MEMCACHED_SUCCESS)
-    {
-      for (unsigned int x= 0; x < cb.number_of_callback; x++)
-      {
-        error= (*cb.callback[x])(ptr->root, &ptr->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;
-}
-
-#ifdef TCP_CORK
-  #define CORK TCP_CORK
-#elif defined TCP_NOPUSH
-  #define CORK TCP_NOPUSH
-#endif
-
-static void memcached_io_cork(memcached_server_st *ptr, int enable)
-{
-  #ifdef CORK
-  if (ptr->type != MEMCACHED_CONNECTION_TCP)
-    return;
-
-  if ((enable && ptr->is_corked) || (!enable && !ptr->is_corked))
-    return;
-
-  int err= setsockopt(ptr->fd, IPPROTO_TCP, CORK,
-                      &enable, (socklen_t)sizeof(int));
-  if (!err)
-    ptr->is_corked= enable;
-  #endif
-}
-
-#ifdef UNUSED
-void memcached_io_preread(memcached_st *ptr)
-{
-  unsigned int x;
-
-  return;
-
-  for (x= 0; x < ptr->number_of_hosts; x++)
-  {
-    if (memcached_server_response_count(ptr, x) &&
-        ptr->hosts[x].read_data_length < MEMCACHED_MAX_BUFFER )
-    {
-      size_t data_read;
-
-      data_read= read(ptr->hosts[x].fd,
-                      ptr->hosts[x].read_ptr + ptr->hosts[x].read_data_length,
-                      MEMCACHED_MAX_BUFFER - ptr->hosts[x].read_data_length);
-      if (data_read == -1)
-        continue;
-
-      ptr->hosts[x].read_buffer_length+= data_read;
-      ptr->hosts[x].read_data_length+= data_read;
-    }
-  }
-}
-#endif
-
-memcached_return memcached_io_read(memcached_server_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= read(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER);
-        if (data_read > 0)
-          break;
-        else if (data_read == -1)
-        {
-          ptr->cached_errno= errno;
-          memcached_return rc= MEMCACHED_UNKNOWN_READ_FAILURE;
-          switch (errno)
-          {
-          case EAGAIN:
-          case EINTR:
-            if ((rc= io_wait(ptr, MEM_READ)) == MEMCACHED_SUCCESS)
-              continue;
-          /* fall through */
-
-          default:
-            {
-              memcached_quit_server(ptr, 1);
-              *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.
-          */
-          memcached_quit_server(ptr, 1);
-          *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;
-}
-
-ssize_t memcached_io_write(memcached_server_st *ptr,
-                           const void *buffer, size_t length, char with_flush)
-{
-  size_t original_length;
-  const char* buffer_ptr;
-
-  WATCHPOINT_ASSERT(ptr->fd != -1);
-
-  original_length= length;
-  buffer_ptr= buffer;
-
-  /* more writable data is coming if a flush isn't required, so delay send */
-  if (!with_flush)
-    memcached_io_cork(ptr, 1);
-
-  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 rc;
-      ssize_t sent_length;
-
-      WATCHPOINT_ASSERT(ptr->fd != -1);
-      sent_length= io_flush(ptr, &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 rc;
-    WATCHPOINT_ASSERT(ptr->fd != -1);
-    if (io_flush(ptr, &rc) == -1)
-      return -1;
-    memcached_io_cork(ptr, 0);
-  }
-
-  return (ssize_t) original_length;
-}
-
-memcached_return memcached_io_close(memcached_server_st *ptr)
-{
-  int r;
-
-  if (ptr->fd == -1)
-    return MEMCACHED_SUCCESS;
-
-  /* in case of death shutdown to avoid blocking at close() */
-  if (1)
-  {
-    r= shutdown(ptr->fd, SHUT_RDWR);
-
-#ifdef DEBUG
-    if (r && errno != ENOTCONN)
-    {
-      WATCHPOINT_NUMBER(ptr->fd);
-      WATCHPOINT_ERRNO(errno);
-      WATCHPOINT_ASSERT(errno);
-    }
-#endif
-  }
-
-  r= close(ptr->fd);
-#ifdef DEBUG
-  if (r != 0)
-    WATCHPOINT_ERRNO(errno);
-#endif
-
-  return MEMCACHED_SUCCESS;
-}
-
-memcached_server_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 (unsigned int x= 0;
-       x< memc->number_of_hosts && host_index < MAX_SERVERS_TO_POLL;
-       ++x)
-  {
-    if (memc->hosts[x].read_buffer_length > 0) /* I have data in the buffer */
-      return &memc->hosts[x];
-
-    if (memcached_server_response_count(&memc->hosts[x]) > 0)
-    {
-      fds[host_index].events = POLLIN;
-      fds[host_index].revents = 0;
-      fds[host_index].fd = memc->hosts[x].fd;
-      ++host_index;
-    }
-  }
-
-  if (host_index < 2)
-  {
-    /* We have 0 or 1 server with pending events.. */
-    for (unsigned int x= 0; x< memc->number_of_hosts; ++x)
-      if (memcached_server_response_count(&memc->hosts[x]) > 0)
-        return &memc->hosts[x];
-
-    return NULL;
-  }
-
-  int err= poll(fds, host_index, memc->poll_timeout);
-  switch (err) {
-  case -1:
-    memc->cached_errno = errno;
-    /* FALLTHROUGH */
-  case 0:
-    break;
-  default:
-    for (unsigned int x= 0; x < host_index; ++x)
-      if (fds[x].revents & POLLIN)
-        for (unsigned int y= 0; y < memc->number_of_hosts; ++y)
-          if (memc->hosts[y].fd == fds[x].fd)
-            return &memc->hosts[y];
-  }
-
-  return NULL;
-}
-
-static ssize_t io_flush(memcached_server_st *ptr,
-                        memcached_return *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 rc;
-     WATCHPOINT_ASSERT(ptr->fd != -1);
-     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 != -1);
-
-  // 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 != -1);
-    WATCHPOINT_ASSERT(write_length > 0);
-    sent_length= 0;
-    if (ptr->type == MEMCACHED_CONNECTION_UDP)
-      increment_udp_message_id(ptr);
-    sent_length= write(ptr->fd, local_write_ptr, write_length);
-
-    if (sent_length == -1)
-    {
-      ptr->cached_errno= errno;
-      switch (errno)
-      {
-      case ENOBUFS:
-        continue;
-      case EAGAIN:
-      {
-        /*
-         * 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 rc;
-        rc= io_wait(ptr, MEM_WRITE);
-
-        if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_TIMEOUT)
-          continue;
-
-        memcached_quit_server(ptr, 1);
-        return -1;
-      }
-      default:
-        memcached_quit_server(ptr, 1);
-        *error= MEMCACHED_ERRNO;
-        return -1;
-      }
-    }
-
-    if (ptr->type == MEMCACHED_CONNECTION_UDP &&
-        (size_t)sent_length != write_length)
-    {
-      memcached_quit_server(ptr, 1);
-      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_st *ptr)
-{
-  memcached_quit_server(ptr, 1);
-}
-
-/**
- * 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 memcached_safe_read(memcached_server_st *ptr,
-                                     void *dta,
-                                     size_t size)
-{
-  size_t offset= 0;
-  char *data= dta;
-
-  while (offset < size)
-  {
-    ssize_t nread;
-    memcached_return 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 memcached_io_readline(memcached_server_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 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_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 memcached_io_init_udp_header(memcached_server_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/memcached_io.h b/libmemcached/memcached_io.h
deleted file mode 100644 (file)
index da25395..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Summary: Server IO, Not public!
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Brian Aker
- */
-
-#ifndef LIBMEMCACHED_MEMCACHED_IO_H
-#define LIBMEMCACHED_MEMCACHED_IO_H
-
-#if defined(BUILDING_LIBMEMCACHED)
-
-#include "libmemcached/memcached.h"
-
-#define MAX_UDP_DATAGRAM_LENGTH 1400
-#define UDP_DATAGRAM_HEADER_LENGTH 8
-#define UDP_REQUEST_ID_MSG_SIG_DIGITS 10
-#define UDP_REQUEST_ID_THREAD_MASK 0xFFFF << UDP_REQUEST_ID_MSG_SIG_DIGITS
-#define get_udp_datagram_request_id(A) ntohs((A)->request_id)
-#define get_udp_datagram_seq_num(A) ntohs((A)->sequence_number)
-#define get_udp_datagram_num_datagrams(A) ntohs((A)->num_datagrams)
-#define get_msg_num_from_request_id(A) ( (A) & (~(UDP_REQUEST_ID_THREAD_MASK)) )
-#define get_thread_id_from_request_id(A) ( (A) & (UDP_REQUEST_ID_THREAD_MASK) ) >> UDP_REQUEST_ID_MSG_SIG_DIGITS
-#define generate_udp_request_thread_id(A) (A) << UDP_REQUEST_ID_MSG_SIG_DIGITS
-#define UDP_REQUEST_ID_MAX_THREAD_ID get_thread_id_from_request_id(0xFFFF)
-
-struct udp_datagram_header_st {
-  uint16_t request_id;
-  uint16_t sequence_number;
-  uint16_t num_datagrams;
-  uint16_t reserved;
-};
-
-ssize_t memcached_io_write(memcached_server_st *ptr,
-                           const void *buffer, size_t length, char with_flush);
-void memcached_io_reset(memcached_server_st *ptr);
-memcached_return memcached_io_read(memcached_server_st *ptr,
-                                   void *buffer, size_t length, ssize_t *nread);
-/* Read a line (terminated by '\n') into the buffer */
-memcached_return memcached_io_readline(memcached_server_st *ptr,
-                                       char *buffer_ptr,
-                                       size_t size);
-memcached_return memcached_io_close(memcached_server_st *ptr);
-/* Read n bytes of data from the server and store them in dta */
-memcached_return memcached_safe_read(memcached_server_st *ptr, 
-                                     void *dta, 
-                                     size_t size);
-/* Read a single response from the server */
-memcached_return memcached_read_one_response(memcached_server_st *ptr,
-                                             char *buffer, size_t buffer_length,
-                                             memcached_result_st *result);
-memcached_return memcached_io_init_udp_header(memcached_server_st *ptr,
-                                              uint16_t thread_id);
-
-memcached_server_st *memcached_io_get_readable_server(memcached_st *memc);
-
-#endif /* BUILDING_LIBMEMCACHED */
-#endif /* LIBMEMCACHED_MEMCACHED_IO_H */
diff --git a/libmemcached/memcached_key.c b/libmemcached/memcached_key.c
deleted file mode 100644 (file)
index 9aac1eb..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#include "common.h"
-
-memcached_return memcached_key_test(const char * const *keys, 
-                                    const size_t *key_length, 
-                                    size_t number_of_keys)
-{
-  uint32_t x;
-  memcached_return 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/memcached_parse.c b/libmemcached/memcached_parse.c
deleted file mode 100644 (file)
index ec695cf..0000000
+++ /dev/null
@@ -1,74 +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_st *memcached_servers_parse(const char *server_strings)
-{
-  char *string;
-  uint32_t port;
-  uint32_t weight;
-  const char *begin_ptr;
-  const char *end_ptr;
-  memcached_server_st *servers= NULL;
-  memcached_return 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;
-    port= 0;
-    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, ':');
-
-    if (ptr)
-    {
-      ptr[0]= 0;
-
-      ptr++;
-
-      port= (uint32_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/memcached_pool.h b/libmemcached/memcached_pool.h
deleted file mode 100644 (file)
index 03fc0e3..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Summary: Connection pool implementation for libmemcached.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Trond Norbye
- */
-
-#ifndef MEMCACHED_POOL_H
-#define MEMCACHED_POOL_H
-
-#include <libmemcached/memcached.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct memcached_pool_st;
-typedef struct memcached_pool_st memcached_pool_st;
-
-LIBMEMCACHED_API
-memcached_pool_st *memcached_pool_create(memcached_st* mmc, uint32_t initial, 
-                                         uint32_t max);
-LIBMEMCACHED_API
-memcached_st* memcached_pool_destroy(memcached_pool_st* pool);
-LIBMEMCACHED_API
-memcached_st* memcached_pool_pop(memcached_pool_st* pool,
-                                 bool block,
-                                 memcached_return* rc);
-LIBMEMCACHED_API
-memcached_return memcached_pool_push(memcached_pool_st* pool, 
-                                     memcached_st* mmc);
-
-LIBMEMCACHED_API
-memcached_return memcached_pool_behavior_set(memcached_pool_st *ptr, memcached_behavior flag, uint64_t data);
-LIBMEMCACHED_API
-memcached_return memcached_pool_behavior_get(memcached_pool_st *ptr, memcached_behavior flag, uint64_t *value);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* MEMCACHED_POOL_H */
diff --git a/libmemcached/memcached_purge.c b/libmemcached/memcached_purge.c
deleted file mode 100644 (file)
index 9e5e31a..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "common.h"
-#include "memcached_io.h"
-#include "memcached_constants.h"
-
-memcached_return memcached_purge(memcached_server_st *ptr)
-{
-  uint32_t x;
-  memcached_return ret= MEMCACHED_SUCCESS;
-
-  if (ptr->root->purging || /* 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.. */
-  ptr->root->purging= 1;
-
-  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, 1) == -1)
-  {
-    ptr->root->purging= 0;
-    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
-     */
-    int32_t timeo= ptr->root->poll_timeout;
-    ptr->root->poll_timeout= 2000;
-
-    result_ptr= memcached_result_create(ptr->root, &result);
-    WATCHPOINT_ASSERT(result_ptr);
-
-    for (x= 0; x < no_msg; x++)
-    {
-      memcached_result_reset(result_ptr);
-      memcached_return 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);
-      }
-    }
-
-    memcached_result_free(result_ptr);
-    ptr->root->poll_timeout= timeo;
-  }
-  ptr->root->purging= 0;
-
-  return ret;
-}
diff --git a/libmemcached/memcached_quit.c b/libmemcached/memcached_quit.c
deleted file mode 100644 (file)
index 8ac76d4..0000000
+++ /dev/null
@@ -1,77 +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, uint8_t io_death)
-{
-  if (ptr->fd != -1)
-  {
-    if (io_death == 0 && ptr->type != MEMCACHED_CONNECTION_UDP)
-    {
-      memcached_return rc;
-      char buffer[MEMCACHED_MAX_BUFFER];
-
-      if (ptr->root->flags & MEM_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), 1);
-      }
-      else
-        rc= memcached_do(ptr, "quit\r\n", 6, 1);
-
-      WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_FETCH_NOTFINISHED);
-
-      /* 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
-       */
-      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= -1;
-    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;
-    memcached_server_response_reset(ptr);
-  }
-
-  if(io_death) ptr->server_failure_counter++;
-}
-
-void memcached_quit(memcached_st *ptr)
-{
-  unsigned int x;
-
-  if (ptr->hosts == NULL ||
-      ptr->number_of_hosts == 0)
-    return;
-
-  if (ptr->hosts && ptr->number_of_hosts)
-  {
-    for (x= 0; x < ptr->number_of_hosts; x++)
-      memcached_quit_server(&ptr->hosts[x], 0);
-  }
-}
diff --git a/libmemcached/memcached_response.c b/libmemcached/memcached_response.c
deleted file mode 100644 (file)
index fe13ddd..0000000
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
-  Memcached library
-
-  memcached_response() is used to determine the return result
-  from an issued command.
-*/
-
-#include "common.h"
-#include "memcached_io.h"
-
-static memcached_return textual_read_one_response(memcached_server_st *ptr,
-                                                  char *buffer, size_t buffer_length,
-                                                  memcached_result_st *result);
-static memcached_return binary_read_one_response(memcached_server_st *ptr,
-                                                 char *buffer, size_t buffer_length,
-                                                 memcached_result_st *result);
-
-memcached_return memcached_read_one_response(memcached_server_st *ptr,
-                                             char *buffer, size_t buffer_length,
-                                             memcached_result_st *result)
-{
-  memcached_server_response_decrement(ptr);
-
-  if (result == NULL)
-    result = &ptr->root->result;
-
-  memcached_return rc;
-  if (ptr->root->flags & MEM_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 memcached_response(memcached_server_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 & MEM_NO_BLOCK)
-    (void)memcached_io_write(ptr, NULL, 0, 1);
-
-  /*
-   * 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 & MEM_BINARY_PROTOCOL) == 0)
-    while (memcached_server_response_count(ptr) > 1)
-    {
-      memcached_return 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 textual_value_fetch(memcached_server_st *ptr,
-                                            char *buffer,
-                                            memcached_result_st *result)
-{
-  memcached_return rc= MEMCACHED_SUCCESS;
-  char *string_ptr;
-  char *end_ptr;
-  char *next_ptr;
-  size_t value_length;
-  size_t to_read;
-  char *value_ptr;
-
-  if (ptr->root->flags & MEM_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->key;
-    result->key_length= 0;
-
-    for (prefix_length= ptr->root->prefix_key_length; !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
-    {
-      if (prefix_length == 0)
-      {
-        *key= *string_ptr;
-        key++;
-        result->key_length++;
-      }
-      else
-        prefix_length--;
-    }
-    result->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->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->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(&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;
-  ssize_t read_length= 0;
-  memcached_return 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(&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 textual_read_one_response(memcached_server_st *ptr,
-                                                  char *buffer, size_t buffer_length,
-                                                  memcached_result_st *result)
-{
-  memcached_return 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);
-      WATCHPOINT_ASSERT(0);
-      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 *)ptr->root->call_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);
-        WATCHPOINT_ASSERT(0);
-        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
-        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
-        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;
-
-      return MEMCACHED_UNKNOWN_READ_FAILURE;
-    }
-  }
-
-  /* NOTREACHED */
-}
-
-char *memcached_result_value(memcached_result_st *ptr)
-{
-  memcached_string_st *sptr= &ptr->value;
-  return memcached_string_value(sptr);
-}
-
-size_t memcached_result_length(memcached_result_st *ptr)
-{
-  memcached_string_st *sptr= &ptr->value;
-  return memcached_string_length(sptr);
-}
-
-static memcached_return binary_read_one_response(memcached_server_st *ptr,
-                                                 char *buffer, size_t buffer_length,
-                                                 memcached_result_st *result)
-{
-  protocol_binary_response_header header;
-   
-  unlikely (memcached_safe_read(ptr, &header.bytes, 
-                                sizeof(header.bytes)) != MEMCACHED_SUCCESS)
-    return MEMCACHED_UNKNOWN_READ_FAILURE;
-
-  unlikely (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 == 0) 
-  {
-    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->cas= header.response.cas;
-
-        if (memcached_safe_read(ptr, &result->flags,
-                                sizeof (result->flags)) != MEMCACHED_SUCCESS)
-          return MEMCACHED_UNKNOWN_READ_FAILURE;
-
-        result->flags= ntohl(result->flags);
-        bodylen -= header.response.extlen;
-
-        result->key_length= keylen;
-        if (memcached_safe_read(ptr, result->key, keylen) != MEMCACHED_SUCCESS) 
-          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(&result->value);
-        if (memcached_safe_read(ptr, vptr, bodylen) != MEMCACHED_SUCCESS) 
-          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 (memcached_safe_read(ptr, &val, sizeof(val)) != MEMCACHED_SUCCESS) 
-          return MEMCACHED_UNKNOWN_READ_FAILURE;
-
-        val= ntohll(val);
-        memcpy(buffer, &val, sizeof(val));
-      } 
-      break;
-    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 (memcached_safe_read(ptr, buffer, bodylen) != MEMCACHED_SUCCESS)
-          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 (memcached_safe_read(ptr, buffer, keylen) != MEMCACHED_SUCCESS ||
-              memcached_safe_read(ptr, buffer + keylen + 1, 
-                                  bodylen - keylen) != MEMCACHED_SUCCESS)
-            return MEMCACHED_UNKNOWN_READ_FAILURE;
-        }
-      } 
-      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 (memcached_safe_read(ptr, hole, nr) != MEMCACHED_SUCCESS)
-        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;
-    }
-  }
-
-  memcached_return 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_EINVAL:
-    case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
-    default:
-      /* @todo fix the error mappings */
-      rc= MEMCACHED_PROTOCOL_ERROR;
-      break;
-    }
-    
-  return rc;
-}
diff --git a/libmemcached/memcached_result.c b/libmemcached/memcached_result.c
deleted file mode 100644 (file)
index 0d77130..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* 
-  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"
-
-memcached_result_st *memcached_result_create(memcached_st *memc, 
-                                             memcached_result_st *ptr)
-{
-  /* Saving malloc calls :) */
-  if (ptr)
-    memset(ptr, 0, sizeof(memcached_result_st));
-  else
-  {
-    ptr= memc->call_malloc(memc, sizeof(memcached_result_st));
-
-    if (ptr == NULL)
-      return NULL;
-    ptr->is_allocated= true;
-  }
-
-  ptr->root= memc;
-  memcached_string_create(memc, &ptr->value, 0);
-  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->flags= 0;
-  ptr->cas= 0;
-  ptr->expiration= 0;
-}
-
-/*
-  NOTE turn into macro
-*/
-memcached_return memcached_result_set_value(memcached_result_st *ptr, const char *value, size_t length)
-{
-  return memcached_string_append(&ptr->value, value, length);
-}
-
-void memcached_result_free(memcached_result_st *ptr)
-{
-  if (ptr == NULL)
-    return;
-
-  memcached_string_free(&ptr->value);
-
-  if (ptr->is_allocated)
-    free(ptr);
-}
diff --git a/libmemcached/memcached_result.h b/libmemcached/memcached_result.h
deleted file mode 100644 (file)
index e7ce012..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Summary: Result structure used for libmemcached.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Brian Aker
- */
-
-#ifndef __MEMCACHED_RESULT_H__
-#define __MEMCACHED_RESULT_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct memcached_result_st {
-  uint32_t flags;
-  bool is_allocated;
-  time_t expiration;
-  memcached_st *root;
-  size_t key_length;
-  uint64_t cas;
-  memcached_string_st value;
-  char key[MEMCACHED_MAX_KEY];
-  /* Add result callback function */
-};
-
-/* Result Struct */
-LIBMEMCACHED_API
-void memcached_result_free(memcached_result_st *result);
-LIBMEMCACHED_API
-void memcached_result_reset(memcached_result_st *ptr);
-LIBMEMCACHED_API
-memcached_result_st *memcached_result_create(memcached_st *ptr, 
-                                             memcached_result_st *result);
-#define memcached_result_key_value(A) (A)->key
-#define memcached_result_key_length(A) (A)->key_length
-#define memcached_result_string_st(A) ((A)->value)
-#ifdef FIX
-#define memcached_result_value(A) memcached_string_value((A)->value)
-#define memcached_result_length(A) memcached_string_length((A)->value)
-#else
-LIBMEMCACHED_API
-char *memcached_result_value(memcached_result_st *ptr);
-LIBMEMCACHED_API
-size_t memcached_result_length(memcached_result_st *ptr);
-#endif
-#define memcached_result_flags(A) (A)->flags
-#define memcached_result_cas(A) (A)->cas
-LIBMEMCACHED_API
-memcached_return memcached_result_set_value(memcached_result_st *ptr, const char *value, size_t length);
-#define memcached_result_set_flags(A,B) (A)->flags=(B)
-#define memcached_result_set_expiration(A,B) (A)->expiration=(B)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MEMCACHED_RESULT_H__ */
diff --git a/libmemcached/memcached_server.c b/libmemcached/memcached_server.c
deleted file mode 100644 (file)
index e45d1c9..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
-  This is a partial implementation for fetching/creating memcached_server_st objects.
-*/
-#include "common.h"
-
-memcached_server_st *memcached_server_create(memcached_st *memc, memcached_server_st *ptr)
-{
-  if (ptr == NULL)
-  {
-    ptr= (memcached_server_st *)calloc(1, sizeof(memcached_server_st));
-
-    if (!ptr)
-      return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
-
-    ptr->is_allocated= true;
-  }
-  else
-    memset(ptr, 0, sizeof(memcached_server_st));
-
-  ptr->root= memc;
-
-  return ptr;
-}
-
-memcached_server_st *memcached_server_create_with(memcached_st *memc, memcached_server_st *host,
-                                                  const char *hostname, unsigned int port,
-                                                  uint32_t weight, memcached_connection type)
-{
-  host= memcached_server_create(memc, host);
-
-  if (host == NULL)
-    return NULL;
-
-  strncpy(host->hostname, hostname, MEMCACHED_MAX_HOST_LENGTH - 1);
-  host->root= memc ? memc : NULL;
-  host->port= port;
-  host->weight= weight;
-  host->fd= -1;
-  host->type= type;
-  host->read_ptr= host->read_buffer;
-  host->is_corked= 0;
-  if (memc)
-    host->next_retry= memc->retry_timeout;
-  if (type == MEMCACHED_CONNECTION_UDP)
-  {
-    host->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
-    memcached_io_init_udp_header(host, 0);
-  }
-
-  return host;
-}
-
-void memcached_server_free(memcached_server_st *ptr)
-{
-  memcached_quit_server(ptr, 0);
-
-  if (ptr->cached_server_error)
-    free(ptr->cached_server_error);
-
-  if (ptr->address_info)
-    freeaddrinfo(ptr->address_info);
-
-  if (ptr->is_allocated)
-    ptr->root->call_free(ptr->root, ptr);
-  else
-    memset(ptr, 0, sizeof(memcached_server_st));
-}
-
-/*
-  If we do not have a valid object to clone from, we toss an error.
-*/
-memcached_server_st *memcached_server_clone(memcached_server_st *clone, memcached_server_st *ptr)
-{
-  memcached_server_st *rv= NULL;
-
-  /* We just do a normal create if ptr is missing */
-  if (ptr == NULL)
-    return NULL;
-
-  rv = memcached_server_create_with(ptr->root, clone,
-                                    ptr->hostname, ptr->port, ptr->weight,
-                                    ptr->type);
-  if (rv != NULL)
-  {
-    rv->cached_errno= ptr->cached_errno;
-    if (ptr->cached_server_error)
-      rv->cached_server_error= strdup(ptr->cached_server_error);
-  }
-
-  return rv;
-
-}
-
-memcached_return memcached_server_cursor(memcached_st *ptr,
-                                         memcached_server_function *callback,
-                                         void *context,
-                                         unsigned int number_of_callbacks)
-{
-  unsigned int y;
-
-  for (y= 0; y < ptr->number_of_hosts; y++)
-  {
-    unsigned int x;
-
-    for (x= 0; x < number_of_callbacks; x++)
-    {
-      unsigned int iferror;
-
-      iferror= (*callback[x])(ptr, &ptr->hosts[y], context);
-
-      if (iferror)
-        continue;
-    }
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-memcached_server_st *memcached_server_by_key(memcached_st *ptr,  const char *key, size_t key_length, memcached_return *error)
-{
-  uint32_t server_key;
-
-  *error= memcached_validate_key_length(key_length,
-                                        ptr->flags & MEM_BINARY_PROTOCOL);
-  unlikely (*error != MEMCACHED_SUCCESS)
-    return NULL;
-
-  unlikely (ptr->number_of_hosts == 0)
-  {
-    *error= MEMCACHED_NO_SERVERS;
-    return NULL;
-  }
-
-  if ((ptr->flags & MEM_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);
-
-  return memcached_server_clone(NULL, &ptr->hosts[server_key]);
-
-}
-
-const char *memcached_server_error(memcached_server_st *ptr)
-{
-  if (ptr)
-    return ptr->cached_server_error;
-  else
-    return NULL;
-}
-
-void memcached_server_error_reset(memcached_server_st *ptr)
-{
-  ptr->cached_server_error[0]= 0;
-}
-
-memcached_server_st *memcached_server_get_last_disconnect(memcached_st *ptr)
-{
-  return ptr->last_disconnected_server;
-}
diff --git a/libmemcached/memcached_server.h b/libmemcached/memcached_server.h
deleted file mode 100644 (file)
index 6d1e376..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Summary: String structure used for libmemcached.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Brian Aker
- */
-
-#ifndef __MEMCACHED_SERVER_H__
-#define __MEMCACHED_SERVER_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct memcached_server_st {
-  bool is_allocated;
-  bool sockaddr_inited;
-  uint16_t count;
-  unsigned int cursor_active;
-  unsigned int port;
-  int cached_errno;
-  int fd;
-  uint32_t io_bytes_sent; /* # bytes sent since last read */
-  uint32_t server_failure_counter;
-  uint32_t weight;
-  uint8_t major_version;
-  uint8_t micro_version;
-  uint8_t minor_version;
-  memcached_connection type;
-  char *read_ptr;
-  char *cached_server_error;
-  size_t read_buffer_length;
-  size_t read_data_length;
-  size_t write_buffer_offset;
-  struct addrinfo *address_info;
-  time_t next_retry;
-  memcached_st *root;
-  uint64_t limit_maxbytes;
-  char read_buffer[MEMCACHED_MAX_BUFFER];
-  char write_buffer[MEMCACHED_MAX_BUFFER];
-  char hostname[MEMCACHED_MAX_HOST_LENGTH];
-  bool is_corked;
-};
-
-#define memcached_server_count(A) (A)->number_of_hosts
-#define memcached_server_name(A,B) (B).hostname
-#define memcached_server_port(A,B) (B).port
-#define memcached_server_list(A) (A)->hosts
-#define memcached_server_response_count(A) (A)->cursor_active
-
-LIBMEMCACHED_API
-memcached_return memcached_server_cursor(memcached_st *ptr,
-                                         memcached_server_function *callback,
-                                         void *context,
-                                         unsigned int number_of_callbacks);
-
-LIBMEMCACHED_API
-memcached_server_st *memcached_server_by_key(memcached_st *ptr,  const char *key,
-                                             size_t key_length, memcached_return *error);
-
-LIBMEMCACHED_API
-const char *memcached_server_error(memcached_server_st *ptr);
-
-LIBMEMCACHED_API
-void memcached_server_error_reset(memcached_server_st *ptr);
-
-/* These should not currently be used by end users */
-/* TODO: Is the above comment valid? If so, how can we unit test these if they
- * aren't exported. If not, we should remove the comment */
-LIBMEMCACHED_API
-memcached_server_st *memcached_server_create(memcached_st *memc, memcached_server_st *ptr);
-
-LIBMEMCACHED_API
-memcached_server_st *memcached_server_create_with(memcached_st *memc, memcached_server_st *host,
-                                                  const char *hostname, unsigned int port,
-                                                  uint32_t weight, memcached_connection type);
-
-LIBMEMCACHED_API
-void memcached_server_free(memcached_server_st *ptr);
-LIBMEMCACHED_API
-memcached_server_st *memcached_server_clone(memcached_server_st *clone, memcached_server_st *ptr);
-LIBMEMCACHED_API
-memcached_analysis_st *memcached_analyze(memcached_st *memc, memcached_stat_st *memc_stat,
-                                         memcached_return *error);
-
-LIBMEMCACHED_API
-memcached_return memcached_server_remove(memcached_server_st *st_ptr);
-
-LIBMEMCACHED_API
-memcached_server_st *memcached_server_get_last_disconnect(memcached_st *ptr);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MEMCACHED_SERVER_H__ */
diff --git a/libmemcached/memcached_stats.c b/libmemcached/memcached_stats.c
deleted file mode 100644 (file)
index 04928f0..0000000
+++ /dev/null
@@ -1,454 +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
-};
-
-
-static memcached_return 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))
-  {
-    WATCHPOINT_STRING(key);
-    return MEMCACHED_UNKNOWN_STAT_KEY;
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-char *memcached_stat_get_value(memcached_st *ptr, memcached_stat_st *memc_stat, 
-                               const char *key, memcached_return *error)
-{
-  char buffer[SMALL_STRING_LEN];
-  int length;
-  char *ret;
-
-  *error= MEMCACHED_SUCCESS;
-
-  if (!memcmp("pid", key, strlen("pid")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pid);
-  else if (!memcmp("uptime", key, strlen("uptime")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->uptime);
-  else if (!memcmp("time", key, strlen("time")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time);
-  else if (!memcmp("version", key, strlen("version")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version);
-  else if (!memcmp("pointer_size", key, strlen("pointer_size")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pointer_size);
-  else if (!memcmp("rusage_user", key, strlen("rusage_user")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds);
-  else if (!memcmp("rusage_system", key, strlen("rusage_system")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds);
-  else if (!memcmp("curr_items", key, strlen("curr_items")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_items);
-  else if (!memcmp("total_items", key, strlen("total_items")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_items);
-  else if (!memcmp("curr_connections", key, strlen("curr_connections")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_connections);
-  else if (!memcmp("total_connections", key, strlen("total_connections")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_connections);
-  else if (!memcmp("connection_structures", key, strlen("connection_structures")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->connection_structures);
-  else if (!memcmp("cmd_get", key, strlen("cmd_get")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get);
-  else if (!memcmp("cmd_set", key, strlen("cmd_set")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set);
-  else if (!memcmp("get_hits", key, strlen("get_hits")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits);
-  else if (!memcmp("get_misses", key, strlen("get_misses")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses);
-  else if (!memcmp("evictions", key, strlen("evictions")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions);
-  else if (!memcmp("bytes_read", key, strlen("bytes_read")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read);
-  else if (!memcmp("bytes_written", key, strlen("bytes_written")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written);
-  else if (!memcmp("bytes", key, strlen("bytes")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes);
-  else if (!memcmp("limit_maxbytes", key, strlen("limit_maxbytes")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes);
-  else if (!memcmp("threads", key, strlen("threads")))
-    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->threads);
-  else
-  {
-    *error= MEMCACHED_NOTFOUND;
-    return NULL;
-  }
-
-  ret= ptr->call_malloc(ptr, (size_t) (length + 1));
-  memcpy(ret, buffer, (size_t) length);
-  ret[length]= '\0';
-
-  return ret;
-}
-
-static memcached_return binary_stats_fetch(memcached_st *ptr,
-                                           memcached_stat_st *memc_stat,
-                                           char *args,
-                                           unsigned int server_key)
-{
-  memcached_return 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);
-      
-    if ((memcached_do(&ptr->hosts[server_key], request.bytes, 
-                      sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
-        (memcached_io_write(&ptr->hosts[server_key], args, len, 1) == -1)) 
-    {
-      memcached_io_reset(&ptr->hosts[server_key]);
-      return MEMCACHED_WRITE_FAILURE;
-    }
-  }
-  else
-  {
-    if (memcached_do(&ptr->hosts[server_key], request.bytes, 
-                     sizeof(request.bytes), 1) != MEMCACHED_SUCCESS) 
-    {
-      memcached_io_reset(&ptr->hosts[server_key]);
-      return MEMCACHED_WRITE_FAILURE;
-    }
-  }
-
-  memcached_server_response_decrement(&ptr->hosts[server_key]);  
-  do 
-  {
-     rc= memcached_response(&ptr->hosts[server_key], buffer, 
-                             sizeof(buffer), NULL);
-     if (rc == MEMCACHED_END)
-        break;
-     
-     unlikely (rc != MEMCACHED_SUCCESS) 
-     {
-        memcached_io_reset(&ptr->hosts[server_key]);
-        return rc;
-     }
-     
-     unlikely((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY)
-     {
-       WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
-       WATCHPOINT_ASSERT(0);
-     }
-  } 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.
-  */
-  ptr->hosts[server_key].cursor_active= 0;
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return ascii_stats_fetch(memcached_st *ptr,
-                                              memcached_stat_st *memc_stat,
-                                              char *args,
-                                              unsigned int server_key)
-{
-  memcached_return rc;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  size_t 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)
-    return MEMCACHED_WRITE_FAILURE;
-
-  rc= memcached_do(&ptr->hosts[server_key], buffer, send_length, 1);
-  if (rc != MEMCACHED_SUCCESS)
-      goto error;
-
-  while (1)
-  {
-    rc= memcached_response(&ptr->hosts[server_key], 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;
-      unlikely((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY)
-      {
-        WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
-        WATCHPOINT_ASSERT(0);
-      }
-    }
-    else
-      break;
-  }
-
-error:
-  if (rc == MEMCACHED_END)
-    return MEMCACHED_SUCCESS;
-  else
-    return rc;
-}
-
-memcached_stat_st *memcached_stat(memcached_st *ptr, char *args, memcached_return *error)
-{
-  unsigned int x;
-  memcached_return rc;
-  memcached_stat_st *stats;
-
-  unlikely (ptr->flags & MEM_USE_UDP)
-  {
-    *error= MEMCACHED_NOT_SUPPORTED;
-    return NULL;
-  }
-
-  stats= ptr->call_calloc(ptr, ptr->number_of_hosts, sizeof(memcached_stat_st));
-
-  if (!stats)
-  {
-    *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-    return NULL;
-  }
-
-  rc= MEMCACHED_SUCCESS;
-  for (x= 0; x < ptr->number_of_hosts; x++)
-  {
-    memcached_return temp_return;
-    
-    if (ptr->flags & MEM_BINARY_PROTOCOL)
-      temp_return= binary_stats_fetch(ptr, stats + x, args, x);
-    else
-      temp_return= ascii_stats_fetch(ptr, stats + x, args, x);
-    
-    if (temp_return != MEMCACHED_SUCCESS)
-      rc= MEMCACHED_SOME_ERRORS;
-  }
-
-  *error= rc;
-  return stats;
-}
-
-memcached_return memcached_stat_servername(memcached_stat_st *memc_stat, char *args, 
-                                           char *hostname, unsigned int port)
-{
-  memcached_return rc;
-  memcached_st memc;
-
-  memcached_create(&memc);
-
-  memcached_server_add(&memc, hostname, port);
-
-  if (memc.flags & MEM_BINARY_PROTOCOL)
-    rc= binary_stats_fetch(&memc, memc_stat, args, 0);
-  else
-    rc= ascii_stats_fetch(&memc, memc_stat, args, 0);
-
-  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(memcached_st *ptr, memcached_stat_st *memc_stat, 
-                                memcached_return *error)
-{
-  (void) memc_stat;
-  char **list;
-  size_t length= sizeof(memcached_stat_keys);
-
-  list= ptr->call_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(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 (ptr)
-    ptr->call_free(ptr, memc_stat);
-  else
-    free(memc_stat);
-}
diff --git a/libmemcached/memcached_storage.c b/libmemcached/memcached_storage.c
deleted file mode 100644 (file)
index ecefc56..0000000
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
-  Memcached library
-
-  memcached_set()
-  memcached_replace()
-  memcached_add()
-
-*/
-#include "common.h"
-#include "memcached_io.h"
-
-typedef enum {
-  SET_OP,
-  REPLACE_OP,
-  ADD_OP,
-  PREPEND_OP,
-  APPEND_OP,
-  CAS_OP,
-} memcached_storage_action;
-
-/* Inline this */
-static const char *storage_op_string(memcached_storage_action 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 memcached_send_binary(memcached_st *ptr,
-                                              const char *master_key, 
-                                              size_t master_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 verb);
-
-static inline memcached_return memcached_send(memcached_st *ptr, 
-                                              const char *master_key, size_t master_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 verb)
-{
-  char to_write;
-  size_t write_length;
-  ssize_t sent_length;
-  memcached_return rc;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  unsigned int server_key;
-
-  WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));
-
-  rc= memcached_validate_key_length(key_length, ptr->flags & MEM_BINARY_PROTOCOL);
-  unlikely (rc != MEMCACHED_SUCCESS)
-    return rc;
-  
-  unlikely (ptr->number_of_hosts == 0)
-    return MEMCACHED_NO_SERVERS;
-
-  if ((ptr->flags & MEM_VERIFY_KEY) && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
-    return MEMCACHED_BAD_KEY_PROVIDED;
-
-  if (ptr->flags & MEM_BINARY_PROTOCOL)
-    return memcached_send_binary(ptr, master_key, master_key_length,
-                                 key, key_length,
-                                 value, value_length, expiration,
-                                 flags, cas, verb);
-
-  server_key= memcached_generate_hash(ptr, master_key, master_key_length);
-
-  if (cas)
-    write_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
-                                    "%s %s%.*s %u %llu %zu %llu%s\r\n", 
-                                    storage_op_string(verb),
-                                    ptr->prefix_key,
-                                    (int)key_length, key, flags, 
-                                    (unsigned long long)expiration, value_length, 
-                                    (unsigned long long)cas,
-                                    (ptr->flags & MEM_NOREPLY) ? " noreply" : "");
-  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) , ptr->prefix_key, strlen(ptr->prefix_key));
-
-    /* Copy in the key, adjust point if a key prefix was used. */
-    buffer_ptr= memcpy(buffer_ptr + (ptr->prefix_key ? strlen(ptr->prefix_key) : 0), 
-                       key, key_length);
-    buffer_ptr+= key_length;
-    buffer_ptr[0]=  ' '; 
-    buffer_ptr++;
-
-    write_length= (size_t)(buffer_ptr - buffer);
-    write_length+= (size_t) snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE, 
-                                     "%u %llu %zu%s\r\n", 
-                                     flags, 
-                                     (unsigned long long)expiration, value_length,
-                                     (ptr->flags & MEM_NOREPLY) ? " noreply" : "");
-  }
-
-  if (ptr->flags & MEM_USE_UDP && ptr->flags & MEM_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 + ptr->hosts[server_key].write_buffer_offset > MAX_UDP_DATAGRAM_LENGTH)
-      memcached_io_write(&ptr->hosts[server_key], NULL, 0, 1);
-  }
-
-  if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
-  {
-    rc= MEMCACHED_WRITE_FAILURE;
-    goto error;
-  }
-
-  /* Send command header */
-  rc=  memcached_do(&ptr->hosts[server_key], buffer, write_length, 0);
-  if (rc != MEMCACHED_SUCCESS)
-    goto error;
-
-  /* Send command body */
-  if ((sent_length= memcached_io_write(&ptr->hosts[server_key], value, value_length, 0)) == -1)
-  {
-    rc= MEMCACHED_WRITE_FAILURE;
-    goto error;
-  }
-
-  if ((ptr->flags & MEM_BUFFER_REQUESTS) && verb == SET_OP)
-    to_write= 0;
-  else
-    to_write= 1;
-
-  if ((sent_length= memcached_io_write(&ptr->hosts[server_key], "\r\n", 2, to_write)) == -1)
-  {
-    rc= MEMCACHED_WRITE_FAILURE;
-    goto error;
-  }
-
-  if (ptr->flags & MEM_NOREPLY)
-    return (to_write == 0) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS;
-
-  if (to_write == 0)
-    return MEMCACHED_BUFFERED;
-
-  rc= memcached_response(&ptr->hosts[server_key], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-
-  if (rc == MEMCACHED_STORED)
-    return MEMCACHED_SUCCESS;
-  else 
-    return rc;
-
-error:
-  memcached_io_reset(&ptr->hosts[server_key]);
-
-  return rc;
-}
-
-
-memcached_return 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 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 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 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 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 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 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 rc;
-  rc= memcached_send(ptr, key, key_length, 
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, PREPEND_OP);
-  return rc;
-}
-
-memcached_return 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 rc;
-  rc= memcached_send(ptr, key, key_length, 
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, APPEND_OP);
-  return rc;
-}
-
-memcached_return 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 rc;
-  rc= memcached_send(ptr, key, key_length, 
-                     key, key_length, value, value_length,
-                     expiration, flags, cas, CAS_OP);
-  return rc;
-}
-
-memcached_return memcached_set_by_key(memcached_st *ptr, 
-                                      const char *master_key __attribute__((unused)), 
-                                      size_t master_key_length __attribute__((unused)), 
-                                      const char *key, size_t key_length, 
-                                      const char *value, size_t value_length, 
-                                      time_t expiration,
-                                      uint32_t flags)
-{
-  memcached_return rc;
-  LIBMEMCACHED_MEMCACHED_SET_START();
-  rc= memcached_send(ptr, master_key, master_key_length, 
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, SET_OP);
-  LIBMEMCACHED_MEMCACHED_SET_END();
-  return rc;
-}
-
-memcached_return memcached_add_by_key(memcached_st *ptr, 
-                                      const char *master_key, size_t master_key_length,
-                                      const char *key, size_t key_length,
-                                      const char *value, size_t value_length, 
-                                      time_t expiration,
-                                      uint32_t flags)
-{
-  memcached_return rc;
-  LIBMEMCACHED_MEMCACHED_ADD_START();
-  rc= memcached_send(ptr, master_key, master_key_length, 
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, ADD_OP);
-  LIBMEMCACHED_MEMCACHED_ADD_END();
-  return rc;
-}
-
-memcached_return memcached_replace_by_key(memcached_st *ptr, 
-                                          const char *master_key, size_t master_key_length,
-                                          const char *key, size_t key_length,
-                                          const char *value, size_t value_length, 
-                                          time_t expiration,
-                                          uint32_t flags)
-{
-  memcached_return rc;
-  LIBMEMCACHED_MEMCACHED_REPLACE_START();
-  rc= memcached_send(ptr, master_key, master_key_length, 
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, REPLACE_OP);
-  LIBMEMCACHED_MEMCACHED_REPLACE_END();
-  return rc;
-}
-
-memcached_return memcached_prepend_by_key(memcached_st *ptr, 
-                                          const char *master_key, size_t master_key_length,
-                                          const char *key, size_t key_length,
-                                          const char *value, size_t value_length, 
-                                          time_t expiration,
-                                          uint32_t flags)
-{
-  memcached_return rc;
-  rc= memcached_send(ptr, master_key, master_key_length, 
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, PREPEND_OP);
-  return rc;
-}
-
-memcached_return memcached_append_by_key(memcached_st *ptr, 
-                                         const char *master_key, size_t master_key_length,
-                                         const char *key, size_t key_length,
-                                         const char *value, size_t value_length, 
-                                         time_t expiration,
-                                         uint32_t flags)
-{
-  memcached_return rc;
-  rc= memcached_send(ptr, master_key, master_key_length, 
-                     key, key_length, value, value_length,
-                     expiration, flags, 0, APPEND_OP);
-  return rc;
-}
-
-memcached_return memcached_cas_by_key(memcached_st *ptr, 
-                                      const char *master_key, size_t master_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 rc;
-  rc= memcached_send(ptr, master_key, master_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 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 memcached_send_binary(memcached_st *ptr,
-                                              const char *master_key, 
-                                              size_t master_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 verb)
-{
-  uint8_t flush;
-  protocol_binary_request_set request= {.bytes= {0}};
-  size_t send_length= sizeof(request.bytes);
-  uint32_t server_key= memcached_generate_hash(ptr, master_key, 
-                                               master_key_length);
-  memcached_server_st *server= &ptr->hosts[server_key];
-  bool noreply= server->root->flags & MEM_NOREPLY;
-
-  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);
-  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 + value_length + 
-                                               request.message.header.request.extlen));
-  
-  if (cas)
-    request.message.header.request.cas= htonll(cas);
-  
-  flush= (uint8_t) (((server->root->flags & MEM_BUFFER_REQUESTS) && verb == SET_OP) ? 0 : 1);
-
-  if ((server->root->flags & MEM_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, 1);
-  }
-  
-  /* write the header */
-  if ((memcached_do(server, (const char*)request.bytes, send_length, 0) != MEMCACHED_SUCCESS) ||
-      (memcached_io_write(server, key, key_length, 0) == -1) ||
-      (memcached_io_write(server, value, value_length, (char) flush) == -1)) 
-  {
-    memcached_io_reset(server);
-    return MEMCACHED_WRITE_FAILURE;
-  }
-
-  unlikely (verb == SET_OP && ptr->number_of_replicas > 0) 
-  {
-    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
-
-    for (uint32_t x= 0; x < ptr->number_of_replicas; x++)
-    {
-      ++server_key;
-      if (server_key == ptr->number_of_hosts)
-        server_key= 0;
-
-      memcached_server_st *srv= &ptr->hosts[server_key];
-      if ((memcached_do(srv, (const char*)request.bytes, 
-                        send_length, 0) != MEMCACHED_SUCCESS) ||
-          (memcached_io_write(srv, key, key_length, 0) == -1) ||
-          (memcached_io_write(srv, value, value_length, (char) flush) == -1))
-        memcached_io_reset(srv);
-      else
-        memcached_server_response_decrement(srv);
-    }
-  }
-
-  if (flush == 0)
-    return MEMCACHED_BUFFERED;
-
-  if (noreply)
-    return MEMCACHED_SUCCESS;
-
-  return memcached_response(server, NULL, 0, NULL);   
-}
-
diff --git a/libmemcached/memcached_storage.h b/libmemcached/memcached_storage.h
deleted file mode 100644 (file)
index 834401a..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Summary: Storage functions for libmemcached
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Brian Aker
- */
-
-#ifndef __MEMCACHED_STORAGE_H__
-#define __MEMCACHED_STORAGE_H__
-
-#include "libmemcached/memcached_types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* All of the functions for adding data to the server */
-LIBMEMCACHED_API
-memcached_return 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);
-LIBMEMCACHED_API
-memcached_return 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);
-LIBMEMCACHED_API
-memcached_return 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);
-LIBMEMCACHED_API
-memcached_return 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);
-LIBMEMCACHED_API
-memcached_return 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);
-LIBMEMCACHED_API
-memcached_return 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);
-
-LIBMEMCACHED_API
-memcached_return memcached_set_by_key(memcached_st *ptr, 
-                                      const char *master_key, size_t master_key_length, 
-                                      const char *key, size_t key_length, 
-                                      const char *value, size_t value_length, 
-                                      time_t expiration,
-                                      uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return memcached_add_by_key(memcached_st *ptr, 
-                                      const char *master_key, size_t master_key_length,
-                                      const char *key, size_t key_length,
-                                      const char *value, size_t value_length, 
-                                      time_t expiration,
-                                      uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return memcached_replace_by_key(memcached_st *ptr, 
-                                          const char *master_key, size_t master_key_length,
-                                          const char *key, size_t key_length,
-                                          const char *value, size_t value_length, 
-                                          time_t expiration,
-                                          uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return memcached_prepend_by_key(memcached_st *ptr, 
-                                          const char *master_key, size_t master_key_length,
-                                          const char *key, size_t key_length,
-                                          const char *value, size_t value_length, 
-                                          time_t expiration,
-                                          uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return memcached_append_by_key(memcached_st *ptr, 
-                                         const char *master_key, size_t master_key_length,
-                                         const char *key, size_t key_length,
-                                         const char *value, size_t value_length, 
-                                         time_t expiration,
-                                         uint32_t flags);
-
-LIBMEMCACHED_API
-memcached_return memcached_cas_by_key(memcached_st *ptr, 
-                                      const char *master_key, size_t master_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);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MEMCACHED_STORAGE_H__ */
diff --git a/libmemcached/memcached_strerror.c b/libmemcached/memcached_strerror.c
deleted file mode 100644 (file)
index 28f55a2..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#include "common.h"
-
-const char *memcached_strerror(memcached_st *ptr __attribute__((unused)), memcached_return rc)
-{
-  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_MAXIMUM_RETURN:
-    return "Gibberish returned!";
-  default:
-    return "Gibberish returned!";
-  }
-}
diff --git a/libmemcached/memcached_string.c b/libmemcached/memcached_string.c
deleted file mode 100644 (file)
index 614343c..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-#include "common.h"
-
-memcached_return memcached_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))) / string->block_size;
-    adjust++;
-
-    new_size= sizeof(char) * (size_t)((adjust * string->block_size) + string->current_size);
-    /* Test for overflow */
-    if (new_size < need)
-      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
-
-    new_value= string->root->call_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+= (string->block_size * adjust);
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-memcached_string_st *memcached_string_create(memcached_st *ptr, memcached_string_st *string, size_t initial_size)
-{
-  memcached_return rc;
-
-  /* Saving malloc calls :) */
-  if (string)
-    memset(string, 0, sizeof(memcached_string_st));
-  else
-  {
-    string= ptr->call_calloc(ptr, 1, sizeof(memcached_string_st));
-
-    if (string == NULL)
-      return NULL;
-    string->is_allocated= true;
-  }
-  string->block_size= MEMCACHED_BLOCK_SIZE;
-  string->root= ptr;
-
-  rc=  memcached_string_check(string, initial_size);
-  if (rc != MEMCACHED_SUCCESS)
-  {
-    ptr->call_free(ptr, string);
-    return NULL;
-  }
-
-  WATCHPOINT_ASSERT(string->string == string->end);
-
-  return string;
-}
-
-memcached_return memcached_string_append_character(memcached_string_st *string, 
-                                                   char character)
-{
-  memcached_return rc;
-
-  rc=  memcached_string_check(string, 1);
-
-  if (rc != MEMCACHED_SUCCESS)
-    return rc;
-
-  *string->end= character;
-  string->end++;
-
-  return MEMCACHED_SUCCESS;
-}
-
-memcached_return memcached_string_append(memcached_string_st *string,
-                                         const char *value, size_t length)
-{
-  memcached_return rc;
-
-  rc= memcached_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= string->root->call_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 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)
-    ptr->root->call_free(ptr->root, ptr->string);
-
-  if (ptr->is_allocated)
-    ptr->root->call_free(ptr->root, ptr);
-  else
-    memset(ptr, 0, sizeof(memcached_string_st));
-}
diff --git a/libmemcached/memcached_string.h b/libmemcached/memcached_string.h
deleted file mode 100644 (file)
index bed1428..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Summary: String structure used for libmemcached.
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Brian Aker
- */
-
-#ifndef __MEMCACHED_STRING_H__
-#define __MEMCACHED_STRING_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct memcached_string_st {
-  memcached_st *root;
-  char *end;
-  char *string;
-  size_t current_size;
-  size_t block_size;
-  bool is_allocated;
-};
-
-#define memcached_string_length(A) (size_t)((A)->end - (A)->string)
-#define memcached_string_set_length(A, B) (A)->end= (A)->string + B
-#define memcached_string_size(A) (A)->current_size
-#define memcached_string_value(A) (A)->string
-
-LIBMEMCACHED_API
-memcached_string_st *memcached_string_create(memcached_st *ptr,
-                                             memcached_string_st *string,
-                                             size_t initial_size);
-LIBMEMCACHED_API
-memcached_return memcached_string_check(memcached_string_st *string, size_t need);
-LIBMEMCACHED_API
-char *memcached_string_c_copy(memcached_string_st *string);
-LIBMEMCACHED_API
-memcached_return memcached_string_append_character(memcached_string_st *string,
-                                                   char character);
-LIBMEMCACHED_API
-memcached_return memcached_string_append(memcached_string_st *string,
-                                         const char *value, size_t length);
-LIBMEMCACHED_API
-memcached_return memcached_string_reset(memcached_string_st *string);
-LIBMEMCACHED_API
-void memcached_string_free(memcached_string_st *string);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MEMCACHED_STRING_H__ */
diff --git a/libmemcached/memcached_types.h b/libmemcached/memcached_types.h
deleted file mode 100644 (file)
index 9d2537d..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Summary: Typpes for libmemcached
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Brian Aker
- */
-
-#ifndef LIBMEMCACHED_MEMCACHED_TYPES_H
-#define LIBMEMCACHED_MEMCACHED_TYPES_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct memcached_st memcached_st;
-typedef struct memcached_stat_st memcached_stat_st;
-typedef struct memcached_analysis_st memcached_analysis_st;
-typedef struct memcached_result_st memcached_result_st;
-typedef struct memcached_string_st memcached_string_st;
-typedef struct memcached_server_st memcached_server_st;
-typedef struct memcached_continuum_item_st memcached_continuum_item_st;
-typedef memcached_return (*memcached_clone_func)(memcached_st *parent, memcached_st *clone);
-typedef memcached_return (*memcached_cleanup_func)(memcached_st *ptr);
-typedef void (*memcached_free_function)(memcached_st *ptr, void *mem);
-typedef void *(*memcached_malloc_function)(memcached_st *ptr, const size_t size);
-typedef void *(*memcached_realloc_function)(memcached_st *ptr, void *mem, const size_t size);
-typedef void *(*memcached_calloc_function)(memcached_st *ptr, size_t nelem, const size_t elsize);
-typedef memcached_return (*memcached_execute_function)(memcached_st *ptr, memcached_result_st *result, void *context);
-typedef memcached_return (*memcached_server_function)(memcached_st *ptr, memcached_server_st *server, void *context);
-typedef memcached_return (*memcached_trigger_key)(memcached_st *ptr,  
-                                                  const char *key, size_t key_length, 
-                                                  memcached_result_st *result);
-typedef memcached_return (*memcached_trigger_delete_key)(memcached_st *ptr,  
-                                                         const char *key, size_t key_length);
-
-typedef memcached_return (*memcached_dump_func)(memcached_st *ptr,  
-                                                const char *key, size_t key_length, void *context);
-
-typedef struct {
-  memcached_execute_function *callback;
-  void *context;
-  unsigned int number_of_callback;
-} memcached_callback_st;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBMEMCACHED_MEMCACHED_TYPES_H */
index 65732c87f438919738c9cfd170b4a19da11a7650..0c2c6777e56136ceabaa030f082943572cd1fb78 100644 (file)
@@ -1,15 +1,20 @@
-/*
- * Summary: interface for libmemcached utility library
- * Description: main include file for libmemcachedutil
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
  *
- * Copy: See Copyright for the status of this software.
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Connection pool library.
  *
  * Author: Trond Norbye
+ *
  */
 
+
 #ifndef MEMCACHED_UTIL_H
 #define MEMCACHED_UTIL_H
 
-#include <libmemcached/memcached_pool.h>
+#include <libmemcached/util/pool.h>
 
 #endif /* MEMCACHED_UTIL_H */
diff --git a/libmemcached/memcached_verbosity.c b/libmemcached/memcached_verbosity.c
deleted file mode 100644 (file)
index fd56316..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "common.h"
-
-memcached_return memcached_verbosity(memcached_st *ptr, unsigned int verbosity)
-{
-  unsigned int x;
-  size_t send_length;
-  memcached_return rc;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-
-  send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
-                                 "verbosity %u\r\n", verbosity);
-  unlikely (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
-    return MEMCACHED_WRITE_FAILURE;
-
-  rc= MEMCACHED_SUCCESS;
-  for (x= 0; x < ptr->number_of_hosts; x++)
-  {
-    memcached_return rrc;
-
-    rrc= memcached_do(&ptr->hosts[x], buffer, send_length, 1);
-    if (rrc != MEMCACHED_SUCCESS)
-    {
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-
-    unlikely (ptr->flags & MEM_USE_UDP)
-      continue;
-
-    rrc= memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-    if (rrc != MEMCACHED_SUCCESS)
-      rc= MEMCACHED_SOME_ERRORS;
-  }
-
-  return rc;
-}
diff --git a/libmemcached/memcached_version.c b/libmemcached/memcached_version.c
deleted file mode 100644 (file)
index 9c070ea..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-#include "common.h"
-
-const char * memcached_lib_version(void) 
-{
-  return LIBMEMCACHED_VERSION_STRING;
-}
-
-static inline memcached_return memcached_version_binary(memcached_st *ptr);
-static inline memcached_return memcached_version_textual(memcached_st *ptr);
-
-memcached_return memcached_version(memcached_st *ptr)
-{
-   if (ptr->flags & MEM_USE_UDP)
-    return MEMCACHED_NOT_SUPPORTED;
-
-   if (ptr->flags & MEM_BINARY_PROTOCOL)
-     return memcached_version_binary(ptr);
-   else
-     return memcached_version_textual(ptr);      
-}
-
-static inline memcached_return memcached_version_textual(memcached_st *ptr)
-{
-  unsigned int x;
-  size_t send_length;
-  memcached_return rc;
-  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
-  char *response_ptr;
-  const char *command= "version\r\n";
-
-  send_length= strlen(command);
-
-  rc= MEMCACHED_SUCCESS;
-  for (x= 0; x < ptr->number_of_hosts; x++)
-  {
-    memcached_return rrc;
-
-    rrc= memcached_do(&ptr->hosts[x], command, send_length, 1);
-    if (rrc != MEMCACHED_SUCCESS)
-    {
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-
-    rrc= memcached_response(&ptr->hosts[x], buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
-    if (rrc != MEMCACHED_SUCCESS)
-    {
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-
-    /* Find the space, and then move one past it to copy version */
-    response_ptr= index(buffer, ' ');
-    response_ptr++;
-
-    ptr->hosts[x].major_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
-    response_ptr= index(response_ptr, '.');
-    response_ptr++;
-    ptr->hosts[x].minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
-    response_ptr= index(response_ptr, '.');
-    response_ptr++;
-    ptr->hosts[x].micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
-  }
-
-  return rc;
-}
-
-static inline memcached_return memcached_version_binary(memcached_st *ptr)
-{
-  memcached_return rc;
-  unsigned int x;
-  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 (x= 0; x < ptr->number_of_hosts; x++) 
-  {
-    memcached_return rrc;
-
-    rrc= memcached_do(&ptr->hosts[x], request.bytes, sizeof(request.bytes), 1);
-    if (rrc != MEMCACHED_SUCCESS) 
-    {
-      memcached_io_reset(&ptr->hosts[x]);
-      rc= MEMCACHED_SOME_ERRORS;
-      continue;
-    }
-  }
-
-  for (x= 0; x < ptr->number_of_hosts; x++) 
-    if (memcached_server_response_count(&ptr->hosts[x]) > 0) 
-    {
-      memcached_return rrc;
-      char buffer[32];
-      char *p;
-
-      rrc= memcached_response(&ptr->hosts[x], buffer, sizeof(buffer), NULL);
-      if (rrc != MEMCACHED_SUCCESS) 
-      {
-        memcached_io_reset(&ptr->hosts[x]);
-        rc= MEMCACHED_SOME_ERRORS;
-        continue;
-      }
-
-      ptr->hosts[x].major_version= (uint8_t)strtol(buffer, &p, 10);
-      ptr->hosts[x].minor_version= (uint8_t)strtol(p + 1, &p, 10);
-      ptr->hosts[x].micro_version= (uint8_t)strtol(p + 1, NULL, 10);
-    }
-
-  return rc;
-}
diff --git a/libmemcached/memcached_watchpoint.h b/libmemcached/memcached_watchpoint.h
deleted file mode 100644 (file)
index dc8045a..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Summary: Localized copy of WATCHPOINT debug symbols
- *
- * Copy: See Copyright for the status of this software.
- *
- * Author: Brian Aker
- */
-
-#ifndef LIBMEMCACHED_MEMCACHED_WATCHPOINT_H
-#define LIBMEMCACHED_MEMCACHED_WATCHPOINT_H
-
-/* Some personal debugging functions */
-#if defined(DEBUG)
-
-#include <assert.h>
-
-#define WATCHPOINT fprintf(stderr, "\nWATCHPOINT %s:%d (%s)\n", __FILE__, __LINE__,__func__);fflush(stdout);
-#define WATCHPOINT_ERROR(A) fprintf(stderr, "\nWATCHPOINT %s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, A));fflush(stdout);
-#define WATCHPOINT_IFERROR(A) if(A != MEMCACHED_SUCCESS)fprintf(stderr, "\nWATCHPOINT %s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, A));fflush(stdout);
-#define WATCHPOINT_STRING(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %s\n", __FILE__, __LINE__,__func__,A);fflush(stdout);
-#define WATCHPOINT_STRING_LENGTH(A,B) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %.*s\n", __FILE__, __LINE__,__func__,(int)B,A);fflush(stdout);
-#define WATCHPOINT_NUMBER(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %zu\n", __FILE__, __LINE__,__func__,(size_t)(A));fflush(stdout);
-#define WATCHPOINT_ERRNO(A) fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %s\n", __FILE__, __LINE__,__func__, strerror(A));fflush(stdout);
-#define WATCHPOINT_ASSERT_PRINT(A,B,C) if(!(A)){fprintf(stderr, "\nWATCHPOINT ASSERT %s:%d (%s) ", __FILE__, __LINE__,__func__);fprintf(stderr, (B),(C));fprintf(stderr,"\n");fflush(stdout);}assert((A));
-#define WATCHPOINT_ASSERT(A) assert((A));
-#else
-#define WATCHPOINT
-#define WATCHPOINT_ERROR(A)
-#define WATCHPOINT_IFERROR(A)
-#define WATCHPOINT_STRING(A)
-#define WATCHPOINT_NUMBER(A)
-#define WATCHPOINT_ERRNO(A)
-#define WATCHPOINT_ASSERT_PRINT(A,B,C)
-#define WATCHPOINT_ASSERT(A)
-
-#endif /* DEBUG */
-
-#endif /* LIBMEMCACHED_MEMCACHED_WATCHPOINT_H */
diff --git a/libmemcached/parse.c b/libmemcached/parse.c
new file mode 100644 (file)
index 0000000..6675b1a
--- /dev/null
@@ -0,0 +1,74 @@
+/* 
+  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_st *memcached_servers_parse(const char *server_strings)
+{
+  char *string;
+  in_port_t port;
+  uint32_t weight;
+  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;
+    port= 0;
+    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, ':');
+
+    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 48782a0c735cf85bc00b9b059b8f5e6c4e2a9b44..1d29798c98d5c5b87a7b1861f3e094d2ab6ce43d 100644 (file)
@@ -3,7 +3,9 @@
 #define LIBMEMCACHED_PROTOCOL_COMMON_H
 
 #include "config.h"
-#include <stdbool.h>
+#if !defined(__cplusplus)
+# include <stdbool.h>
+#endif
 #include <assert.h>
 #include <netinet/in.h>
 
diff --git a/libmemcached/protocol/libmemcachedprotocol.ver b/libmemcached/protocol/libmemcachedprotocol.ver
deleted file mode 100644 (file)
index 0909018..0000000
+++ /dev/null
@@ -1 +0,0 @@
-libmemcachedprotocol_0 { global: *; };
index fe92a2cc1f75632a8121424fdd6476b2d436b283..3e4531bb5307a418e76806e756f8516e399db874 100644 (file)
@@ -1,15 +1,23 @@
-/*
- * Summary: Definition of the callback interface to the protocol handler
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
  *
- * Copy: See Copyright for the status of this software.
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Definition of the callback interface to the protocol handler
  *
  * Author: Trond Norbye
+ *
  */
+
 #ifndef MEMCACHED_PROTOCOL_H
 #define MEMCACHED_PROTOCOL_H
 
 #include <sys/types.h>
-#include <stdbool.h>
+#if !defined(__cplusplus)
+# include <stdbool.h>
+#endif
 
 #include <libmemcached/memcached/protocol_binary.h>
 #include <libmemcached/visibility.h>
diff --git a/libmemcached/purge.c b/libmemcached/purge.c
new file mode 100644 (file)
index 0000000..6780c54
--- /dev/null
@@ -0,0 +1,88 @@
+#include "common.h"
+
+memcached_return_t memcached_purge(memcached_server_instance_st *ptr)
+{
+  uint32_t x;
+  memcached_return_t ret= MEMCACHED_SUCCESS;
+
+  if (ptr->root->options.is_purging || /* 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.. */
+  ptr->root->options.is_purging= 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, 1) == -1)
+  {
+    ptr->root->options.is_purging= 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
+   */
+    int32_t timeo= ptr->root->poll_timeout;
+    ptr->root->poll_timeout= 2000;
+
+    result_ptr= memcached_result_create(ptr->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);
+    ptr->root->poll_timeout= timeo;
+  }
+  ptr->root->options.is_purging= false;
+
+  return ret;
+}
diff --git a/libmemcached/quit.c b/libmemcached/quit.c
new file mode 100644 (file)
index 0000000..c22635a
--- /dev/null
@@ -0,0 +1,87 @@
+#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, uint8_t io_death)
+{
+  if (ptr->fd != -1)
+  {
+    if (io_death == 0 && ptr->type != MEMCACHED_CONNECTION_UDP)
+    {
+      memcached_return_t rc;
+      char buffer[MEMCACHED_MAX_BUFFER];
+
+      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), 1);
+      }
+      else
+      {
+        rc= memcached_do(ptr, "quit\r\n", 6, 1);
+      }
+
+      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
+       */
+      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= -1;
+  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;
+  memcached_server_response_reset(ptr);
+
+  if(io_death)
+  {
+    ptr->server_failure_counter++;
+  }
+}
+
+void memcached_quit(memcached_st *ptr)
+{
+  uint32_t x;
+
+  if (memcached_server_count(ptr) == 0)
+    return;
+
+  if (memcached_server_count(ptr))
+  {
+    for (x= 0; x < memcached_server_count(ptr); x++)
+    {
+      memcached_server_instance_st *instance=
+        memcached_server_instance_fetch(ptr, x);
+
+      memcached_quit_server(instance, 0);
+    }
+  }
+}
diff --git a/libmemcached/response.c b/libmemcached/response.c
new file mode 100644 (file)
index 0000000..f9269e5
--- /dev/null
@@ -0,0 +1,514 @@
+/* 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_instance_st *ptr,
+                                                    char *buffer, size_t buffer_length,
+                                                    memcached_result_st *result);
+static memcached_return_t binary_read_one_response(memcached_server_instance_st *ptr,
+                                                   char *buffer, size_t buffer_length,
+                                                   memcached_result_st *result);
+
+memcached_return_t memcached_read_one_response(memcached_server_instance_st *ptr,
+                                               char *buffer, size_t buffer_length,
+                                               memcached_result_st *result)
+{
+  memcached_server_response_decrement(ptr);
+
+  if (result == NULL)
+    result = &ptr->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_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) && (ptr->root->options.is_processing_input == false))
+  {
+    (void)memcached_io_write(ptr, NULL, 0, 1);
+  }
+
+  /*
+   * 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_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->key;
+    result->key_length= 0;
+
+    for (prefix_length= ptr->root->prefix_key_length; !(iscntrl(*string_ptr) || isspace(*string_ptr)) ; string_ptr++)
+    {
+      if (prefix_length == 0)
+      {
+        *key= *string_ptr;
+        key++;
+        result->key_length++;
+      }
+      else
+        prefix_length--;
+    }
+    result->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->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->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(&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(&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_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);
+      WATCHPOINT_ASSERT(0);
+      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 *)ptr->root->call_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);
+        WATCHPOINT_ASSERT(0);
+        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
+        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
+        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;
+
+      return MEMCACHED_UNKNOWN_READ_FAILURE;
+    }
+  }
+
+  /* NOTREACHED */
+}
+
+static memcached_return_t binary_read_one_response(memcached_server_instance_st *ptr,
+                                                   char *buffer, size_t buffer_length,
+                                                   memcached_result_st *result)
+{
+  protocol_binary_response_header header;
+
+  unlikely (memcached_safe_read(ptr, &header.bytes, 
+                                sizeof(header.bytes)) != MEMCACHED_SUCCESS)
+    return MEMCACHED_UNKNOWN_READ_FAILURE;
+
+  unlikely (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 == 0) 
+  {
+    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->cas= header.response.cas;
+
+        if (memcached_safe_read(ptr, &result->flags,
+                                sizeof (result->flags)) != MEMCACHED_SUCCESS)
+          return MEMCACHED_UNKNOWN_READ_FAILURE;
+
+        result->flags= ntohl(result->flags);
+        bodylen -= header.response.extlen;
+
+        result->key_length= keylen;
+        if (memcached_safe_read(ptr, result->key, keylen) != MEMCACHED_SUCCESS) 
+          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(&result->value);
+        if (memcached_safe_read(ptr, vptr, bodylen) != MEMCACHED_SUCCESS) 
+          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 (memcached_safe_read(ptr, &val, sizeof(val)) != MEMCACHED_SUCCESS) 
+          return MEMCACHED_UNKNOWN_READ_FAILURE;
+
+        val= ntohll(val);
+        memcpy(buffer, &val, sizeof(val));
+      } 
+      break;
+    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 (memcached_safe_read(ptr, buffer, bodylen) != MEMCACHED_SUCCESS)
+          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 (memcached_safe_read(ptr, buffer, keylen) != MEMCACHED_SUCCESS ||
+              memcached_safe_read(ptr, buffer + keylen + 1, 
+                                  bodylen - keylen) != MEMCACHED_SUCCESS)
+            return MEMCACHED_UNKNOWN_READ_FAILURE;
+        }
+      } 
+      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 (memcached_safe_read(ptr, hole, nr) != MEMCACHED_SUCCESS)
+        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;
+    }
+  }
+
+  memcached_return_t 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_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.h b/libmemcached/response.h
new file mode 100644 (file)
index 0000000..d6168f8
--- /dev/null
@@ -0,0 +1,34 @@
+/* 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: Change the behavior of the memcached connection.
+ *
+ */
+
+#ifndef __MEMCACHED_RESPONSE_H__
+#define __MEMCACHED_RESPONSE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Read a single response from the server */
+LIBMEMCACHED_LOCAL
+memcached_return_t memcached_read_one_response(memcached_server_instance_st *ptr,
+                                               char *buffer, size_t buffer_length,
+                                               memcached_result_st *result);
+
+LIBMEMCACHED_LOCAL
+memcached_return_t memcached_response(memcached_server_instance_st *ptr,
+                                      char *buffer, size_t buffer_length,
+                                      memcached_result_st *result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_RESPONSE_H__ */
diff --git a/libmemcached/result.c b/libmemcached/result.c
new file mode 100644 (file)
index 0000000..03cd4fc
--- /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: 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"
+
+memcached_result_st *memcached_result_create(memcached_st *memc,
+                                             memcached_result_st *ptr)
+{
+  WATCHPOINT_ASSERT(memc && memc->options.is_initialized);
+
+  /* Saving malloc calls :) */
+  if (ptr)
+  {
+    memset(ptr, 0, sizeof(memcached_result_st));
+  }
+  else
+  {
+    ptr= memc->call_calloc(memc, 1, sizeof(memcached_result_st));
+
+    if (ptr == NULL)
+      return NULL;
+    ptr->options.is_allocated= true;
+  }
+
+  ptr->options.is_initialized= true;
+
+  ptr->root= memc;
+  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->flags= 0;
+  ptr->cas= 0;
+  ptr->expiration= 0;
+}
+
+/*
+  NOTE turn into macro
+*/
+memcached_return_t memcached_result_set_value(memcached_result_st *ptr, const char *value, size_t length)
+{
+  return memcached_string_append(&ptr->value, value, length);
+}
+
+void memcached_result_free(memcached_result_st *ptr)
+{
+  if (ptr == NULL)
+    return;
+
+  memcached_string_free(&ptr->value);
+
+  if (memcached_is_allocated(ptr))
+  {
+    if (ptr->root != NULL)
+    {
+      ptr->root->call_free(ptr->root, ptr);
+    }
+    else
+    {
+      free(ptr);
+    }
+  }
+  else
+  {
+    ptr->options.is_initialized= false;
+  }
+}
+
+
+char *memcached_result_value(memcached_result_st *ptr)
+{
+  memcached_string_st *sptr= &ptr->value;
+  return memcached_string_value(sptr);
+}
+
+size_t memcached_result_length(memcached_result_st *ptr)
+{
+  memcached_string_st *sptr= &ptr->value;
+  return memcached_string_length(sptr);
+}
+
diff --git a/libmemcached/result.h b/libmemcached/result.h
new file mode 100644 (file)
index 0000000..c685984
--- /dev/null
@@ -0,0 +1,68 @@
+/* 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.
+ *
+ */
+
+#ifndef __MEMCACHED_RESULT_H__
+#define __MEMCACHED_RESULT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct memcached_result_st {
+  struct {
+    bool is_allocated:1;
+    bool is_initialized:1;
+  } options;
+  uint32_t flags;
+  time_t expiration;
+  memcached_st *root;
+  size_t key_length;
+  uint64_t cas;
+  memcached_string_st value;
+  char key[MEMCACHED_MAX_KEY];
+  /* Add result callback function */
+};
+
+/* Result Struct */
+LIBMEMCACHED_API
+void memcached_result_free(memcached_result_st *result);
+LIBMEMCACHED_API
+void memcached_result_reset(memcached_result_st *ptr);
+LIBMEMCACHED_API
+memcached_result_st *memcached_result_create(memcached_st *ptr,
+                                             memcached_result_st *result);
+#define memcached_result_key_value(A) (A)->key
+#define memcached_result_key_length(A) (A)->key_length
+#define memcached_result_string_st(A) ((A)->value)
+#ifdef FIX
+#define memcached_result_value(A) memcached_string_value((A)->value)
+#define memcached_result_length(A) memcached_string_length((A)->value)
+#else
+
+LIBMEMCACHED_API
+char *memcached_result_value(memcached_result_st *ptr);
+
+LIBMEMCACHED_API
+size_t memcached_result_length(memcached_result_st *ptr);
+
+#endif
+#define memcached_result_flags(A) (A)->flags
+#define memcached_result_cas(A) (A)->cas
+LIBMEMCACHED_API
+memcached_return_t memcached_result_set_value(memcached_result_st *ptr, const char *value, size_t length);
+#define memcached_result_set_flags(A,B) (A)->flags=(B)
+#define memcached_result_set_expiration(A,B) (A)->expiration=(B)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_RESULT_H__ */
diff --git a/libmemcached/server.c b/libmemcached/server.c
new file mode 100644 (file)
index 0000000..f61f572
--- /dev/null
@@ -0,0 +1,195 @@
+/* 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 "common.h"
+
+memcached_server_st *memcached_server_create(memcached_st *memc, memcached_server_st *ptr)
+{
+  if (ptr == NULL)
+  {
+    ptr= (memcached_server_st *)memc->call_calloc(memc, 1, sizeof(memcached_server_st));
+
+    if (!ptr)
+      return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
+
+    ptr->options.is_allocated= true;
+  }
+  else
+  {
+    memset(ptr, 0, sizeof(memcached_server_st));
+  }
+
+  ptr->root= memc;
+
+  return ptr;
+}
+
+memcached_server_st *memcached_server_create_with(memcached_st *memc, memcached_server_st *host,
+                                                  const char *hostname, in_port_t port,
+                                                  uint32_t weight, memcached_connection_t type)
+{
+  host= memcached_server_create(memc, host);
+
+  if (host == NULL)
+    return NULL;
+
+  strncpy(host->hostname, hostname, MEMCACHED_MAX_HOST_LENGTH - 1);
+  host->root= memc ? memc : NULL;
+  host->port= port;
+  host->weight= weight;
+  host->fd= -1;
+  host->type= type;
+  host->read_ptr= host->read_buffer;
+  host->state.is_corked= 0;
+  if (memc)
+    host->next_retry= memc->retry_timeout;
+  if (type == MEMCACHED_CONNECTION_UDP)
+  {
+    host->write_buffer_offset= UDP_DATAGRAM_HEADER_LENGTH;
+    memcached_io_init_udp_header(host, 0);
+  }
+
+  return host;
+}
+
+void memcached_server_free(memcached_server_st *ptr)
+{
+  memcached_quit_server(ptr, 0);
+
+  if (ptr->cached_server_error)
+    free(ptr->cached_server_error);
+
+  if (ptr->address_info)
+    freeaddrinfo(ptr->address_info);
+
+
+  if (memcached_is_allocated(ptr))
+  {
+    ptr->root->call_free(ptr->root, ptr);
+  }
+  else
+  {
+    memset(ptr, 0, sizeof(memcached_server_st));
+  }
+}
+
+/*
+  If we do not have a valid object to clone from, we toss an error.
+*/
+memcached_server_st *memcached_server_clone(memcached_server_st *clone, memcached_server_st *ptr)
+{
+  memcached_server_st *rv= NULL;
+
+  /* We just do a normal create if ptr is missing */
+  if (ptr == NULL)
+    return NULL;
+
+  rv= memcached_server_create_with(ptr->root, clone,
+                                   ptr->hostname, ptr->port, ptr->weight,
+                                   ptr->type);
+  if (rv != NULL)
+  {
+    rv->cached_errno= ptr->cached_errno;
+    if (ptr->cached_server_error)
+      rv->cached_server_error= strdup(ptr->cached_server_error);
+  }
+
+  return rv;
+
+}
+
+memcached_return_t memcached_server_cursor(memcached_st *ptr,
+                                           memcached_server_fn *callback,
+                                           void *context,
+                                           uint32_t number_of_callbacks)
+{
+  uint32_t y;
+
+  for (y= 0; y < memcached_server_count(ptr); y++)
+  {
+    uint32_t x;
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(ptr, y);
+
+    for (x= 0; x < number_of_callbacks; x++)
+    {
+      unsigned int iferror;
+
+      iferror= (*callback[x])(ptr, instance, context);
+
+      if (iferror)
+        continue;
+    }
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+memcached_server_st *memcached_server_by_key(memcached_st *ptr,  const char *key, size_t key_length, memcached_return_t *error)
+{
+  uint32_t server_key;
+  memcached_server_instance_st *instance;
+
+  *error= memcached_validate_key_length(key_length,
+                                        ptr->flags.binary_protocol);
+  unlikely (*error != MEMCACHED_SUCCESS)
+    return NULL;
+
+  unlikely (memcached_server_count(ptr) == 0)
+  {
+    *error= MEMCACHED_NO_SERVERS;
+    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_fetch(ptr, server_key);
+
+  return memcached_server_clone(NULL, instance);
+
+}
+
+const char *memcached_server_error(memcached_server_st *ptr)
+{
+  return ptr 
+    ?  ptr->cached_server_error
+    : NULL;
+}
+
+void memcached_server_error_reset(memcached_server_st *ptr)
+{
+  ptr->cached_server_error[0]= 0;
+}
+
+memcached_server_st *memcached_server_get_last_disconnect(memcached_st *ptr)
+{
+  return ptr->last_disconnected_server;
+}
+
+uint32_t memcached_server_list_count(memcached_server_st *ptr)
+{
+  return (ptr == NULL)
+    ? 0
+    : memcached_servers_count(ptr);
+}
+
+void memcached_server_list_free(memcached_server_st *ptr)
+{
+  server_list_free(NULL, ptr);
+}
diff --git a/libmemcached/server.h b/libmemcached/server.h
new file mode 100644 (file)
index 0000000..0051e06
--- /dev/null
@@ -0,0 +1,123 @@
+/* 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.
+ *
+ */
+
+#ifndef __MEMCACHED_SERVER_H__
+#define __MEMCACHED_SERVER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct memcached_server_st {
+  struct {
+    bool is_allocated:1;
+    bool sockaddr_inited:1;
+  } options;
+  uint32_t number_of_hosts;
+  uint32_t cursor_active;
+  in_port_t port;
+  int cached_errno;
+  int fd;
+  uint32_t io_bytes_sent; /* # bytes sent since last read */
+  uint32_t server_failure_counter;
+  uint32_t weight;
+  struct { // Place any "state" sort variables in here.
+    bool is_corked;
+  } state;
+  uint8_t major_version;
+  uint8_t micro_version;
+  uint8_t minor_version;
+  memcached_connection_t type;
+  char *read_ptr;
+  char *cached_server_error;
+  size_t read_buffer_length;
+  size_t read_data_length;
+  size_t write_buffer_offset;
+  struct addrinfo *address_info;
+  time_t next_retry;
+  memcached_st *root;
+  uint64_t limit_maxbytes;
+  char read_buffer[MEMCACHED_MAX_BUFFER];
+  char write_buffer[MEMCACHED_MAX_BUFFER];
+  char hostname[MEMCACHED_MAX_HOST_LENGTH];
+};
+
+// Local Only Inline
+static inline uint32_t memcached_servers_count(memcached_server_st *servers)
+{
+  return servers->number_of_hosts;
+}
+
+// Local Only Inline
+static inline uint32_t memcached_servers_set_count(memcached_server_st *servers, uint32_t count)
+{
+  return servers->number_of_hosts= count;
+}
+
+
+
+#define memcached_server_count(A) (A)->number_of_hosts
+#define memcached_server_name(A,B) (B).hostname
+#define memcached_server_port(A,B) (B).port
+#define memcached_server_list(A) (A)->servers
+#define memcached_server_list_set(A,B) (A)->servers=(B)
+#define memcached_server_response_count(A) (A)->cursor_active
+
+LIBMEMCACHED_API
+memcached_return_t memcached_server_cursor(memcached_st *ptr,
+                                           memcached_server_fn *callback,
+                                           void *context,
+                                           uint32_t number_of_callbacks);
+
+LIBMEMCACHED_API
+memcached_server_st *memcached_server_by_key(memcached_st *ptr,
+                                             const char *key,
+                                             size_t key_length,
+                                             memcached_return_t *error);
+
+LIBMEMCACHED_API
+const char *memcached_server_error(memcached_server_st *ptr);
+
+LIBMEMCACHED_API
+void memcached_server_error_reset(memcached_server_st *ptr);
+
+/* These should not currently be used by end users */
+/* TODO: Is the above comment valid? If so, how can we unit test these if they
+ * aren't exported. If not, we should remove the comment */
+LIBMEMCACHED_LOCAL
+memcached_server_st *memcached_server_create(memcached_st *memc, memcached_server_st *ptr);
+
+LIBMEMCACHED_LOCAL
+memcached_server_st *memcached_server_create_with(memcached_st *memc,
+                                                  memcached_server_st *host,
+                                                  const char *hostname,
+                                                  in_port_t port,
+                                                  uint32_t weight,
+                                                  memcached_connection_t type);
+
+LIBMEMCACHED_API
+void memcached_server_free(memcached_server_st *ptr);
+
+LIBMEMCACHED_LOCAL
+memcached_server_st *memcached_server_clone(memcached_server_st *clone,
+                                            memcached_server_st *ptr);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_server_remove(memcached_server_st *st_ptr);
+
+LIBMEMCACHED_API
+memcached_server_st *memcached_server_get_last_disconnect(memcached_st *ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_SERVER_H__ */
diff --git a/libmemcached/stats.c b/libmemcached/stats.c
new file mode 100644 (file)
index 0000000..cf7f4d6
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+*/
+
+#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
+};
+
+
+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))
+  {
+    WATCHPOINT_STRING(key);
+    return MEMCACHED_UNKNOWN_STAT_KEY;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+char *memcached_stat_get_value(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, strlen("pid")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pid);
+  else if (!memcmp("uptime", key, strlen("uptime")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->uptime);
+  else if (!memcmp("time", key, strlen("time")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time);
+  else if (!memcmp("version", key, strlen("version")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version);
+  else if (!memcmp("pointer_size", key, strlen("pointer_size")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->pointer_size);
+  else if (!memcmp("rusage_user", key, strlen("rusage_user")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds);
+  else if (!memcmp("rusage_system", key, strlen("rusage_system")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u.%u", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds);
+  else if (!memcmp("curr_items", key, strlen("curr_items")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_items);
+  else if (!memcmp("total_items", key, strlen("total_items")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_items);
+  else if (!memcmp("curr_connections", key, strlen("curr_connections")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->curr_connections);
+  else if (!memcmp("total_connections", key, strlen("total_connections")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->total_connections);
+  else if (!memcmp("connection_structures", key, strlen("connection_structures")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->connection_structures);
+  else if (!memcmp("cmd_get", key, strlen("cmd_get")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get);
+  else if (!memcmp("cmd_set", key, strlen("cmd_set")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set);
+  else if (!memcmp("get_hits", key, strlen("get_hits")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits);
+  else if (!memcmp("get_misses", key, strlen("get_misses")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses);
+  else if (!memcmp("evictions", key, strlen("evictions")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions);
+  else if (!memcmp("bytes_read", key, strlen("bytes_read")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read);
+  else if (!memcmp("bytes_written", key, strlen("bytes_written")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written);
+  else if (!memcmp("bytes", key, strlen("bytes")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes);
+  else if (!memcmp("limit_maxbytes", key, strlen("limit_maxbytes")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes);
+  else if (!memcmp("threads", key, strlen("threads")))
+    length= snprintf(buffer, SMALL_STRING_LEN,"%u", memc_stat->threads);
+  else
+  {
+    *error= MEMCACHED_NOTFOUND;
+    return NULL;
+  }
+
+  ret= ptr->call_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,
+                                             char *args,
+                                             memcached_server_instance_st *instance)
+{
+  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);
+
+    if ((memcached_do(instance, request.bytes,
+                      sizeof(request.bytes), 0) != MEMCACHED_SUCCESS) ||
+        (memcached_io_write(instance, args, len, 1) == -1))
+    {
+      memcached_io_reset(instance);
+      return MEMCACHED_WRITE_FAILURE;
+    }
+  }
+  else
+  {
+    if (memcached_do(instance, request.bytes,
+                     sizeof(request.bytes), 1) != 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;
+    }
+
+    unlikely((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY)
+    {
+      WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
+      WATCHPOINT_ASSERT(0);
+    }
+  } 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,
+                                            char *args,
+                                            memcached_server_instance_st *instance)
+{
+  memcached_return_t rc;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+  size_t 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)
+    return MEMCACHED_WRITE_FAILURE;
+
+  rc= memcached_do(instance, buffer, send_length, 1);
+  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;
+      unlikely((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY)
+      {
+        WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
+        WATCHPOINT_ASSERT(0);
+      }
+    }
+    else
+      break;
+  }
+
+error:
+  if (rc == MEMCACHED_END)
+    return MEMCACHED_SUCCESS;
+  else
+    return rc;
+}
+
+memcached_stat_st *memcached_stat(memcached_st *ptr, char *args, memcached_return_t *error)
+{
+  uint32_t x;
+  memcached_return_t rc;
+  memcached_stat_st *stats;
+
+  unlikely (ptr->flags.use_udp)
+  {
+    *error= MEMCACHED_NOT_SUPPORTED;
+    return NULL;
+  }
+
+  stats= ptr->call_calloc(ptr, memcached_server_count(ptr), sizeof(memcached_stat_st));
+
+  stats->root= ptr;
+
+  if (!stats)
+  {
+    *error= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+    return NULL;
+  }
+
+  rc= MEMCACHED_SUCCESS;
+  for (x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_return_t temp_return;
+    memcached_server_instance_st *instance;
+
+    instance= memcached_server_instance_fetch(ptr, x);
+
+    if (ptr->flags.binary_protocol)
+    {
+      temp_return= binary_stats_fetch(stats + x, args, instance);
+    }
+    else
+    {
+      temp_return= ascii_stats_fetch(stats + x, args, instance);
+    }
+
+    if (temp_return != MEMCACHED_SUCCESS)
+      rc= MEMCACHED_SOME_ERRORS;
+  }
+
+  *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_return_t rc;
+  memcached_st memc;
+  memcached_st *memc_ptr;
+  memcached_server_instance_st *instance;
+
+  memc_ptr= memcached_create(&memc);
+  WATCHPOINT_ASSERT(memc_ptr);
+
+  memcached_server_add(&memc, hostname, port);
+
+  instance= memcached_server_instance_fetch(memc_ptr, 0);
+
+  if (memc.flags.binary_protocol)
+  {
+    rc= binary_stats_fetch(memc_stat, args, instance);
+  }
+  else
+  {
+    rc= ascii_stats_fetch(memc_stat, args, instance);
+  }
+
+  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(memcached_st *ptr, memcached_stat_st *memc_stat,
+                                memcached_return_t *error)
+{
+  (void) memc_stat;
+  char **list;
+  size_t length= sizeof(memcached_stat_keys);
+
+  list= ptr->call_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(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)
+  {
+    memc_stat->root->call_free(ptr, memc_stat);
+  }
+  else if (ptr)
+  {
+    ptr->call_free(ptr, memc_stat);
+  }
+  else
+  {
+    free(memc_stat);
+  }
+}
diff --git a/libmemcached/stats.h b/libmemcached/stats.h
new file mode 100644 (file)
index 0000000..4b7d48c
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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: Collect up the stats for a memcached server.
+ *
+ */
+
+#ifndef __MEMCACHED_STATS_H__
+#define __MEMCACHED_STATS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct memcached_stat_st {
+  uint32_t connection_structures;
+  uint32_t curr_connections;
+  uint32_t curr_items;
+  uint32_t pid;
+  uint32_t pointer_size;
+  uint32_t rusage_system_microseconds;
+  uint32_t rusage_system_seconds;
+  uint32_t rusage_user_microseconds;
+  uint32_t rusage_user_seconds;
+  uint32_t threads;
+  uint32_t time;
+  uint32_t total_connections;
+  uint32_t total_items;
+  uint32_t uptime;
+  uint64_t bytes;
+  uint64_t bytes_read;
+  uint64_t bytes_written;
+  uint64_t cmd_get;
+  uint64_t cmd_set;
+  uint64_t evictions;
+  uint64_t get_hits;
+  uint64_t get_misses;
+  uint64_t limit_maxbytes;
+  char version[MEMCACHED_VERSION_STRING_LENGTH];
+  memcached_st *root;
+};
+
+LIBMEMCACHED_API
+void memcached_stat_free(memcached_st *, memcached_stat_st *);
+
+LIBMEMCACHED_API
+memcached_stat_st *memcached_stat(memcached_st *ptr, char *args, memcached_return_t *error);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_stat_servername(memcached_stat_st *memc_stat, char *args,
+                                             const char *hostname, in_port_t port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_STATS_H__ */
diff --git a/libmemcached/storage.c b/libmemcached/storage.c
new file mode 100644 (file)
index 0000000..c0db470
--- /dev/null
@@ -0,0 +1,538 @@
+/* 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,
+                                                const char *master_key,
+                                                size_t master_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);
+
+static inline memcached_return_t memcached_send(memcached_st *ptr,
+                                                const char *master_key, size_t master_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)
+{
+  char to_write;
+  size_t write_length;
+  memcached_return_t rc;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+  uint32_t server_key;
+  memcached_server_instance_st *instance;
+
+  WATCHPOINT_ASSERT(!(value == NULL && value_length > 0));
+
+  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;
+
+  if (ptr->flags.verify_key && (memcached_key_test((const char **)&key, &key_length, 1) == MEMCACHED_BAD_KEY_PROVIDED))
+    return MEMCACHED_BAD_KEY_PROVIDED;
+
+  if (ptr->flags.binary_protocol)
+  {
+    return memcached_send_binary(ptr, master_key, master_key_length,
+                                 key, key_length,
+                                 value, value_length, expiration,
+                                 flags, cas, verb);
+  }
+
+  server_key= memcached_generate_hash(ptr, master_key, master_key_length);
+  instance= memcached_server_instance_fetch(ptr, server_key);
+
+  if (cas)
+  {
+    write_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                                    "%s %s%.*s %u %llu %zu %llu%s\r\n",
+                                    storage_op_string(verb),
+                                    ptr->prefix_key,
+                                    (int)key_length, key, flags,
+                                    (unsigned long long)expiration, value_length,
+                                    (unsigned long long)cas,
+                                    (ptr->flags.no_reply) ? " noreply" : "");
+  }
+  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)), ptr->prefix_key, strlen(ptr->prefix_key));
+
+    /* Copy in the key, adjust point if a key prefix was used. */
+    buffer_ptr= memcpy(buffer_ptr + (ptr->prefix_key ? strlen(ptr->prefix_key) : 0),
+                       key, key_length);
+    buffer_ptr+= key_length;
+    buffer_ptr[0]=  ' ';
+    buffer_ptr++;
+
+    write_length= (size_t)(buffer_ptr - buffer);
+    write_length+= (size_t) snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE,
+                                     "%u %llu %zu%s\r\n",
+                                     flags,
+                                     (unsigned long long)expiration, value_length,
+                                     ptr->flags.no_reply ? " noreply" : "");
+  }
+
+  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, 1);
+  }
+
+  if (write_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
+  {
+    rc= MEMCACHED_WRITE_FAILURE;
+    goto error;
+  }
+
+  /* Send command header */
+  rc=  memcached_do(instance, buffer, write_length, 0);
+  if (rc != MEMCACHED_SUCCESS)
+    goto error;
+
+  /* Send command body */
+  if (memcached_io_write(instance, value, value_length, 0) == -1)
+  {
+    rc= MEMCACHED_WRITE_FAILURE;
+    goto error;
+  }
+
+  if (ptr->flags.buffer_requests && verb == SET_OP)
+  {
+    to_write= 0;
+  }
+  else
+  {
+    to_write= 1;
+  }
+
+  if (memcached_io_write(instance, "\r\n", 2, to_write) == -1)
+  {
+    rc= MEMCACHED_WRITE_FAILURE;
+    goto error;
+  }
+
+  if (ptr->flags.no_reply)
+    return (to_write == 0) ? MEMCACHED_BUFFERED : MEMCACHED_SUCCESS;
+
+  if (to_write == 0)
+    return MEMCACHED_BUFFERED;
+
+  rc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+
+  if (rc == MEMCACHED_STORED)
+    return MEMCACHED_SUCCESS;
+  else
+    return rc;
+
+error:
+  memcached_io_reset(instance);
+
+  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 *master_key __attribute__((unused)),
+                                        size_t master_key_length __attribute__((unused)),
+                                        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, master_key, master_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 *master_key, size_t master_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, master_key, master_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 *master_key, size_t master_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, master_key, master_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 *master_key, size_t master_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, master_key, master_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 *master_key, size_t master_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, master_key, master_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 *master_key, size_t master_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, master_key, master_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,
+                                                const char *master_key,
+                                                size_t master_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)
+{
+  uint8_t flush;
+  protocol_binary_request_set request= {.bytes= {0}};
+  size_t send_length= sizeof(request.bytes);
+  uint32_t server_key= memcached_generate_hash(ptr, master_key,
+                                               master_key_length);
+
+  memcached_server_instance_st *server=
+    memcached_server_instance_fetch(ptr, server_key);
+
+  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);
+  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 + value_length +
+                                                            request.message.header.request.extlen));
+
+  if (cas)
+    request.message.header.request.cas= htonll(cas);
+
+  flush= (uint8_t) ((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, 1);
+    }
+  }
+
+  /* write the header */
+  if ((memcached_do(server, (const char*)request.bytes, send_length, 0) != MEMCACHED_SUCCESS) ||
+      (memcached_io_write(server, key, key_length, 0) == -1) ||
+      (memcached_io_write(server, value, value_length, (char) flush) == -1))
+  {
+    memcached_io_reset(server);
+    return MEMCACHED_WRITE_FAILURE;
+  }
+
+  unlikely (verb == SET_OP && ptr->number_of_replicas > 0)
+  {
+    request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SETQ;
+
+    for (uint32_t x= 0; x < ptr->number_of_replicas; x++)
+    {
+      memcached_server_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_do(instance, (const char*)request.bytes,
+                        send_length, 0) != MEMCACHED_SUCCESS) ||
+          (memcached_io_write(instance, key, key_length, 0) == -1) ||
+          (memcached_io_write(instance, value, value_length, (char) flush) == -1))
+      {
+        memcached_io_reset(instance);
+      }
+      else
+      {
+        memcached_server_response_decrement(instance);
+      }
+    }
+  }
+
+  if (flush == 0)
+  {
+    return MEMCACHED_BUFFERED;
+  }
+
+  if (noreply)
+  {
+    return MEMCACHED_SUCCESS;
+  }
+
+  return memcached_response(server, NULL, 0, NULL);
+}
+
diff --git a/libmemcached/storage.h b/libmemcached/storage.h
new file mode 100644 (file)
index 0000000..8f23396
--- /dev/null
@@ -0,0 +1,110 @@
+/* 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,..
+ *
+ */
+
+#ifndef __MEMCACHED_STORAGE_H__
+#define __MEMCACHED_STORAGE_H__
+
+#include "libmemcached/memcached.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* All of the functions for adding data to the server */
+LIBMEMCACHED_API
+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);
+LIBMEMCACHED_API
+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);
+LIBMEMCACHED_API
+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);
+LIBMEMCACHED_API
+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);
+LIBMEMCACHED_API
+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);
+LIBMEMCACHED_API
+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);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_set_by_key(memcached_st *ptr,
+                                        const char *master_key, size_t master_key_length,
+                                        const char *key, size_t key_length,
+                                        const char *value, size_t value_length,
+                                        time_t expiration,
+                                        uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_add_by_key(memcached_st *ptr,
+                                        const char *master_key, size_t master_key_length,
+                                        const char *key, size_t key_length,
+                                        const char *value, size_t value_length,
+                                        time_t expiration,
+                                        uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_replace_by_key(memcached_st *ptr,
+                                            const char *master_key, size_t master_key_length,
+                                            const char *key, size_t key_length,
+                                            const char *value, size_t value_length,
+                                            time_t expiration,
+                                            uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_prepend_by_key(memcached_st *ptr,
+                                            const char *master_key, size_t master_key_length,
+                                            const char *key, size_t key_length,
+                                            const char *value, size_t value_length,
+                                            time_t expiration,
+                                            uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_append_by_key(memcached_st *ptr,
+                                           const char *master_key, size_t master_key_length,
+                                           const char *key, size_t key_length,
+                                           const char *value, size_t value_length,
+                                           time_t expiration,
+                                           uint32_t flags);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_cas_by_key(memcached_st *ptr,
+                                        const char *master_key, size_t master_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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_STORAGE_H__ */
diff --git a/libmemcached/strerror.c b/libmemcached/strerror.c
new file mode 100644 (file)
index 0000000..f1d651c
--- /dev/null
@@ -0,0 +1,90 @@
+#include "common.h"
+
+const char *memcached_strerror(memcached_st *ptr __attribute__((unused)), memcached_return_t rc)
+{
+  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_MAXIMUM_RETURN:
+    return "Gibberish returned!";
+  default:
+    return "Gibberish returned!";
+  }
+}
diff --git a/libmemcached/string.c b/libmemcached/string.c
new file mode 100644 (file)
index 0000000..615d54f
--- /dev/null
@@ -0,0 +1,171 @@
+/* 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))) / string->block_size;
+    adjust++;
+
+    new_size= sizeof(char) * (size_t)((adjust * string->block_size) + string->current_size);
+    /* Test for overflow */
+    if (new_size < need)
+      return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
+
+    new_value= string->root->call_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+= (string->block_size * adjust);
+  }
+
+  return MEMCACHED_SUCCESS;
+}
+
+memcached_string_st *memcached_string_create(memcached_st *memc, memcached_string_st *string, size_t initial_size)
+{
+  memcached_return_t rc;
+
+  /* Saving malloc calls :) */
+  if (string)
+  {
+    WATCHPOINT_ASSERT(string->options.is_initialized == false);
+
+    memset(string, 0, sizeof(memcached_string_st));
+  }
+  else
+  {
+    string= memc->call_calloc(memc, 1, sizeof(memcached_string_st));
+
+    if (string == NULL)
+    {
+      return NULL;
+    }
+
+    string->options.is_allocated= true;
+  }
+  string->block_size= MEMCACHED_BLOCK_SIZE;
+  string->root= memc;
+
+  rc=  _string_check(string, initial_size);
+  if (rc != MEMCACHED_SUCCESS)
+  {
+    memc->call_free(memc, string);
+    return NULL;
+  }
+
+  string->options.is_initialized= true;
+
+  WATCHPOINT_ASSERT(string->string == string->end);
+
+  return string;
+}
+
+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= string->root->call_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)
+  {
+    ptr->root->call_free(ptr->root, ptr->string);
+  }
+
+  if (memcached_is_allocated(ptr))
+  {
+    ptr->root->call_free(ptr->root, ptr);
+  }
+  else
+  {
+    ptr->options.is_initialized= false;
+    memset(ptr, 0, sizeof(memcached_string_st));
+  }
+}
+
+memcached_return_t memcached_string_check(memcached_string_st *string, size_t need)
+{
+  return _string_check(string, need);
+}
+
diff --git a/libmemcached/string.h b/libmemcached/string.h
new file mode 100644 (file)
index 0000000..9a98726
--- /dev/null
@@ -0,0 +1,62 @@
+/* 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.
+ *
+ */
+
+#ifndef __MEMCACHED_STRING_H__
+#define __MEMCACHED_STRING_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct memcached_string_st {
+  memcached_st *root;
+  char *end;
+  char *string;
+  size_t current_size;
+  size_t block_size;
+  struct {
+    bool is_allocated:1;
+    bool is_initialized:1;
+  } options;
+};
+
+#define memcached_string_length(A) (size_t)((A)->end - (A)->string)
+#define memcached_string_set_length(A, B) (A)->end= (A)->string + B
+#define memcached_string_size(A) (A)->current_size
+#define memcached_string_value(A) (A)->string
+
+LIBMEMCACHED_LOCAL
+memcached_string_st *memcached_string_create(memcached_st *ptr,
+                                             memcached_string_st *string,
+                                             size_t initial_size);
+LIBMEMCACHED_LOCAL
+memcached_return_t memcached_string_check(memcached_string_st *string, size_t need);
+
+LIBMEMCACHED_LOCAL
+char *memcached_string_c_copy(memcached_string_st *string);
+
+LIBMEMCACHED_LOCAL
+memcached_return_t memcached_string_append_character(memcached_string_st *string,
+                                                     char character);
+LIBMEMCACHED_LOCAL
+memcached_return_t memcached_string_append(memcached_string_st *string,
+                                           const char *value, size_t length);
+LIBMEMCACHED_LOCAL
+memcached_return_t memcached_string_reset(memcached_string_st *string);
+
+LIBMEMCACHED_LOCAL
+void memcached_string_free(memcached_string_st *string);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MEMCACHED_STRING_H__ */
diff --git a/libmemcached/types.h b/libmemcached/types.h
new file mode 100644 (file)
index 0000000..e01a47e
--- /dev/null
@@ -0,0 +1,78 @@
+/* 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: Types for libmemcached
+ *
+ */
+
+#ifndef LIBMEMCACHED_MEMCACHED_TYPES_H
+#define LIBMEMCACHED_MEMCACHED_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct memcached_st memcached_st;
+typedef struct memcached_stat_st memcached_stat_st;
+typedef struct memcached_analysis_st memcached_analysis_st;
+typedef struct memcached_result_st memcached_result_st;
+typedef struct memcached_string_st memcached_string_st;
+typedef struct memcached_server_st memcached_server_st;
+typedef struct memcached_continuum_item_st memcached_continuum_item_st;
+typedef memcached_return_t (*memcached_clone_fn)(memcached_st *parent, memcached_st *clone);
+typedef memcached_return_t (*memcached_cleanup_fn)(memcached_st *ptr);
+typedef void (*memcached_free_fn)(memcached_st *ptr, void *mem);
+typedef void *(*memcached_malloc_fn)(memcached_st *ptr, const size_t size);
+typedef void *(*memcached_realloc_fn)(memcached_st *ptr, void *mem, const size_t size);
+typedef void *(*memcached_calloc_fn)(memcached_st *ptr, size_t nelem, const size_t elsize);
+typedef memcached_return_t (*memcached_execute_fn)(memcached_st *ptr, memcached_result_st *result, void *context);
+typedef memcached_return_t (*memcached_server_fn)(memcached_st *ptr, memcached_server_st *server, void *context);
+typedef memcached_return_t (*memcached_trigger_key_fn)(memcached_st *ptr,
+                                                       const char *key, size_t key_length,
+                                                       memcached_result_st *result);
+typedef memcached_return_t (*memcached_trigger_delete_key_fn)(memcached_st *ptr,
+                                                              const char *key, size_t key_length);
+
+typedef memcached_return_t (*memcached_dump_fn)(memcached_st *ptr,
+                                                const char *key,
+                                                size_t key_length,
+                                                void *context);
+
+typedef struct {
+  memcached_execute_fn *callback;
+  void *context;
+  uint32_t number_of_callback;
+} memcached_callback_st;
+
+/**
+  @note The following definitions are just here for backwards compatibility.
+*/
+typedef memcached_return_t memcached_return;
+typedef memcached_server_distribution_t memcached_server_distribution;
+typedef memcached_behavior_t memcached_behavior;
+typedef memcached_callback_t memcached_callback;
+typedef memcached_hash_t memcached_hash;
+typedef memcached_connection_t memcached_connection;
+typedef memcached_clone_fn memcached_clone_func;
+typedef memcached_cleanup_fn memcached_cleanup_func;
+typedef memcached_free_fn memcached_free_function;
+typedef memcached_malloc_fn memcached_malloc_function;
+typedef memcached_realloc_fn memcached_realloc_function;
+typedef memcached_calloc_fn memcached_calloc_function;
+typedef memcached_execute_fn memcached_execute_function;
+typedef memcached_server_fn memcached_server_function;
+typedef memcached_trigger_key_fn memcached_trigger_key;
+typedef memcached_trigger_delete_key_fn memcached_trigger_delete_key;
+typedef memcached_dump_fn memcached_dump_func;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBMEMCACHED_MEMCACHED_TYPES_H */
diff --git a/libmemcached/util/libmemcachedutil.ver b/libmemcached/util/libmemcachedutil.ver
deleted file mode 100644 (file)
index 1a6d501..0000000
+++ /dev/null
@@ -1 +0,0 @@
-libmemcachedutil_0 { global: *; };
diff --git a/libmemcached/util/memcached_pool.c b/libmemcached/util/memcached_pool.c
deleted file mode 100644 (file)
index afc2fee..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#include "libmemcached/common.h"
-#include "libmemcached/memcached_pool.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;
-  char* version;
-};
-
-static memcached_return 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 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 0;
-}
-
-memcached_pool_st *memcached_pool_create(memcached_st* mmc, 
-                                         uint32_t initial, uint32_t max) 
-{
-  memcached_pool_st* ret = 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 };
-
-  if (object.mmc != NULL) 
-  {
-    ret= calloc(1, sizeof(*ret));
-    if (ret == NULL) 
-    {
-      free(object.mmc);
-      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_st*  memcached_pool_destroy(memcached_pool_st* pool) 
-{
-  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);
-  free(pool);
-
-  return ret;
-}
-
-memcached_st* memcached_pool_pop(memcached_pool_st* pool,
-                                 bool block,
-                                 memcached_return *rc) 
-{
-  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 memcached_pool_push(memcached_pool_st* pool, 
-                                     memcached_st *mmc)
-{
-  memcached_return 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 rval= mutex_exit(&pool->mutex);
-  if (rc == MEMCACHED_SOME_ERRORS)
-    return rc;
-
-  return rval;
-}
-
-
-memcached_return memcached_pool_behavior_set(memcached_pool_st *pool, 
-                                             memcached_behavior flag, 
-                                             uint64_t data)
-{
-
-  memcached_return 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 memcached_pool_behavior_get(memcached_pool_st *pool, 
-                                             memcached_behavior flag,
-                                             uint64_t *value)
-{
-  memcached_return 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.c b/libmemcached/util/pool.c
new file mode 100644 (file)
index 0000000..012d550
--- /dev/null
@@ -0,0 +1,257 @@
+/* -*- 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;
+  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 0;
+}
+
+memcached_pool_st *memcached_pool_create(memcached_st* mmc,
+                                         uint32_t initial, uint32_t max)
+{
+  memcached_pool_st* ret = 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 };
+
+  if (object.mmc != NULL)
+  {
+    ret= calloc(1, sizeof(*ret));
+    if (ret == NULL)
+    {
+      free(object.mmc);
+      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_st*  memcached_pool_destroy(memcached_pool_st* pool)
+{
+  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);
+  free(pool);
+
+  return ret;
+}
+
+memcached_st* memcached_pool_pop(memcached_pool_st* pool,
+                                 bool block,
+                                 memcached_return_t *rc)
+{
+  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)
+{
+  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)
+{
+
+  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)
+{
+  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.h b/libmemcached/util/pool.h
new file mode 100644 (file)
index 0000000..b6325f3
--- /dev/null
@@ -0,0 +1,51 @@
+/* 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: Connection pool implementation for libmemcached.
+ *
+ */
+
+
+#ifndef MEMCACHED_POOL_H
+#define MEMCACHED_POOL_H
+
+#include <libmemcached/memcached.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct memcached_pool_st;
+typedef struct memcached_pool_st memcached_pool_st;
+
+LIBMEMCACHED_API
+memcached_pool_st *memcached_pool_create(memcached_st* mmc, uint32_t initial,
+                                         uint32_t max);
+LIBMEMCACHED_API
+memcached_st* memcached_pool_destroy(memcached_pool_st* pool);
+LIBMEMCACHED_API
+memcached_st* memcached_pool_pop(memcached_pool_st* pool,
+                                 bool block,
+                                 memcached_return_t* rc);
+LIBMEMCACHED_API
+memcached_return_t memcached_pool_push(memcached_pool_st* pool,
+                                       memcached_st* mmc);
+
+LIBMEMCACHED_API
+memcached_return_t memcached_pool_behavior_set(memcached_pool_st *ptr,
+                                               memcached_behavior_t flag,
+                                               uint64_t data);
+LIBMEMCACHED_API
+memcached_return_t memcached_pool_behavior_get(memcached_pool_st *ptr,
+                                               memcached_behavior_t flag,
+                                               uint64_t *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEMCACHED_POOL_H */
diff --git a/libmemcached/verbosity.c b/libmemcached/verbosity.c
new file mode 100644 (file)
index 0000000..90a16f7
--- /dev/null
@@ -0,0 +1,38 @@
+#include "common.h"
+
+memcached_return_t memcached_verbosity(memcached_st *ptr, unsigned int verbosity)
+{
+  uint32_t x;
+  size_t send_length;
+  memcached_return_t rc;
+  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
+
+  send_length= (size_t) snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 
+                                 "verbosity %u\r\n", verbosity);
+  unlikely (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE)
+    return MEMCACHED_WRITE_FAILURE;
+
+  rc= MEMCACHED_SUCCESS;
+  for (x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_return_t rrc;
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    rrc= memcached_do(instance, buffer, send_length, 1);
+    if (rrc != MEMCACHED_SUCCESS)
+    {
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+
+    unlikely (ptr->flags.use_udp)
+      continue;
+
+    rrc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+    if (rrc != MEMCACHED_SUCCESS)
+      rc= MEMCACHED_SOME_ERRORS;
+  }
+
+  return rc;
+}
diff --git a/libmemcached/version.c b/libmemcached/version.c
new file mode 100644 (file)
index 0000000..d854efd
--- /dev/null
@@ -0,0 +1,122 @@
+#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;
+
+  if (ptr->flags.binary_protocol)
+    return memcached_version_binary(ptr);
+  else
+    return memcached_version_textual(ptr);      
+}
+
+static inline memcached_return_t memcached_version_textual(memcached_st *ptr)
+{
+  unsigned int x;
+  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= strlen(command);
+
+  rc= MEMCACHED_SUCCESS;
+  for (x= 0; x < memcached_server_count(ptr); x++)
+  {
+    memcached_return_t rrc;
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    rrc= memcached_do(instance, command, send_length, 1);
+    if (rrc != MEMCACHED_SUCCESS)
+    {
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+
+    rrc= memcached_response(instance, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, NULL);
+    if (rrc != MEMCACHED_SUCCESS)
+    {
+      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);
+    response_ptr= index(response_ptr, '.');
+    response_ptr++;
+    instance->minor_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
+    response_ptr= index(response_ptr, '.');
+    response_ptr++;
+    instance->micro_version= (uint8_t)strtol(response_ptr, (char **)NULL, 10);
+  }
+
+  return rc;
+}
+
+static inline memcached_return_t memcached_version_binary(memcached_st *ptr)
+{
+  memcached_return_t rc;
+  unsigned int x;
+  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 (x= 0; x < memcached_server_count(ptr); x++) 
+  {
+    memcached_return_t rrc;
+
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), 1);
+    if (rrc != MEMCACHED_SUCCESS) 
+    {
+      memcached_io_reset(instance);
+      rc= MEMCACHED_SOME_ERRORS;
+      continue;
+    }
+  }
+
+  for (x= 0; x < memcached_server_count(ptr); x++) 
+  {
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(ptr, x);
+
+    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);
+      instance->minor_version= (uint8_t)strtol(p + 1, &p, 10);
+      instance->micro_version= (uint8_t)strtol(p + 1, NULL, 10);
+    }
+  }
+
+  return rc;
+}
index 9405a88d6f8a5267b6d1658af8d7cdff6474484a..6ee385333e057b4ca93ace089c8c72f75b2529b3 100644 (file)
@@ -1,11 +1,14 @@
-/*
- * Summary: interface for memcached server
- * Description: visibitliy macros for libmemcached
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker 
+ * All rights reserved.
  *
  * Use and distribution licensed under the BSD license.  See
- * the COPYING file in this directory for full text.
- * 
- * Author: Monty Taylor
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Interface for memcached server.
+ *
+ * Author: Trond Norbye
+ *
  */
 
 /**
diff --git a/libmemcached/watchpoint.h b/libmemcached/watchpoint.h
new file mode 100644 (file)
index 0000000..a69d391
--- /dev/null
@@ -0,0 +1,45 @@
+/* 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: Localized copy of WATCHPOINT debug symbols
+ *
+ */
+
+#ifndef LIBMEMCACHED_MEMCACHED_WATCHPOINT_H
+#define LIBMEMCACHED_MEMCACHED_WATCHPOINT_H
+
+/* Some personal debugging functions */
+#if defined(DEBUG)
+
+#include <assert.h>
+
+#define WATCHPOINT do { fprintf(stderr, "\nWATCHPOINT %s:%d (%s)\n", __FILE__, __LINE__,__func__);fflush(stdout); } while (0)
+#define WATCHPOINT_ERROR(A) do {fprintf(stderr, "\nWATCHPOINT %s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, A));fflush(stdout); } while (0)
+#define WATCHPOINT_IFERROR(A) do { if(A != MEMCACHED_SUCCESS)fprintf(stderr, "\nWATCHPOINT %s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, A));fflush(stdout); } while (0)
+#define WATCHPOINT_STRING(A) do { fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %s\n", __FILE__, __LINE__,__func__,A);fflush(stdout); } while (0)
+#define WATCHPOINT_STRING_LENGTH(A,B) do { fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %.*s\n", __FILE__, __LINE__,__func__,(int)B,A);fflush(stdout); } while (0)
+#define WATCHPOINT_NUMBER(A) do { fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %zu\n", __FILE__, __LINE__,__func__,(size_t)(A));fflush(stdout); } while (0)
+#define WATCHPOINT_ERRNO(A) do { fprintf(stderr, "\nWATCHPOINT %s:%d (%s) %s\n", __FILE__, __LINE__,__func__, strerror(A));fflush(stdout); } while (0)
+#define WATCHPOINT_ASSERT_PRINT(A,B,C) do { if(!(A)){fprintf(stderr, "\nWATCHPOINT ASSERT %s:%d (%s) ", __FILE__, __LINE__,__func__);fprintf(stderr, (B),(C));fprintf(stderr,"\n");fflush(stdout);}assert((A)); } while (0)
+#define WATCHPOINT_ASSERT(A) assert((A))
+#define WATCHPOINT_ASSERT_INITIALIZED(A) assert(memcached_is_initialized((A)))
+
+#else
+
+#define WATCHPOINT
+#define WATCHPOINT_ERROR(A)
+#define WATCHPOINT_IFERROR(A)
+#define WATCHPOINT_STRING(A)
+#define WATCHPOINT_NUMBER(A)
+#define WATCHPOINT_ERRNO(A)
+#define WATCHPOINT_ASSERT_PRINT(A,B,C)
+#define WATCHPOINT_ASSERT(A)
+#define WATCHPOINT_ASSERT_INITIALIZED(A)
+
+#endif /* DEBUG */
+
+#endif /* LIBMEMCACHED_MEMCACHED_WATCHPOINT_H */
index 7d2c99ba5d2b0e901b4523995b891ec53517922d..4692bbd205c44a9fe3719e4a534169272b10de15 100644 (file)
@@ -1,40 +1,25 @@
 AC_DEFUN([DETECT_BYTEORDER],
 [
-    AC_MSG_CHECKING([for htonll])
-    have_htoll="no"
+    AC_REQUIRE([AC_C_BIGENDIAN])
+    AC_CACHE_CHECK([for htonll],[av_cv_have_htonll],[
+
     AC_RUN_IFELSE([
-       AC_LANG_PROGRAM([
+       AC_LANG_PROGRAM([[
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <inttypes.h>
-       ][
+       ]],[[
           return htonll(0);
-       ])            
+       ]])            
     ], [
-      have_htoll="yes"
-      AC_DEFINE([HAVE_HTONLL], [1], [Have ntohll])
-    ])
+      ac_cv_have_htonll=yes
+    ],[
+      ac_cv_have_htonll=no
+    ])])
 
-    AC_MSG_RESULT([$have_htoll])
-    AM_CONDITIONAL([BUILD_BYTEORDER],[test "x$have_htoll" = "xno"])
-    AC_MSG_CHECKING([byteorder])
-    have_htoll="no"
-    AC_RUN_IFELSE([
-       AC_LANG_PROGRAM([
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <inttypes.h>
-       ], [
-if (htonl(5) != 5) {
-   return 1;
-}
-       ])            
-    ], [
-       AC_MSG_RESULT([big endian])
-       AC_DEFINE([BYTEORDER_BIG_ENDIAN], [1], [Enable big endian byteorder])
-    ], [
-       AC_MSG_RESULT([little endian])
-       AC_DEFINE([BYTEORDER_LITTLE_ENDIAN], [1], [Enable little endian byteorder])
-    ])
+    AS_IF([test "x$ac_cv_have_htonll" = "xyes"],[
+      AC_DEFINE([HAVE_HTONLL], [1], [Have ntohll])])
+
+    AM_CONDITIONAL([BUILD_BYTEORDER],[test "x$ac_cv_have_htonll" = "xno"])
 ])
 
index 0084b43850cde559fe63b9941f54e59ef035e063..576a81ca31abf9d1b9b64d6325bc1cf85a81c99e 100644 (file)
@@ -4,13 +4,23 @@ dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
 dnl Which version of the canonical setup we're using
-AC_DEFUN([PANDORA_CANONICAL_VERSION],[0.62])
+AC_DEFUN([PANDORA_CANONICAL_VERSION],[0.96])
 
 AC_DEFUN([PANDORA_FORCE_DEPEND_TRACKING],[
+  AC_ARG_ENABLE([fat-binaries],
+    [AS_HELP_STRING([--enable-fat-binaries],
+      [Enable fat binary support on OSX @<:@default=off@:>@])],
+    [ac_enable_fat_binaries="$enableval"],
+    [ac_enable_fat_binaries="no"])
+
   dnl Force dependency tracking on for Sun Studio builds
   AS_IF([test "x${enable_dependency_tracking}" = "x"],[
     enable_dependency_tracking=yes
   ])
+  dnl If we're building OSX Fat Binaries, we have to turn off -M options
+  AS_IF([test "x${ac_enable_fat_binaries}" = "xyes"],[
+    enable_dependency_tracking=no
+  ])
 ])
 
 dnl The standard setup for how we build Pandora projects
@@ -24,6 +34,8 @@ AC_DEFUN([PANDORA_CANONICAL_TARGET],[
   m4_define([PCT_IGNORE_SHARED_PTR],[no])
   m4_define([PCT_FORCE_GCC42],[no])
   m4_define([PCT_SRC_IN_SRC],[no])
+  m4_define([PCT_VERSION_FROM_VC],[no])
+  m4_define([PCT_USE_VISIBILITY],[yes])
   m4_foreach([pct_arg],[$*],[
     m4_case(pct_arg,
       [use-gnulib], [
@@ -42,9 +54,17 @@ AC_DEFUN([PANDORA_CANONICAL_TARGET],[
         m4_undefine([PCT_FORCE_GCC42])
         m4_define([PCT_FORCE_GCC42],[yes])
       ],
+      [skip-visibility], [
+        m4_undefine([PCT_USE_VISIBILITY])
+        m4_define([PCT_USE_VISIBILITY],[no])
+      ],
       [src-in-src], [
         m4_undefine([PCT_SRC_IN_SRC])
         m4_define([PCT_SRC_IN_SRC],[yes])
+      ],
+      [version-from-vc], [
+        m4_undefine([PCT_VERSION_FROM_VC])
+        m4_define([PCT_VERSION_FROM_VC],[yes])
     ])
   ])
 
@@ -58,7 +78,7 @@ AC_DEFUN([PANDORA_CANONICAL_TARGET],[
   
   AC_CANONICAL_TARGET
   
-  AM_INIT_AUTOMAKE(-Wall -Werror nostdinc subdir-objects)
+  AM_INIT_AUTOMAKE(-Wall -Werror nostdinc subdir-objects foreign)
   m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 
   m4_if(PCT_USE_GNULIB,yes,[ gl_EARLY ])
@@ -67,6 +87,11 @@ AC_DEFUN([PANDORA_CANONICAL_TARGET],[
   AC_REQUIRE([PANDORA_MAC_GCC42])
   AC_REQUIRE([PANDORA_64BIT])
 
+  m4_if(PCT_VERSION_FROM_VC,yes,[
+    PANDORA_VC_VERSION
+  ])
+  PANDORA_VERSION
+
   dnl Once we can use a modern autoconf, we can use this
   dnl AC_PROG_CC_C99
   AC_REQUIRE([AC_PROG_CXX])
@@ -90,6 +115,7 @@ AC_DEFUN([PANDORA_CANONICAL_TARGET],[
     AS_IF([test "$ac_cv_cxx_stdcxx_98" = "no"],[
       AC_MSG_ERROR([No working C++ Compiler has been found. ${PACKAGE} requires a C++ compiler that can handle C++98])
     ])
+
   ])
   
   PANDORA_SHARED_PTR
@@ -104,6 +130,9 @@ AC_DEFUN([PANDORA_CANONICAL_TARGET],[
     AC_CONFIG_LIBOBJ_DIR([gnulib])
   ])
 
+  PANDORA_CHECK_C_VERSION
+  PANDORA_CHECK_CXX_VERSION
+
   AC_C_BIGENDIAN
   AC_C_CONST
   AC_C_INLINE
@@ -114,17 +143,70 @@ AC_DEFUN([PANDORA_CANONICAL_TARGET],[
   AC_TYPE_SIZE_T
   AC_SYS_LARGEFILE
 
+  # off_t is not a builtin type
+  AC_CHECK_SIZEOF(off_t, 4)
+  AS_IF([test "$ac_cv_sizeof_off_t" -eq 0],[
+    AC_MSG_ERROR("${PACKAGE} needs an off_t type.")
+  ])
+
+  AC_CHECK_SIZEOF(size_t)
+  AS_IF([test "$ac_cv_sizeof_size_t" -eq 0],[
+    AC_MSG_ERROR("${PACKAGE} needs an size_t type.")
+  ])
+
+  AC_DEFINE_UNQUOTED([SIZEOF_SIZE_T],[$ac_cv_sizeof_size_t],[Size of size_t as computed by sizeof()])
+  AC_CHECK_SIZEOF(long long)
+  AC_DEFINE_UNQUOTED([SIZEOF_LONG_LONG],[$ac_cv_sizeof_long_long],[Size of long long as computed by sizeof()])
+  AC_CACHE_CHECK([if time_t is unsigned], [ac_cv_time_t_unsigned],[
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+      [[
+#include <time.h>
+      ]],
+      [[
+      int array[(((time_t)-1) > 0) ? 1 : -1];
+      ]])
+    ],[
+      ac_cv_time_t_unsigned=yes
+    ],[
+      ac_cv_time_t_unsigned=no
+    ])
+  ])
+  AS_IF([test "$ac_cv_time_t_unsigned" = "yes"],[
+    AC_DEFINE([TIME_T_UNSIGNED], 1, [Define to 1 if time_t is unsigned])
+  ])
+
+  dnl AC_FUNC_ALLOCA would test for stack direction if we didn't have a working
+  dnl alloca - but we need to know it anyway for check_stack_overrun.
+  PANDORA_STACK_DIRECTION
+
+  AC_CHECK_FUNC(floorf, [], [AC_CHECK_LIB(m, floorf)])
+  AC_CHECK_FUNC(setsockopt, [], [AC_CHECK_LIB(socket, setsockopt)])
+  AC_CHECK_FUNC(bind, [], [AC_CHECK_LIB(bind, bind)])
+
 
-  PANDORA_CHECK_C_VERSION
-  PANDORA_CHECK_CXX_VERSION
 
   PANDORA_OPTIMIZE
 
-  dnl We need to inject error into the cflags to test if visibility works or not
-  save_CFLAGS="${CFLAGS}"
-  CFLAGS="${CFLAGS} -Werror"
-  gl_VISIBILITY
-  CFLAGS="${save_CFLAGS}"
+  AC_LANG_PUSH(C++)
+  # Test whether madvise() is declared in C++ code -- it is not on some
+  # systems, such as Solaris
+  AC_CHECK_DECLS([madvise], [], [], [AC_INCLUDES_DEFAULT[
+  #if HAVE_SYS_MMAN_H
+  #include <sys/types.h>
+  #include <sys/mman.h>
+  #endif
+  ]])
+  AC_LANG_POP()
+
+  PANDORA_HAVE_GCC_ATOMICS
+
+  m4_if(PCT_USE_VISIBILITY,[yes],[
+    dnl We need to inject error into the cflags to test if visibility works or not
+    save_CFLAGS="${CFLAGS}"
+    CFLAGS="${CFLAGS} -Werror"
+    PANDORA_VISIBILITY
+    CFLAGS="${save_CFLAGS}"
+  ])
 
   PANDORA_HEADER_ASSERT
 
@@ -159,5 +241,6 @@ AC_DEFUN([PANDORA_CANONICAL_TARGET],[
   AC_SUBST([AM_CFLAGS])
   AC_SUBST([AM_CXXFLAGS])
   AC_SUBST([AM_CPPFLAGS])
+  AC_SUBST([AM_LDFLAGS])
 
 ])
index d4189ea0b5ec41abd893e48d1676938712f554cf..6a88a31f3298cd72c534603aa8563944ae8bab3d 100644 (file)
@@ -8,9 +8,16 @@ AC_DEFUN([PANDORA_CHECK_CXX_STANDARD],[
   AS_IF([test "$GCC" = "yes"],
         [AS_IF([test "$ac_cv_cxx_compile_cxx0x_native" = "yes"],[],
                [AS_IF([test "$ac_cv_cxx_compile_cxx0x_gxx" = "yes"],
-                      [CXXFLAGS="-std=gnu++0x ${CXXFLAGS}"],
-                      [CXXFLAGS="-std=gnu++98"])
+                      [CXX_STANDARD="-std=gnu++0x"],
+                      [CXX_STANDARD="-std=gnu++98"])
                ])
         ])
+  AM_CXXFLAGS="${CXX_STANDARD} ${AM_CXXFLAGS}"
+  
+  save_CXXFLAGS="${CXXFLAGS}"
+  CXXFLAGS="${CXXFLAGS} ${CXX_STANDARD}"
   AC_CXX_HEADER_STDCXX_98
+  CXXFLAGS="${save_CXXFLAGS}"
+
+  AC_SUBST([CXX_STANDARD])
 ])
diff --git a/m4/pandora_cinttypes.m4 b/m4/pandora_cinttypes.m4
new file mode 100644 (file)
index 0000000..83a7251
--- /dev/null
@@ -0,0 +1,34 @@
+# We check two things: where the include file is for cinttypes. We
+# include AC_TRY_COMPILE for all the combinations we've seen in the
+# wild.  We define one of HAVE_CINTTYPES or HAVE_TR1_CINTTYPES or 
+# HAVE_BOOST_CINTTYPES depending
+# on location.
+
+AC_DEFUN([PANDORA_CXX_CINTTYPES],
+  [AC_REQUIRE([PANDORA_CXX_CSTDINT])
+   AC_MSG_CHECKING(the location of cinttypes)
+   AC_LANG_PUSH(C++)
+   save_CXXFLAGS="${CXXFLAGS}"
+   CXXFLAGS="${CXX_STANDARD} ${CXXFLAGS}"
+   ac_cv_cxx_cinttypes=""
+   for location in tr1/cinttypes boost/cinttypes cinttypes; do
+     if test -z "$ac_cv_cxx_cinttypes"; then
+       AC_TRY_COMPILE([#include $ac_cv_cxx_cstdint;
+                       #include <$location>],
+                      [uint32_t foo= UINT32_C(1)],
+                      [ac_cv_cxx_cinttypes="<$location>";])
+     fi
+   done
+   AC_LANG_POP()
+   CXXFLAGS="${save_CXXFLAGS}"
+   if test -n "$ac_cv_cxx_cinttypes"; then
+      AC_MSG_RESULT([$ac_cv_cxx_cinttypes])
+   else
+      ac_cv_cxx_cinttypes="<inttypes.h>"
+      AC_MSG_RESULT()
+      AC_MSG_WARN([Could not find a cinttypes header.])
+   fi
+   AC_DEFINE([__STDC_LIMIT_MACROS],[1],[Use STDC Limit Macros in C++])
+   AC_DEFINE_UNQUOTED(CINTTYPES_H,$ac_cv_cxx_cinttypes,
+                      [the location of <cinttypes>])
+])
diff --git a/m4/pandora_cstdint.m4 b/m4/pandora_cstdint.m4
new file mode 100644 (file)
index 0000000..fb6fbac
--- /dev/null
@@ -0,0 +1,33 @@
+# We check two things: where the include file is for cstdint. We
+# include AC_TRY_COMPILE for all the combinations we've seen in the
+# wild.  We define one of HAVE_CSTDINT or HAVE_TR1_CSTDINT or 
+# HAVE_BOOST_CSTDINT depending
+# on location.
+
+AC_DEFUN([PANDORA_CXX_CSTDINT],
+  [AC_MSG_CHECKING(the location of cstdint)
+   AC_LANG_PUSH(C++)
+   save_CXXFLAGS="${CXXFLAGS}"
+   CXXFLAGS="${CXX_STANDARD} ${CXXFLAGS}"
+   ac_cv_cxx_cstdint=""
+   for location in tr1/cstdint boost/cstdint cstdint; do
+     if test -z "$ac_cv_cxx_cstdint"; then
+       AC_TRY_COMPILE([#include <$location>],
+                      [uint32_t t],
+                      [ac_cv_cxx_cstdint="<$location>";])
+     fi
+   done
+   AC_LANG_POP()
+   CXXFLAGS="${save_CXXFLAGS}"
+   if test -n "$ac_cv_cxx_cstdint"; then
+      AC_MSG_RESULT([$ac_cv_cxx_cstdint])
+   else
+      AC_DEFINE([__STDC_CONSTANT_MACROS],[1],[Use STDC Constant Macros in C++])
+      AC_DEFINE([__STDC_FORMAT_MACROS],[1],[Use STDC Format Macros in C++])
+      ac_cv_cxx_cstdint="<stdint.h>"
+      AC_MSG_RESULT()
+      AC_MSG_WARN([Could not find a cstdint header.])
+   fi
+   AC_DEFINE_UNQUOTED(CSTDINT_H,$ac_cv_cxx_cstdint,
+                      [the location of <cstdint>])
+])
diff --git a/m4/pandora_cxx_demangle.m4 b/m4/pandora_cxx_demangle.m4
new file mode 100644 (file)
index 0000000..d2d9ddd
--- /dev/null
@@ -0,0 +1,27 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Check for all of the headers and libs that Drizzle needs. We check all
+dnl of these for plugins too, to ensure that all of the appropriate defines
+dnl are set.
+
+AC_DEFUN([PANDORA_CXX_DEMANGLE],[
+  AC_LANG_PUSH([C++])
+  save_CXXFLAGS="${CXXFLAGS}"
+  CXXFLAGS="${CXX_STANDARD} ${CXXFLAGS}"
+  AC_CHECK_HEADERS(cxxabi.h)
+  AC_CACHE_CHECK([checking for abi::__cxa_demangle], pandora_cv_cxa_demangle,
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <cxxabi.h>]], [[
+    char *foo= 0; int bar= 0;
+    foo= abi::__cxa_demangle(foo, foo, 0, &bar);
+  ]])],[pandora_cv_cxa_demangle=yes],[pandora_cv_cxa_demangle=no])])
+  CXXFLAGS="${save_CXXFLAGS}"
+  AC_LANG_POP()
+
+  AS_IF([test "x$pandora_cv_cxa_demangle" = xyes],[
+    AC_DEFINE(HAVE_ABI_CXA_DEMANGLE, 1,
+              [Define to 1 if you have the `abi::__cxa_demangle' function.])
+  ])
+])
diff --git a/m4/pandora_drizzle_build.m4 b/m4/pandora_drizzle_build.m4
new file mode 100644 (file)
index 0000000..fa132cc
--- /dev/null
@@ -0,0 +1,110 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Check for all of the headers and libs that Drizzle needs. We check all
+dnl of these for plugins too, to ensure that all of the appropriate defines
+dnl are set.
+
+AC_DEFUN([PANDORA_DRIZZLE_BUILD],[
+
+  dnl We need to turn on our CXXFLAGS to make sure it shows up correctly
+  PANDORA_CXX_STL_HASH
+
+  PANDORA_CXX_CSTDINT
+  PANDORA_CXX_CINTTYPES
+
+  AC_STRUCT_TM
+
+  AC_FUNC_ALLOCA
+  AC_FUNC_UTIME_NULL
+  AC_FUNC_VPRINTF
+
+  PANDORA_WORKING_FDATASYNC
+
+  AC_CHECK_FUNCS(\
+    gethrtime \
+    setupterm \
+    backtrace \
+    backtrace_symbols \
+    backtrace_symbols_fd)
+
+  AC_HEADER_STAT
+  AC_HEADER_DIRENT
+  AC_HEADER_STDC
+  AC_HEADER_SYS_WAIT
+  AC_HEADER_STDBOOL
+
+  AC_CHECK_HEADERS(sys/types.h sys/fpu.h fpu_control.h ieeefp.h)
+  AC_CHECK_HEADERS(select.h sys/select.h)
+  AC_CHECK_HEADERS(utime.h sys/utime.h )
+  AC_CHECK_HEADERS(synch.h sys/mman.h sys/socket.h)
+  AC_CHECK_HEADERS(sched.h)
+  AC_CHECK_HEADERS(sys/prctl.h)
+  AC_CHECK_HEADERS(execinfo.h)
+  AC_CHECK_HEADERS(locale.h)
+  AC_CHECK_HEADERS(termcap.h termio.h termios.h asm/termbits.h)
+  AC_CHECK_HEADERS(paths.h)
+
+  
+  #--------------------------------------------------------------------
+  # Check for system libraries. Adds the library to $LIBS
+  # and defines HAVE_LIBM etc
+  #--------------------------------------------------------------------
+  
+    # For the sched_yield() function on Solaris
+  AC_CHECK_FUNC(sched_yield, [],
+    [AC_CHECK_LIB(posix4, [sched_yield],
+      [AC_DEFINE(HAVE_SCHED_YIELD, 1, [Have sched_yield function]) LIBS="$LIBS -lposix4"])])
+  
+  AS_IF([test "$ac_cv_header_termio_h" = "no" -a "$ac_cv_header_termios_h" = "no"],[
+    AC_CHECK_FUNC(gtty, [], [AC_CHECK_LIB(compat, gtty)])
+  ])
+  
+  AC_CHECK_HEADERS([curses.h term.h],[],[],[[
+    #ifdef HAVE_CURSES_H
+    # include <curses.h>
+    #endif
+  ]])
+  AC_CHECK_TYPES([uint, ulong])
+
+  PANDORA_CXX_DEMANGLE
+
+  AH_TOP([
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+#include "config/top.h"
+])
+  mkdir -p config
+  cat > config/top.h.stamp <<EOF_CONFIG_TOP
+
+#if defined(i386) && !defined(__i386__)
+#define __i386__
+#endif
+
+#if defined(_FILE_OFFSET_BITS)
+# undef _FILE_OFFSET_BITS
+#endif
+EOF_CONFIG_TOP
+  diff config/top.h.stamp config/top.h >/dev/null 2>&1 || mv config/top.h.stamp config/top.h
+  rm -f config/top.h.stamp
+
+
+  AH_BOTTOM([
+#if defined(__cplusplus)
+# include CSTDINT_H
+# include CINTTYPES_H
+#else
+# include <stdint.h>
+# include <inttypes.h>
+#endif
+
+#if !defined(HAVE_ULONG) && !defined(__USE_MISC)
+typedef unsigned long int ulong;
+#endif
+
+#endif /* __CONFIG_H__ */
+  ])
+])
diff --git a/m4/pandora_fdatasync.m4 b/m4/pandora_fdatasync.m4
new file mode 100644 (file)
index 0000000..3b9461e
--- /dev/null
@@ -0,0 +1,25 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+#--------------------------------------------------------------------
+# Check for a working fdatasync call
+#--------------------------------------------------------------------
+
+
+AC_DEFUN([PANDORA_WORKING_FDATASYNC],[
+  AC_CACHE_CHECK([working fdatasync],[ac_cv_func_fdatasync],[
+    AC_LANG_PUSH(C++)
+    AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <unistd.h>
+      ]],[[
+fdatasync(4);
+      ]])],
+    [ac_cv_func_fdatasync=yes],
+    [ac_cv_func_fdatasync=no])
+    AC_LANG_POP()
+  ])
+  AS_IF([test "x${ac_cv_func_fdatasync}" = "xyes"],
+    [AC_DEFINE([HAVE_FDATASYNC],[1],[If the system has a working fdatasync])])
+])
\ No newline at end of file
index 18b474806331984b7818a96d8d6e66e970105920..6f46ee9ae802b5308d193cac3cc28ba3539da4ed 100644 (file)
@@ -60,3 +60,9 @@ AC_DEFUN([PANDORA_HAVE_BETTER_MALLOC],[
   AC_SUBST([BETTER_MALLOC_LIBS])
 
 ])
+
+AC_DEFUN([PANDORA_USE_BETTER_MALLOC],[
+  AC_REQUIRE([PANDORA_HAVE_BETTER_MALLOC])
+  LIBS="${LIBS} ${BETTER_MALLOC_LIBS}"
+])
+
diff --git a/m4/pandora_have_gcc_atomics.m4 b/m4/pandora_have_gcc_atomics.m4
new file mode 100644 (file)
index 0000000..5b3b21a
--- /dev/null
@@ -0,0 +1,37 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+#--------------------------------------------------------------------
+# Check for GCC Atomic Support
+#--------------------------------------------------------------------
+
+
+AC_DEFUN([PANDORA_HAVE_GCC_ATOMICS],[
+       
+  AC_CACHE_CHECK(
+    [whether the compiler provides atomic builtins],
+    [ac_cv_gcc_atomic_builtins],
+    [AC_RUN_IFELSE(
+      [AC_LANG_PROGRAM([],[[
+        int foo= -10; int bar= 10;
+        if (!__sync_fetch_and_add(&foo, bar) || foo)
+          return -1;
+        bar= __sync_lock_test_and_set(&foo, bar);
+        if (bar || foo != 10)
+          return -1;
+        bar= __sync_val_compare_and_swap(&bar, foo, 15);
+        if (bar)
+          return -1;
+        return 0;
+        ]])],
+      [ac_cv_gcc_atomic_builtins=yes],
+      [ac_cv_gcc_atomic_builtins=no])])
+
+  AS_IF([test "x$ac_cv_gcc_atomic_builtins" = "xyes"],[
+    AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS, 1,
+              [Define to 1 if compiler provides atomic builtins.])
+  ])
+
+])
\ No newline at end of file
diff --git a/m4/pandora_have_libavahi.m4 b/m4/pandora_have_libavahi.m4
new file mode 100644 (file)
index 0000000..72c274f
--- /dev/null
@@ -0,0 +1,41 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([_PANDORA_SEARCH_LIBAVAHI],[
+  AC_REQUIRE([AC_LIB_PREFIX])
+
+  dnl --------------------------------------------------------------------
+  dnl  Check for libavahi
+  dnl --------------------------------------------------------------------
+
+  AC_ARG_ENABLE([libavahi],
+    [AS_HELP_STRING([--disable-libavahi],
+      [Build with libavahi support @<:@default=on@:>@])],
+    [ac_enable_libavahi="$enableval"],
+    [ac_enable_libavahi="yes"])
+
+  AS_IF([test "x$ac_enable_libavahi" = "xyes"],[
+    AC_LIB_HAVE_LINKFLAGS(avahi-client,avahi-common,[
+      #include <avahi-client/client.h>
+      #include <avahi-common/simple-watch.h>
+    ],[
+      AvahiSimplePoll *simple_poll= avahi_simple_poll_new();
+    ])
+  ],[
+    ac_cv_libavahi="no"
+  ])
+
+  AM_CONDITIONAL(HAVE_LIBAVAHI, [test "x${ac_cv_libavahi}" = "xyes"])
+])
+
+AC_DEFUN([PANDORA_HAVE_LIBAVAHI],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBAVAHI])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBAVAHI],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBAVAHI])
+  AS_IF([test "x${ac_cv_libavahi}" = "xno"],
+    AC_MSG_ERROR([libavahi is required for ${PACKAGE}]))
+])
diff --git a/m4/pandora_have_libbdb.m4 b/m4/pandora_have_libbdb.m4
new file mode 100644 (file)
index 0000000..3e2d144
--- /dev/null
@@ -0,0 +1,40 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([_PANDORA_SEARCH_LIBBDB],[
+  AC_REQUIRE([AC_LIB_PREFIX])
+
+  dnl --------------------------------------------------------------------
+  dnl  Check for bekerely db
+  dnl --------------------------------------------------------------------
+
+  AC_ARG_ENABLE([libbdb],
+    [AS_HELP_STRING([--disable-libbdb],
+      [Build with libbdb support @<:@default=on@:>@])],
+    [ac_enable_libbdb="$enableval"],
+    [ac_enable_libbdb="yes"])
+
+  AS_IF([test "x$ac_enable_libbdb" = "xyes"],[
+    AC_LIB_HAVE_LINKFLAGS(db,,[
+      #include <db.h>
+    ],[
+      const char *test= DB_VERSION_STRING;
+    ])
+  ],[
+    ac_cv_libbdb="no"
+  ])
+
+  AM_CONDITIONAL(HAVE_LIBBDB, [test "x${ac_cv_libbdb}" = "xyes"])
+])
+
+AC_DEFUN([PANDORA_HAVE_LIBBDB],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBBDB])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBBDB],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBBDB])
+  AS_IF([test "x${ac_cv_libbdb}" = "xno"],
+    AC_MSG_ERROR([libbdb is required for ${PACKAGE}]))
+])
diff --git a/m4/pandora_have_libdl.m4 b/m4/pandora_have_libdl.m4
new file mode 100644 (file)
index 0000000..1317ee9
--- /dev/null
@@ -0,0 +1,51 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+#--------------------------------------------------------------------
+# Check for libdl
+#--------------------------------------------------------------------
+
+
+AC_DEFUN([_PANDORA_SEARCH_LIBDL],[
+
+  save_LIBS="$LIBS"
+  LIBS=""
+  AC_CHECK_LIB(dl,dlopen)
+  AC_CHECK_FUNCS(dlopen)
+  LIBDL_LIBS="$LIBS"
+  LIBS="${save_LIBS}"
+  AC_SUBST(LIBDL_LIBS)
+
+  AM_CONDITIONAL(HAVE_LIBDL, [test "x${ac_cv_func_dlopen}" = "xyes"])
+])
+
+AC_DEFUN([_PANDORA_HAVE_LIBDL],[
+
+  AC_ARG_ENABLE([libdl],
+    [AS_HELP_STRING([--disable-libdl],
+      [Build with libdl support @<:@default=on@:>@])],
+    [ac_enable_libdl="$enableval"],
+    [ac_enable_libdl="yes"])
+
+  _PANDORA_SEARCH_LIBDL
+])
+
+
+AC_DEFUN([PANDORA_HAVE_LIBDL],[
+  AC_REQUIRE([_PANDORA_HAVE_LIBDL])
+])
+
+AC_DEFUN([_PANDORA_REQUIRE_LIBDL],[
+  ac_enable_libdl="yes"
+  _PANDORA_SEARCH_LIBDL
+
+  AS_IF([test "$ac_cv_func_dlopen" != "yes"],[
+    AC_MSG_ERROR([libdl/dlopen() is required for ${PACKAGE}. On Debian this can be found in libc6-dev. On RedHat this can be found in glibc-devel.])
+  ])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBDL],[
+  AC_REQUIRE([_PANDORA_REQUIRE_LIBDL])
+])
diff --git a/m4/pandora_have_libevent.m4 b/m4/pandora_have_libevent.m4
new file mode 100644 (file)
index 0000000..87e5a89
--- /dev/null
@@ -0,0 +1,66 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+#--------------------------------------------------------------------
+# Check for libevent
+#--------------------------------------------------------------------
+
+
+AC_DEFUN([_PANDORA_SEARCH_LIBEVENT],[
+  AC_REQUIRE([AC_LIB_PREFIX])
+
+  AC_LIB_HAVE_LINKFLAGS(event,,
+  [
+    #include <sys/types.h>
+    #include <sys/time.h>
+    #include <stdlib.h>
+    #include <event.h>
+  ],[
+    struct bufferevent bev;
+    bufferevent_settimeout(&bev, 1, 1);
+    event_init();
+    event_loop(EVLOOP_ONCE);
+  ]) 
+
+  AM_CONDITIONAL(HAVE_LIBEVENT, [test "x${ac_cv_libevent}" = "xyes"])
+
+  AS_IF([test "x${ac_cv_libevent}" = "xyes"],[
+    save_LIBS="${LIBS}"
+    LIBS="${LIBS} ${LTLIBEVENT}"
+    AC_CHECK_FUNCS(event_base_new)
+    AC_CHECK_FUNCS(event_base_free)
+    AC_CHECK_FUNCS(event_base_get_method)
+    LIBS="$save_LIBS"
+  ])
+])
+
+AC_DEFUN([_PANDORA_HAVE_LIBEVENT],[
+
+  AC_ARG_ENABLE([libevent],
+    [AS_HELP_STRING([--disable-libevent],
+      [Build with libevent support @<:@default=on@:>@])],
+    [ac_enable_libevent="$enableval"],
+    [ac_enable_libevent="yes"])
+
+  _PANDORA_SEARCH_LIBEVENT
+])
+
+
+AC_DEFUN([PANDORA_HAVE_LIBEVENT],[
+  AC_REQUIRE([_PANDORA_HAVE_LIBEVENT])
+])
+
+AC_DEFUN([_PANDORA_REQUIRE_LIBEVENT],[
+  ac_enable_libevent="yes"
+  _PANDORA_SEARCH_LIBEVENT
+
+  AS_IF([test x$ac_cv_libevent = xno],[
+    AC_MSG_ERROR([libevent is required for ${PACKAGE}. On Debian this can be found in libevent-dev. On RedHat this can be found in libevent-devel.])
+  ])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBEVENT],[
+  AC_REQUIRE([_PANDORA_REQUIRE_LIBEVENT])
+])
index 2387bed9bc52dbe125ed07d14dffbe85bf4895c8..d66a9e45289901229f9b3491e8c0447d3739d76c 100644 (file)
@@ -21,7 +21,7 @@ AC_DEFUN([_PANDORA_SEARCH_LIBGEARMAN],[
       #include <libgearman/gearman.h>
     ],[
       gearman_client_st gearman_client;
-      gearman_version();
+      gearman_client_context(&gearman_client);
     ])
   ],[
     ac_cv_libgearman="no"
@@ -37,5 +37,5 @@ AC_DEFUN([PANDORA_HAVE_LIBGEARMAN],[
 AC_DEFUN([PANDORA_REQUIRE_LIBGEARMAN],[
   AC_REQUIRE([PANDORA_HAVE_LIBGEARMAN])
   AS_IF([test "x${ac_cv_libgearman}" = "xno"],
-      AC_MSG_ERROR([libgearman is required for ${PACKAGE}]))
+      AC_MSG_ERROR([At least version 0.10 of libgearman is required for ${PACKAGE}]))
 ])
index d1a44c60e04c5cbf512f16a72e673839d2384c9c..25c056131ea9789721df2dcb8d302db9a224181a 100644 (file)
@@ -24,13 +24,30 @@ AC_DEFUN([_PANDORA_SEARCH_LIBMEMCACHED],[
       memcached_dump_func *df;
       memcached_lib_version();
     ])
+    AC_LIB_HAVE_LINKFLAGS(memcachedprotocol,,[
+      #include <libmemcached/protocol_handler.h>
+    ],[
+      struct memcached_protocol_st *protocol_handle;
+      protocol_handle= memcached_protocol_create_instance();
+    ])
   ],[
     ac_cv_libmemcached="no"
   ])
   
+  AC_CACHE_CHECK([if libmemcached has memcached_server_fn],
+    [pandora_cv_libmemcached_server_fn],
+    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <libmemcached/memcached.h>
+memcached_server_fn callbacks[1];
+    ]])],
+    [pandora_cv_libmemcached_server_fn=yes],
+    [pandora_cv_libmemcached_server_fn=no])])
+  AS_IF([test "x$pandora_cv_libmemcached_server_fn" = "xyes"],[
+    AC_DEFINE([HAVE_MEMCACHED_SERVER_FN],[1],[If we have the new memcached_server_fn typedef])
+  ])
+
   AM_CONDITIONAL(HAVE_LIBMEMCACHED, [test "x${ac_cv_libmemcached}" = "xyes"])
   
-  AS_IF([test "x${ac_cv_libmemcached}" = "xyes"], [ PANDORA_WITH_MEMCACHED ])
 ])
 
 AC_DEFUN([PANDORA_HAVE_LIBMEMCACHED],[
@@ -42,3 +59,4 @@ AC_DEFUN([PANDORA_REQUIRE_LIBMEMCACHED],[
   AS_IF([test x$ac_cv_libmemcached = xno],
       AC_MSG_ERROR([libmemcached is required for ${PACKAGE}]))
 ])
+
diff --git a/m4/pandora_have_libpcre.m4 b/m4/pandora_have_libpcre.m4
new file mode 100644 (file)
index 0000000..64c649b
--- /dev/null
@@ -0,0 +1,73 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+#--------------------------------------------------------------------
+# Check for libpcre
+#--------------------------------------------------------------------
+
+
+AC_DEFUN([_PANDORA_SEARCH_LIBPCRE],[
+  AC_REQUIRE([AC_LIB_PREFIX])
+
+  AC_LIB_HAVE_LINKFLAGS(pcre,,
+  [#include <pcre.h>],
+  [
+    pcre *re= NULL;
+    pcre_version();
+  ])
+  AS_IF([test "x$ac_cv_libpcre" = "xno"],
+  [
+    unset ac_cv_libpcre
+    unset HAVE_LIBPCRE
+    unset LIBPCRE
+    unset LIBPCRE_PREFIX
+    unset LTLIBPCRE
+    AC_LIB_HAVE_LINKFLAGS(pcre,,
+    [#include <pcre/pcre.h>],
+    [
+      pcre *re= NULL;
+      pcre_version();
+    ])
+    AS_IF([test "x$ac_cv_libpcre" = "xyes"], [
+      ac_cv_pcre_location="<pcre/pcre.h>"
+    ])
+  ],[
+    ac_cv_pcre_location="<pcre.h>"
+  ])
+
+  AM_CONDITIONAL(HAVE_LIBPCRE, [test "x${ac_cv_libpcre}" = "xyes"])
+])
+
+AC_DEFUN([_PANDORA_HAVE_LIBPCRE],[
+
+  AC_ARG_ENABLE([libpcre],
+    [AS_HELP_STRING([--disable-libpcre],
+      [Build with libpcre support @<:@default=on@:>@])],
+    [ac_enable_libpcre="$enableval"],
+    [ac_enable_libpcre="yes"])
+
+  _PANDORA_SEARCH_LIBPCRE
+])
+
+
+AC_DEFUN([PANDORA_HAVE_LIBPCRE],[
+  AC_REQUIRE([_PANDORA_HAVE_LIBPCRE])
+])
+
+AC_DEFUN([_PANDORA_REQUIRE_LIBPCRE],[
+  ac_enable_libpcre="yes"
+  _PANDORA_SEARCH_LIBPCRE
+
+  AS_IF([test x$ac_cv_libpcre = xno],[
+    AC_MSG_ERROR([libpcre is required for ${PACKAGE}. On Debian this can be found in libpcre3-dev. On RedHat this can be found in pcre-devel.])
+  ],[
+    AC_DEFINE_UNQUOTED(PCRE_HEADER,[${ac_cv_pcre_location}],
+                       [Location of pcre header])
+  ])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBPCRE],[
+  AC_REQUIRE([_PANDORA_REQUIRE_LIBPCRE])
+])
diff --git a/m4/pandora_have_libreadline.m4 b/m4/pandora_have_libreadline.m4
new file mode 100644 (file)
index 0000000..bc739d5
--- /dev/null
@@ -0,0 +1,242 @@
+#
+# SYNOPSIS
+#
+#   PANDORA_HAVE_LIBREADLINE
+#
+# DESCRIPTION
+#
+#   Searches for a readline compatible library. If found, defines
+#   `HAVE_LIBREADLINE'. If the found library has the `add_history'
+#   function, sets also `HAVE_READLINE_HISTORY'. Also checks for the
+#   locations of the necessary include files and sets `HAVE_READLINE_H'
+#   or `HAVE_READLINE_READLINE_H' and `HAVE_READLINE_HISTORY_H' or
+#   'HAVE_HISTORY_H' if the corresponding include files exists.
+#
+#   The libraries that may be readline compatible are `libedit',
+#   `libeditline' and `libreadline'. Sometimes we need to link a
+#   termcap library for readline to work, this macro tests these cases
+#   too by trying to link with `libtermcap', `libcurses' or
+#   `libncurses' before giving up.
+#
+#   Here is an example of how to use the information provided by this
+#   macro to perform the necessary includes or declarations in a C
+#   file:
+#
+#     #ifdef HAVE_LIBREADLINE
+#     #  if defined(HAVE_READLINE_READLINE_H)
+#     #    include <readline/readline.h>
+#     #  elif defined(HAVE_READLINE_H)
+#     #    include <readline.h>
+#     #  else /* !defined(HAVE_READLINE_H) */
+#     extern char *readline ();
+#     #  endif /* !defined(HAVE_READLINE_H) */
+#     char *cmdline = NULL;
+#     #else /* !defined(HAVE_READLINE_READLINE_H) */
+#       /* no readline */
+#     #endif /* HAVE_LIBREADLINE */
+#
+#     #ifdef HAVE_READLINE_HISTORY
+#     #  if defined(HAVE_READLINE_HISTORY_H)
+#     #    include <readline/history.h>
+#     #  elif defined(HAVE_HISTORY_H)
+#     #    include <history.h>
+#     #  else /* !defined(HAVE_HISTORY_H) */
+#     extern void add_history ();
+#     extern int write_history ();
+#     extern int read_history ();
+#     #  endif /* defined(HAVE_READLINE_HISTORY_H) */
+#       /* no history */
+#     #endif /* HAVE_READLINE_HISTORY */
+#
+# LAST MODIFICATION
+#
+#   2009-11-17
+#
+# Based on VL_LIB_READLINE from  Ville Laurikari
+#
+# COPYLEFT
+#
+#   Copyright (c) 2009 Monty Taylor
+#   Copyright (c) 2002 Ville Laurikari <vl@iki.fi>
+#
+#   Copying and distribution of this file, with or without
+#   modification, are permitted in any medium without royalty provided
+#   the copyright notice and this notice are preserved.
+
+AC_DEFUN([PANDORA_CHECK_TIOCGWINSZ],[
+  AC_CACHE_CHECK([for TIOCGWINSZ in sys/ioctl.h],
+    [pandora_cv_tiocgwinsz_in_ioctl],[
+    AC_COMPILE_IFELSE([
+      AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#include <sys/ioctl.h>
+      ]],[[
+int x= TIOCGWINSZ;
+      ]])
+    ],[
+      pandora_cv_tiocgwinsz_in_ioctl=yes
+    ],[
+      pandora_cv_tiocgwinsz_in_ioctl=no
+    ])
+  ])
+  AS_IF([test "$pandora_cv_tiocgwinsz_in_ioctl" = "yes"],[   
+    AC_DEFINE([GWINSZ_IN_SYS_IOCTL], [1],
+              [READLINE: your system defines TIOCGWINSZ in sys/ioctl.h.])
+  ])
+])
+
+AC_DEFUN([PANDORA_CHECK_RL_COMPENTRY], [
+  AC_CACHE_CHECK([defined rl_compentry_func_t], [pandora_cv_rl_compentry],[
+    AC_COMPILE_IFELSE([
+      AC_LANG_PROGRAM([[
+#include "stdio.h"
+#include "readline/readline.h"
+      ]],[[
+rl_compentry_func_t *func2= (rl_compentry_func_t*)0;
+      ]])
+    ],[
+      pandora_cv_rl_compentry=yes
+    ],[
+      pandora_cv_rl_compentry=no
+    ])
+  ])
+  AS_IF([test "$pandora_cv_rl_compentry" = "yes"],[
+    AC_DEFINE([HAVE_RL_COMPENTRY], [1],
+              [Does system provide rl_compentry_func_t])
+  ])
+
+  save_CXXFLAGS="${CXXFLAGS}"
+  CXXFLAGS="${AM_CXXFLAGS} ${CXXFLAGS}"
+  AC_LANG_PUSH(C++)
+  AC_CACHE_CHECK([rl_compentry_func_t works], [pandora_cv_rl_compentry_works],[
+    AC_COMPILE_IFELSE([
+      AC_LANG_PROGRAM([[
+#include "stdio.h"
+#include "readline/readline.h"
+      ]],[[
+rl_completion_entry_function= (rl_compentry_func_t*)NULL;
+      ]])
+    ],[
+      pandora_cv_rl_compentry_works=yes
+    ],[
+      pandora_cv_rl_compentry_works=no
+    ])
+  ])
+  AS_IF([test "$pandora_cv_rl_compentry_works" = "yes"],[
+    AC_DEFINE([HAVE_WORKING_RL_COMPENTRY], [1],
+              [Does system provide an rl_compentry_func_t that is usable])
+  ])
+  CXXFLAGS="${save_CXXFLAGS}"
+  AC_LANG_POP()
+])
+
+
+AC_DEFUN([PANDORA_CHECK_RL_COMPLETION_FUNC], [
+  AC_CACHE_CHECK([defined rl_completion_func_t], [pandora_cv_rl_completion],[
+    AC_COMPILE_IFELSE([
+      AC_LANG_PROGRAM([[
+#include "stdio.h"
+#include "readline/readline.h"
+      ]],[[
+rl_completion_func_t *func1= (rl_completion_func_t*)0;
+      ]])
+    ],[
+      pandora_cv_rl_completion=yes
+    ],[
+      pandora_cv_rl_completion=no
+    ])
+  ])
+  AS_IF([test "$pandora_cv_rl_completion" = "yes"],[
+    AC_DEFINE([HAVE_RL_COMPLETION], [1],
+              [Does system provide rl_completion_func_t])
+  ])
+])
+
+AC_DEFUN([_PANDORA_SEARCH_LIBREADLINE], [
+
+  save_LIBS="${LIBS}"
+  LIBS=""
+
+  AC_CACHE_CHECK([for a readline compatible library],
+                 ac_cv_libreadline, [
+    ORIG_LIBS="$LIBS"
+    for readline_lib in readline edit editline; do
+      for termcap_lib in "" termcap curses ncurses; do
+        if test -z "$termcap_lib"; then
+          TRY_LIB="-l$readline_lib"
+        else
+          TRY_LIB="-l$readline_lib -l$termcap_lib"
+        fi
+        LIBS="$ORIG_LIBS $TRY_LIB"
+        AC_TRY_LINK_FUNC(readline, ac_cv_libreadline="$TRY_LIB")
+        if test -n "$ac_cv_libreadline"; then
+          break
+        fi
+      done
+      if test -n "$ac_cv_libreadline"; then
+        break
+      fi
+    done
+    if test -z "$ac_cv_libreadline"; then
+      ac_cv_libreadline="no"
+      LIBS="$ORIG_LIBS"
+    fi
+  ])
+
+  if test "$ac_cv_libreadline" != "no"; then
+    AC_DEFINE(HAVE_LIBREADLINE, 1,
+              [Define if you have a readline compatible library])
+    AC_CHECK_HEADERS(readline.h readline/readline.h)
+    AC_CACHE_CHECK([whether readline supports history],
+                   ac_cv_libreadline_history, [
+      ac_cv_libreadline_history="no"
+      AC_TRY_LINK_FUNC(add_history, ac_cv_libreadline_history="yes")
+    ])
+    if test "$ac_cv_libreadline_history" = "yes"; then
+      AC_DEFINE(HAVE_READLINE_HISTORY, 1,
+                [Define if your readline library has \`add_history'])
+      AC_CHECK_HEADERS(history.h readline/history.h)
+    fi
+  fi
+  PANDORA_CHECK_RL_COMPENTRY  
+  PANDORA_CHECK_RL_COMPLETION_FUNC
+  PANDORA_CHECK_TIOCGWINSZ
+
+
+  READLINE_LIBS="${LIBS}"
+  LIBS="${save_LIBS}"
+  AC_SUBST(READLINE_LIBS)
+
+  AM_CONDITIONAL(HAVE_LIBREADLINE, [test "x${ac_cv_libreadline}" = "xyes"])
+])
+
+AC_DEFUN([_PANDORA_HAVE_LIBREADLINE],[
+
+  AC_ARG_ENABLE([libreadline],
+    [AS_HELP_STRING([--disable-libreadline],
+      [Build with libreadline support @<:@default=on@:>@])],
+    [ac_enable_libreadline="$enableval"],
+    [ac_enable_libreadline="yes"])
+
+  _PANDORA_SEARCH_LIBREADLINE
+])
+
+
+AC_DEFUN([PANDORA_HAVE_LIBREADLINE],[
+  AC_REQUIRE([_PANDORA_HAVE_LIBREADLINE])
+])
+
+AC_DEFUN([_PANDORA_REQUIRE_LIBREADLINE],[
+  ac_enable_libreadline="yes"
+  _PANDORA_SEARCH_LIBREADLINE
+
+  AS_IF([test "x$ac_cv_libreadline" = "xno"],
+    AC_MSG_ERROR([libreadline is required for ${PACKAGE}. On Debian this can be found in libreadline5-dev. On RedHat this can be found in readline-devel.]))
+
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBREADLINE],[
+  AC_REQUIRE([_PANDORA_REQUIRE_LIBREADLINE])
+])
+
+
diff --git a/m4/pandora_have_libtokyocabinet.m4 b/m4/pandora_have_libtokyocabinet.m4
new file mode 100644 (file)
index 0000000..cc4d887
--- /dev/null
@@ -0,0 +1,52 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl Provides support for finding libtokyocabinet.
+dnl LIBTOKYOCABINET_CFLAGS will be set, in addition to LIBTOKYOCABINET and LTLIBTOKYOCABINET
+
+AC_DEFUN([_PANDORA_SEARCH_LIBTOKYOCABINET],[
+  AC_REQUIRE([AC_LIB_PREFIX])
+
+  dnl --------------------------------------------------------------------
+  dnl  Check for libtokyocabinet
+  dnl --------------------------------------------------------------------
+
+  AC_ARG_ENABLE([libtokyocabinet],
+    [AS_HELP_STRING([--disable-libtokyocabinet],
+      [Build with libtokyocabinet support @<:@default=on@:>@])],
+    [ac_enable_libtokyocabinet="$enableval"],
+    [ac_enable_libtokyocabinet="yes"])
+
+  AS_IF([test "x$ac_enable_libtokyocabinet" = "xyes"],[
+    AC_LIB_HAVE_LINKFLAGS(tokyocabinet,,[
+#include <tcutil.h>
+    ],[
+const char *test= tcversion;
+    ])
+  ],[
+    ac_cv_libtokyocabinet="no"
+  ])
+
+  AS_IF([test "${ac_cv_libtokyocabinet}" = "no" -a "${ac_enable_libtokyocabinet}" = "yes"],[
+
+    PKG_CHECK_MODULES([LIBTOKYOCABINET], [libtokyocabinet], [
+      ac_cv_libtokyocabinet=yes
+      LTLIBTOKYOCABINET=${LIBTOKYOCABINET_LIBS}
+      LIBTOKYOCABINET=${LIBTOKYOCABINET_LIBS}
+    ],[])
+  ])
+
+  AM_CONDITIONAL(HAVE_LIBTOKYOCABINET, [test "${ac_cv_libtokyocabinet}" = "yes"])
+])
+
+AC_DEFUN([PANDORA_HAVE_LIBTOKYOCABINET],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBTOKYOCABINET])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBTOKYOCABINET],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBTOKYOCABINET])
+  AS_IF([test "x${ac_cv_libtokyocabinet}" = "xno"],
+    AC_MSG_ERROR([libtokyocabinet is required for ${PACKAGE}. On Debian systems this is found in libtokyocabinet-dev. On RedHat, in tokyocabinet-devel.]))
+])
diff --git a/m4/pandora_have_libuuid.m4 b/m4/pandora_have_libuuid.m4
new file mode 100644 (file)
index 0000000..5ba66d7
--- /dev/null
@@ -0,0 +1,55 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+#--------------------------------------------------------------------
+# Check for libuuid
+#--------------------------------------------------------------------
+
+
+AC_DEFUN([_PANDORA_SEARCH_LIBUUID],[
+  AC_REQUIRE([AC_LIB_PREFIX])
+
+  dnl Do this by hand. Need to check for uuid/uuid.h, but uuid may or may
+  dnl not be a lib is weird.
+  AC_CHECK_HEADERS(uuid/uuid.h)
+  AC_LIB_HAVE_LINKFLAGS(uuid,,
+  [
+    #include <uuid/uuid.h>
+  ],
+  [
+    uuid_t uout;
+    uuid_generate(uout);
+  ])
+
+  AM_CONDITIONAL(HAVE_LIBUUID, [test "x${ac_cv_libuuid}" = "xyes"])
+])
+
+AC_DEFUN([_PANDORA_HAVE_LIBUUID],[
+
+  AC_ARG_ENABLE([libuuid],
+    [AS_HELP_STRING([--disable-libuuid],
+      [Build with libuuid support @<:@default=on@:>@])],
+    [ac_enable_libuuid="$enableval"],
+    [ac_enable_libuuid="yes"])
+
+  _PANDORA_SEARCH_LIBUUID
+])
+
+
+AC_DEFUN([PANDORA_HAVE_LIBUUID],[
+  AC_REQUIRE([_PANDORA_HAVE_LIBUUID])
+])
+
+AC_DEFUN([_PANDORA_REQUIRE_LIBUUID],[
+  ac_enable_libuuid="yes"
+  _PANDORA_SEARCH_LIBUUID
+  AS_IF([test "x$ac_cv_header_uuid_uuid_h" = "xno"],[
+    AC_MSG_ERROR([Couldn't find uuid/uuid.h. On Debian this can be found in uuid-dev. On Redhat this can be found in e2fsprogs-devel.])
+  ])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBUUID],[
+  AC_REQUIRE([_PANDORA_REQUIRE_LIBUUID])
+])
diff --git a/m4/pandora_have_libxml2.m4 b/m4/pandora_have_libxml2.m4
new file mode 100644 (file)
index 0000000..eabd0f3
--- /dev/null
@@ -0,0 +1,52 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl Provides support for finding libxml2.
+dnl LIBXML2_CFLAGS will be set, in addition to LIBXML2 and LTLIBXML2
+
+AC_DEFUN([_PANDORA_SEARCH_LIBXML2],[
+  AC_REQUIRE([AC_LIB_PREFIX])
+
+  dnl --------------------------------------------------------------------
+  dnl  Check for libxml2
+  dnl --------------------------------------------------------------------
+
+  AC_ARG_ENABLE([libxml2],
+    [AS_HELP_STRING([--disable-libxml2],
+      [Build with libxml2 support @<:@default=on@:>@])],
+    [ac_enable_libxml2="$enableval"],
+    [ac_enable_libxml2="yes"])
+
+  AS_IF([test "x$ac_enable_libxml2" = "xyes"],[
+    AC_LIB_HAVE_LINKFLAGS(xml2,,[
+#include <libxml/xmlversion.h>
+    ],[
+const char *test= LIBXML_DOTTED_VERSION;
+    ])
+  ],[
+    ac_cv_libxml2="no"
+  ])
+
+  AS_IF([test "${ac_cv_libxml2}" = "no" -a "${ac_enable_libxml2}" = "yes"],[
+
+    PKG_CHECK_MODULES([LIBXML2], [libxml-2.0], [
+      ac_cv_libxml2=yes
+      LTLIBXML2=${LIBXML2_LIBS}
+      LIBXML2=${LIBXML2_LIBS}
+    ],[])
+  ])
+
+  AM_CONDITIONAL(HAVE_LIBXML2, [test "${ac_cv_libxml2}" = "yes"])
+])
+
+AC_DEFUN([PANDORA_HAVE_LIBXML2],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBXML2])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBXML2],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBXML2])
+  AS_IF([test "x${ac_cv_libxml2}" = "xno"],
+    AC_MSG_ERROR([libxml2 is required for ${PACKAGE}. On Debian systems this is found in libxml2-dev. On RedHat, libxml2-devel.]))
+])
diff --git a/m4/pandora_have_libz.m4 b/m4/pandora_have_libz.m4
new file mode 100644 (file)
index 0000000..823cb4e
--- /dev/null
@@ -0,0 +1,51 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+#--------------------------------------------------------------------
+# Check for libz
+#--------------------------------------------------------------------
+
+
+AC_DEFUN([_PANDORA_SEARCH_LIBZ],[
+  AC_REQUIRE([AC_LIB_PREFIX])
+
+  AC_LIB_HAVE_LINKFLAGS(z,,
+  [
+    #include <zlib.h>
+  ],[
+    crc32(0, Z_NULL, 0);
+  ])
+
+  AM_CONDITIONAL(HAVE_LIBZ, [test "x${ac_cv_libz}" = "xyes"])
+])
+
+AC_DEFUN([_PANDORA_HAVE_LIBZ],[
+
+  AC_ARG_ENABLE([libz],
+    [AS_HELP_STRING([--disable-libz],
+      [Build with libz support @<:@default=on@:>@])],
+    [ac_enable_libz="$enableval"],
+    [ac_enable_libz="yes"])
+
+  _PANDORA_SEARCH_LIBZ
+])
+
+
+AC_DEFUN([PANDORA_HAVE_LIBZ],[
+  AC_REQUIRE([_PANDORA_HAVE_LIBZ])
+])
+
+AC_DEFUN([_PANDORA_REQUIRE_LIBZ],[
+  ac_enable_libz="yes"
+  _PANDORA_SEARCH_LIBZ
+
+  AS_IF([test x$ac_cv_libz = xno],[
+    AC_MSG_ERROR([libz is required for ${PACKAGE}. On Debian this can be found in zlib1g-dev. On RedHat this can be found in zlib-devel.])
+  ])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBZ],[
+  AC_REQUIRE([_PANDORA_REQUIRE_LIBZ])
+])
index eb5d15b90542a70e2f6c2f26395d7c01fc16e83b..1bd95eb58b4d316bbdb6c7f0d13484f73bbea319 100644 (file)
@@ -8,6 +8,7 @@ dnl ----------------
 dnl Check whether to enable assertions.
 AC_DEFUN([PANDORA_HEADER_ASSERT],
 [
+  AC_CHECK_HEADERS(assert.h)
   AC_MSG_CHECKING([whether to enable assertions])
   AC_ARG_ENABLE([assert],
     [AS_HELP_STRING([--disable-assert],
@@ -16,8 +17,7 @@ AC_DEFUN([PANDORA_HEADER_ASSERT],
     [ac_cv_assert="yes"])
   AC_MSG_RESULT([$ac_cv_assert])
 
-  AS_IF([test "$ac_cv_assert" = "yes"], 
-    [AC_CHECK_HEADERS(assert.h)],
+  AS_IF([test "$ac_cv_assert" = "no"], 
     [AC_DEFINE(NDEBUG, 1, [Define to 1 if assertions should be disabled.])])
 ])
 
index b9e461c7dcfbfb7b8a419a5eddbb57b34c87db10..543cbb6b05687b34ea4d8997a053559c832c8910 100644 (file)
@@ -4,7 +4,17 @@ dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
 AC_DEFUN([PANDORA_LIBTOOL],[
+  AC_REQUIRE([AC_DISABLE_STATIC])
   AC_REQUIRE([AC_PROG_LIBTOOL])
+  m4_ifndef([LT_PREREQ],[
+    pandora_have_old_libtool=yes
+  ],[
+    pandora_have_old_libtool=no
+  ])
+  AS_IF([test "$SUNCC" = "yes" -a "${pandora_have_old_libtool}" = "yes"],[
+    AC_MSG_ERROR([Building ${PACKAGE} with Sun Studio requires at least libtool 2.2])
+  ])
+
   dnl By requiring AC_PROG_LIBTOOL, we should force the macro system to read
   dnl libtool.m4, where in 2.2 AC_PROG_LIBTOOL is an alias for LT_INIT
   dnl Then, if we're on 2.2, we should have LT_LANG, so we'll call it.
index 17b636bfd09a144ba67ed5a5700894031c04e5e1..65f9cdc80692be2464362195d5e71312ada77051 100644 (file)
@@ -51,7 +51,7 @@ AC_DEFUN([PANDORA_OPTIMIZE],[
     CXX="${CXX} -xlang=c99"
 
     AM_CFLAGS="-g -mt -xstrconst -Xa ${AM_CFLAGS}"
-    AM_CXXFLAGS="-mt -compat=5 -library=stlport4 -template=no%extdef ${AM_CXXFLAGS}"
+    AM_CXXFLAGS="-mt -compat=5 -library=stlport4 -library=Crun -template=no%extdef ${AM_CXXFLAGS}"
 
     DEBUG_CXXFLAGS="-g"
 
index 678b51ea029e2b6dd62a9d12bd420fe37744d298..4e54562dce534597cbaa7db144a49ca5b20fb07e 100644 (file)
@@ -74,4 +74,12 @@ AC_DEFUN([PANDORA_PLATFORM],[
       [Cause Sun Studio to not be quite so strict with standards conflicts])
   ])
 
+  AS_IF([test "x$TARGET_OSX" = "xtrue"],[
+    AS_IF([test "x$ac_enable_fat_binaries" = "xyes"],[
+      AM_CFLAGS="-arch i386 -arch x86_64 -arch ppc"
+      AM_CXXFLAGS="-arch i386 -arch x86_64 -arch ppc"
+      AM_LDFLAGS="-arch i386 -arch x86_64 -arch ppc"
+    ])
+  ])
+
 ])
index 75e3732959f491b5ee2870b5d5b02d9d633c7b0a..25ed1e9153d7b523c53864cede292f3644eab017 100644 (file)
@@ -9,20 +9,32 @@ dnl--------------------------------------------------------------------
 
 AC_DEFUN([PANDORA_PLUGINS],[
 
-  m4_sinclude(config/plugin.ac)
-  dnl Add code here to read set plugin lists and  set drizzled_default_plugin_list
-  AC_DEFINE_UNQUOTED([PANDORA_PLUGIN_LIST],[$pandora_default_plugin_list],
-                     [List of plugins that should be loaded on startup if no
-                      value is given for --plugin-load])
+  dnl We do this to prime the files from a fresh checkout. Normally we want
+  dnl these commands to be executed by make. Perhaps we should split them into
+  dnl a few shell script snippets in config and make Make call them... we're
+  dnl going to get there...
+  dnl ANYWAY - syscmd gets called during aclocal - so before automake. It will
+  dnl get called probably during autoconf too, so it's important to protect
+  dnl with test -f ... if the files exist, we don't have the chicken/egg 
+  dnl problem and therefore don't need to do anything here
+  m4_syscmd([python config/pandora-plugin > /dev/null])
+  m4_syscmd([test -f config/plugin.stamp || touch config/plugin.stamp aclocal.m4])
+
+  m4_sinclude(config/pandora-plugin.ac)
 
+  dnl Add code here to read set plugin lists and  set drizzled_default_plugin_list
   pandora_builtin_list=`echo $pandora_builtin_list | sed 's/, *$//'`
   AS_IF([test "x$pandora_builtin_list" = "x"], pandora_builtin_list="NULL")
   AC_SUBST([PANDORA_BUILTIN_LIST],[$pandora_builtin_list])
+  AC_SUBST([PANDORA_PLUGIN_LIST],[$pandora_default_plugin_list])
   m4_ifval(m4_normalize([$1]),[
     AC_CONFIG_FILES($*)
     ],[
     AC_DEFINE_UNQUOTED([PANDORA_BUILTIN_LIST],[$pandora_builtin_list],
                        [List of plugins to be built in])
+    AC_DEFINE_UNQUOTED([PANDORA_PLUGIN_LIST],["$pandora_default_plugin_list"],
+                       [List of plugins that should be loaded on startup if no
+                        value is given for --plugin-load])
   ])
 
 
diff --git a/m4/pandora_print_callstack.m4 b/m4/pandora_print_callstack.m4
new file mode 100644 (file)
index 0000000..e28b593
--- /dev/null
@@ -0,0 +1,61 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Try to define a macro to dump the current callstack.
+AC_DEFUN([PANDORA_PRINT_CALLSTACK],[
+  AC_CHECK_HEADERS([ucontext.h])
+  AS_IF([test "x$ac_cv_header_ucontext_h" = "xyes"],
+       [ AC_CHECK_FUNCS([printstack]) ])
+
+
+  AS_IF([ test "x$ac_cv_func_printstack" != "xyes"],
+        [ AC_CHECK_HEADERS([dlfcn.h])
+          AC_CHECK_HEADERS([execinfo.h])
+          AC_CHECK_FUNCS([backtrace])
+          AC_CHECK_FUNCS([backtrace_symbols_fd]) ])
+
+  AH_BOTTOM([
+#ifdef __cplusplus
+#include <cstdio>
+#define PANDORA_PRINTSTACK_STD_PREFIX std::
+#else
+#include <stdio.h>
+#define PANDORA_PRINTSTACK_STD_PREFIX
+#endif
+
+#if defined(HAVE_UCONTEXT_H) && defined(HAVE_PRINTSTACK)
+#include <ucontext.h>
+#define pandora_print_callstack(a) \
+printstack(PANDORA_PRINTSTACK_STD_PREFIX fileno(a))
+#elif defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS_FD)
+
+#include <execinfo.h>
+
+#define pandora_print_callstack(a) \
+{ \
+  void *stack[100];  \
+  int depth = backtrace(stack, 100); \
+  backtrace_symbols_fd(stack, depth, PANDORA_PRINTSTACK_STD_PREFIX fileno(a)); \
+}
+#elif defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) && !defined(HAVE_BACKTRACE_SYMBOLS_FD)
+
+#include <execinfo.h>
+
+#define pandora_print_callstack(a) \
+{ \
+  void *stack[100];  \
+  int depth= backtrace(stack, 100); \
+  char **symbol= backtrace_symbols(stack, depth); \
+  for (int x= 0; x < size; ++x) \
+    PANDORA_PRINTSTACK_STD_PREFIX fprintf(a, "%s\n", symbol[x]); \
+}
+#else
+#define pandora_print_callstack(a) \
+    PANDORA_PRINTSTACK_STD_PREFIX fprintf(a, \
+      "Stackdump not supported for this platform\n");
+#endif
+  ])
+
+])
index 75b00fc35550fe9dc3b1927dc391657e7c866b59..a41111661547e2f545b48ac9344b02265021c6e3 100644 (file)
@@ -53,6 +53,186 @@ AC_DEFUN([PANDORA_PTHREAD_YIELD],[
               [pthread_yield function with one argument])
   ])
 
+  AC_CHECK_FUNCS(pthread_attr_getstacksize pthread_attr_setprio \
+    pthread_attr_setschedparam \
+    pthread_attr_setstacksize pthread_condattr_create pthread_getsequence_np \
+    pthread_key_delete pthread_rwlock_rdlock pthread_setprio \
+    pthread_setprio_np pthread_setschedparam pthread_sigmask \
+    pthread_attr_create rwlock_init
+)
+
+
+
+# Check definition of pthread_getspecific
+AC_CACHE_CHECK([args to pthread_getspecific], [pandora_cv_getspecific_args],
+  [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#if !defined(_REENTRANT)
+#define _REENTRANT
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS 
+#define _POSIX_PTHREAD_SEMANTICS 
+#endif
+#include <pthread.h>
+   ]], [[
+void *pthread_getspecific(pthread_key_t key);
+pthread_getspecific((pthread_key_t) NULL);
+   ]])],
+    [pandora_cv_getspecific_args=POSIX],
+    [pandora_cv_getspecific_args=other])])
+  if test "$pandora_cv_getspecific_args" = "other"
+  then
+    AC_DEFINE([HAVE_NONPOSIX_PTHREAD_GETSPECIFIC], [1],
+              [For some non posix threads])
+  fi
+
+  # Check definition of pthread_mutex_init
+  AC_CACHE_CHECK([args to pthread_mutex_init], [pandora_cv_mutex_init_args],
+    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+#define _POSIX_PTHREAD_SEMANTICS 
+#endif
+#include <pthread.h> ]], [[ 
+  pthread_mutexattr_t attr;
+  pthread_mutex_t mp;
+  pthread_mutex_init(&mp,&attr); ]])],
+      [pandora_cv_mutex_init_args=POSIX],
+      [pandora_cv_mutex_init_args=other])])
+  if test "$pandora_cv_mutex_init_args" = "other"
+  then
+    AC_DEFINE([HAVE_NONPOSIX_PTHREAD_MUTEX_INIT], [1],
+              [For some non posix threads])
+  fi
+#---END:
+
+#---START: Used in for client configure
+# Check definition of readdir_r
+AC_CACHE_CHECK([args to readdir_r], [pandora_cv_readdir_r],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS 
+#define _POSIX_PTHREAD_SEMANTICS 
+#endif
+#include <pthread.h>
+#include <dirent.h>]], [[ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+readdir_r((DIR *) NULL, (struct dirent *) NULL, (struct dirent **) NULL); ]])],
+    [pandora_cv_readdir_r=POSIX],
+    [pandora_cv_readdir_r=other])])
+if test "$pandora_cv_readdir_r" = "POSIX"
+then
+  AC_DEFINE([HAVE_READDIR_R], [1], [POSIX readdir_r])
+fi
+
+# Check definition of posix sigwait()
+AC_CACHE_CHECK([style of sigwait], [pandora_cv_sigwait],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+#define _POSIX_PTHREAD_SEMANTICS 
+#endif
+#include <pthread.h>
+#include <signal.h>
+      ]], [[
+#ifndef _AIX
+sigset_t set;
+int sig;
+sigwait(&set,&sig);
+#endif
+      ]])],
+    [pandora_cv_sigwait=POSIX],
+    [pandora_cv_sigwait=other])])
+if test "$pandora_cv_sigwait" = "POSIX"
+then
+  AC_DEFINE([HAVE_SIGWAIT], [1], [POSIX sigwait])
+fi
+
+if test "$pandora_cv_sigwait" != "POSIX"
+then
+unset pandora_cv_sigwait
+# Check definition of posix sigwait()
+AC_CACHE_CHECK([style of sigwait], [pandora_cv_sigwait],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+#define _POSIX_PTHREAD_SEMANTICS 
+#endif
+#include <pthread.h>
+#include <signal.h>
+      ]], [[
+sigset_t set;
+int sig;
+sigwait(&set);
+      ]])],
+    [pandora_cv_sigwait=NONPOSIX],
+    [pandora_cv_sigwait=other])])
+if test "$pandora_cv_sigwait" = "NONPOSIX"
+then
+  AC_DEFINE([HAVE_NONPOSIX_SIGWAIT], [1], [sigwait with one argument])
+fi
+fi
+#---END:
+
+# Check if pthread_attr_setscope() exists
+AC_CACHE_CHECK([for pthread_attr_setscope], [pandora_cv_pthread_attr_setscope],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+#define _POSIX_PTHREAD_SEMANTICS 
+#endif
+#include <pthread.h>
+      ]], [[
+pthread_attr_t thr_attr;
+pthread_attr_setscope(&thr_attr,0);
+      ]])],
+    [pandora_cv_pthread_attr_setscope=yes],
+    [pandora_cv_pthread_attr_setscope=no])])
+if test "$pandora_cv_pthread_attr_setscope" = "yes"
+then
+  AC_DEFINE([HAVE_PTHREAD_ATTR_SETSCOPE], [1], [pthread_attr_setscope])
+fi
+
+
+AC_CACHE_CHECK([if pthread_yield takes zero arguments], ac_cv_pthread_yield_zero_arg,
+[AC_TRY_LINK([#define _GNU_SOURCE
+#include <pthread.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+],
+[
+  pthread_yield();
+], ac_cv_pthread_yield_zero_arg=yes, ac_cv_pthread_yield_zero_arg=yeso)])
+if test "$ac_cv_pthread_yield_zero_arg" = "yes"
+then
+  AC_DEFINE([HAVE_PTHREAD_YIELD_ZERO_ARG], [1],
+            [pthread_yield that doesn't take any arguments])
+fi
+AC_CACHE_CHECK([if pthread_yield takes 1 argument], ac_cv_pthread_yield_one_arg,
+[AC_TRY_LINK([#define _GNU_SOURCE
+#include <pthread.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+],
+[
+  pthread_yield(0);
+], ac_cv_pthread_yield_one_arg=yes, ac_cv_pthread_yield_one_arg=no)])
+if test "$ac_cv_pthread_yield_one_arg" = "yes"
+then
+  AC_DEFINE([HAVE_PTHREAD_YIELD_ONE_ARG], [1],
+            [pthread_yield function with one argument])
+fi
+
   CFLAGS="${save_CFLAGS}"
   CXXFLAGS="${save_CXXFLAGS}"
 ])
diff --git a/m4/pandora_run_cpplint.m4 b/m4/pandora_run_cpplint.m4
new file mode 100644 (file)
index 0000000..5099acf
--- /dev/null
@@ -0,0 +1,8 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([PANDORA_RUN_CPPLINT],[
+  m4_syscmd([python config/make-lint.py])
+])
diff --git a/m4/pandora_sasl.m4 b/m4/pandora_sasl.m4
new file mode 100644 (file)
index 0000000..75513d1
--- /dev/null
@@ -0,0 +1,133 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([_PANDORA_SEARCH_SASL],[
+  AC_REQUIRE([AC_LIB_PREFIX])
+
+  dnl --------------------------------------------------------------------
+  dnl  Check for sasl
+  dnl --------------------------------------------------------------------
+  AC_ARG_ENABLE([sasl],
+    [AS_HELP_STRING([--disable-sasl],
+      [Build with sasl support @<:@default=on@:>@])],
+    [ac_enable_sasl="$enableval"],
+    [ac_enable_sasl="yes"])
+
+  AS_IF([test "x$ac_enable_sasl" = "xyes"],
+    [
+      AC_LIB_HAVE_LINKFLAGS(sasl,,[
+        #include <stdlib.h>
+        #include <sasl/sasl.h>
+      ],[
+        sasl_server_init(NULL, NULL);
+      ])
+
+      AS_IF([test "x${ac_cv_libsasl}" != "xyes" ],
+            [
+              AC_LIB_HAVE_LINKFLAGS(sasl2,,[
+                #include <stdlib.h>
+                #include <sasl/sasl.h>
+              ],[
+                sasl_server_init(NULL, NULL);
+              ])
+              HAVE_LIBSASL="$HAVE_LIBSASL2"
+              LIBSASL="$LIBSASL2"
+              LIBSASL_PREFIX="$LIBSASL2_PREFIX"
+             LTLIBSASL="$LT_LIBSASL2"
+            ])
+    ])
+
+  AS_IF([test "x${ac_cv_libsasl}" = "xyes" -o "x${ac_cv_libsasl2}" = "xyes"],
+        [ac_cv_sasl=yes],
+        [ac_cv_sasl=no])
+
+  AM_CONDITIONAL(HAVE_LIBSASL, [test "x${ac_cv_libsasl}" = "xyes"])
+  AM_CONDITIONAL(HAVE_LIBSASL2, [test "x${ac_cv_libsasl2}" = "xyes"])
+  AM_CONDITIONAL(HAVE_SASL, [test "x${ac_cv_sasl}" = "xyes"])
+])
+
+AC_DEFUN([PANDORA_HAVE_SASL],[
+  AC_REQUIRE([_PANDORA_SEARCH_SASL])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_SASL],[
+  AC_REQUIRE([_PANDORA_SEARCH_SASL])
+  AS_IF([test "x${ac_cv_sasl}" = "xno"],
+    AC_MSG_ERROR([SASL (libsasl or libsasl2) is required for ${PACKAGE}]))
+])
+
+AC_DEFUN([_PANDORA_SEARCH_LIBSASL],[
+  AC_REQUIRE([AC_LIB_PREFIX])
+
+  dnl --------------------------------------------------------------------
+  dnl  Check for libsasl
+  dnl --------------------------------------------------------------------
+
+  AC_ARG_ENABLE([libsasl],
+    [AS_HELP_STRING([--disable-libsasl],
+      [Build with libsasl support @<:@default=on@:>@])],
+    [ac_enable_libsasl="$enableval"],
+    [ac_enable_libsasl="yes"])
+
+  AS_IF([test "x$ac_enable_libsasl" = "xyes"],[
+    AC_LIB_HAVE_LINKFLAGS(sasl,,[
+      #include <stdlib.h>
+      #include <sasl/sasl.h>
+    ],[
+      sasl_server_init(NULL, NULL);
+    ])
+  ],[
+    ac_cv_libsasl="no"
+  ])
+
+  AM_CONDITIONAL(HAVE_LIBSASL, [test "x${ac_cv_libsasl}" = "xyes"])
+])
+
+AC_DEFUN([PANDORA_HAVE_LIBSASL],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBSASL])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBSASL],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBSASL])
+  AS_IF([test "x${ac_cv_libsasl}" = "xno"],
+    AC_MSG_ERROR([libsasl is required for ${PACKAGE}]))
+])
+
+AC_DEFUN([_PANDORA_SEARCH_LIBSASL2],[
+  AC_REQUIRE([AC_LIB_PREFIX])
+
+  dnl --------------------------------------------------------------------
+  dnl  Check for libsasl2
+  dnl --------------------------------------------------------------------
+
+  AC_ARG_ENABLE([libsasl2],
+    [AS_HELP_STRING([--disable-libsasl2],
+      [Build with libsasl2 support @<:@default=on@:>@])],
+    [ac_enable_libsasl2="$enableval"],
+    [ac_enable_libsasl2="yes"])
+
+  AS_IF([test "x$ac_enable_libsasl2" = "xyes"],[
+    AC_LIB_HAVE_LINKFLAGS(sasl2,,[
+      #include <stdlib.h>
+      #include <sasl2/sasl2.h>
+    ],[
+      sasl2_server_init(NULL, NULL);
+    ])
+  ],[
+    ac_cv_libsasl2="no"
+  ])
+
+  AM_CONDITIONAL(HAVE_LIBSASL2, [test "x${ac_cv_libsasl2}" = "xyes"])
+])
+
+AC_DEFUN([PANDORA_HAVE_LIBSASL2],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBSASL2])
+])
+
+AC_DEFUN([PANDORA_REQUIRE_LIBSASL2],[
+  AC_REQUIRE([_PANDORA_SEARCH_LIBSASL2])
+  AS_IF([test "x${ac_cv_libsasl2}" = "xno"],
+    AC_MSG_ERROR([libsasl2 is required for ${PACKAGE}]))
+])
index 70185ade52343248957868d64e6fe9c6e09b47a6..5d6e8dde806f46150058bfa2ae74bb987a8fdf62 100644 (file)
@@ -20,6 +20,8 @@ dnl
 AC_DEFUN([PANDORA_SHARED_PTR],[
   AC_REQUIRE([PANDORA_CHECK_CXX_STANDARD])
   AC_LANG_PUSH(C++)
+  save_CXXFLAGS="${CXXFLAGS}"
+  CXXFLAGS="${CXX_STANDARD} ${CXXFLAGS}"
   AC_CHECK_HEADERS(memory tr1/memory boost/shared_ptr.hpp)
   AC_CACHE_CHECK([the location of shared_ptr header file],
     [ac_cv_shared_ptr_h],[
@@ -52,5 +54,6 @@ shared_ptr<string> test_ptr(new string("test string"));
   AC_DEFINE_UNQUOTED([SHARED_PTR_NAMESPACE],
                      ${ac_cv_shared_ptr_namespace},
                      [The namespace in which SHARED_PTR can be found])
+  CXXFLAGS="${save_CXXFLAGS}"
   AC_LANG_POP()
 ])
diff --git a/m4/pandora_stack_direction.m4 b/m4/pandora_stack_direction.m4
new file mode 100644 (file)
index 0000000..635586a
--- /dev/null
@@ -0,0 +1,39 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+#--------------------------------------------------------------------
+# Check what direction the stack runs in
+#--------------------------------------------------------------------
+
+AC_DEFUN([PANDORA_STACK_DIRECTION],[
+ AC_REQUIRE([AC_FUNC_ALLOCA])
+ AC_CACHE_CHECK([stack direction], [ac_cv_c_stack_direction],[
+  AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <stdlib.h>
+ int find_stack_direction ()
+ {
+   static char *addr = 0;
+   auto char dummy;
+   if (addr == 0)
+     {
+       addr = &dummy;
+       return find_stack_direction ();
+     }
+   else
+     return (&dummy > addr) ? 1 : -1;
+ }
+  ]],[[
+    exit (find_stack_direction() < 0);
+  ]])],[
+   ac_cv_c_stack_direction=1
+  ],[
+   ac_cv_c_stack_direction=-1
+  ])
+ ])
+ AC_DEFINE_UNQUOTED(STACK_DIRECTION, $ac_cv_c_stack_direction)
+])
+
+
+
diff --git a/m4/pandora_stl_hash.m4 b/m4/pandora_stl_hash.m4
new file mode 100644 (file)
index 0000000..26281ae
--- /dev/null
@@ -0,0 +1,110 @@
+# We check two things: where the include file is for hash_map, and
+# what namespace hash_map lives in within that include file.  We
+# include AC_COMPILE_IFELSE for all the combinations we've seen in the
+# wild.  We define one of HAVE_HASH_MAP or HAVE_EXT_HASH_MAP depending
+# on location, and HASH_NAMESPACE to be the namespace hash_map is
+# defined in.
+#
+# Ideally we'd use AC_CACHE_CHECK, but that only lets us store one value
+# at a time, and we need to store two (filename and namespace).
+# prints messages itself, so we have to do the message-printing ourselves
+# via AC_MSG_CHECKING + AC_MSG_RESULT.  (TODO(csilvers): can we cache?)
+
+AC_DEFUN([PANDORA_CXX_STL_HASH],
+  [AC_MSG_CHECKING(the location of hash_map)
+   save_CXXFLAGS="${CXXFLAGS}"
+   CXXFLAGS="${AM_CXXFLAGS} ${CXXFLAGS}"
+   AC_LANG_PUSH(C++)
+   ac_cv_cxx_hash_map=""
+   for location in "" "ext/" "tr1/" ; do
+     for namespace in __gnu_cxx "" std stdext; do
+       for classprefix in unordered hash; do
+         if test -z "$ac_cv_cxx_hash_map"; then
+           AC_COMPILE_IFELSE(
+             [AC_LANG_PROGRAM([[#include <${location}${classprefix}_map>]],
+                           [[${namespace}::${classprefix}_map<int, int> t]])],
+             [ac_cv_cxx_hash_map="<${location}${classprefix}_map>";
+              ac_cv_cxx_hash_set="<${location}${classprefix}_set>";
+              ac_cv_cxx_hash_namespace="$namespace";
+              ac_cv_cxx_hash_map_class="${classprefix}_map";
+              ac_cv_cxx_hash_set_class="${classprefix}_set"])
+
+         fi
+       done
+     done
+   done
+
+   if test -n "$ac_cv_cxx_hash_map"; then
+      AC_DEFINE(HAVE_HASH_MAP, 1, [define if the compiler has hash_map])
+      AC_DEFINE(HAVE_HASH_SET, 1, [define if the compiler has hash_set])
+      AC_DEFINE_UNQUOTED(HASH_MAP_H,$ac_cv_cxx_hash_map,
+                         [the location of <hash_map>])
+      AC_DEFINE_UNQUOTED(HASH_SET_H,$ac_cv_cxx_hash_set,
+                         [the location of <hash_set>])
+      AC_DEFINE_UNQUOTED(HASH_NAMESPACE,$ac_cv_cxx_hash_namespace,
+                         [the namespace of hash_map/hash_set])
+      AC_DEFINE_UNQUOTED(HASH_MAP_CLASS,$ac_cv_cxx_hash_map_class,
+                         [the classname of hash_map])
+      AC_DEFINE_UNQUOTED(HASH_SET_CLASS,$ac_cv_cxx_hash_set_class,
+                         [the classname of hash_set])
+      AC_MSG_RESULT([$ac_cv_cxx_hash_map])
+   else
+      AC_MSG_RESULT()
+      AC_MSG_WARN([could not find an STL hash_map])
+   fi
+   AC_CACHE_CHECK(
+     [whether hash_map has rehash method],
+     [ac_cv_hash_map_has_rehash],
+     [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM([[
+#include HASH_MAP_H
+using namespace HASH_NAMESPACE;
+       ]],[[
+HASH_MAP_CLASS<int, int> test_hash;
+test_hash.rehash(100);
+          ]])],
+       [ac_cv_hash_map_has_rehash=yes],
+       [ac_cv_hash_map_has_rehash=no])])
+   AS_IF([test $ac_cv_hash_map_has_rehash = yes],[
+      AC_DEFINE(HASH_MAP_HAS_REHASH, 1, [if hash_map<> hash rehash method])
+   ])
+   AC_CACHE_CHECK(
+     [whether hash_map has resize method],
+     [ac_cv_hash_map_has_resize],
+     [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM([[
+#include HASH_MAP_H
+using namespace HASH_NAMESPACE;
+       ]],[[
+HASH_MAP_CLASS<int, int> test_hash;
+test_hash.resize(100);
+          ]])],
+       [ac_cv_hash_map_has_resize=yes],
+       [ac_cv_hash_map_has_resize=no])])
+   AS_IF([test $ac_cv_hash_map_has_resize = yes],[
+      AC_DEFINE(HASH_MAP_HAS_RESIZE, 1, [if hash_map<> hash resize method])
+   ])
+   AC_CACHE_CHECK(
+     [whether to redefine hash<string>],
+     [ac_cv_redefine_hash_string],
+     [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM([[
+#include HASH_SET_H
+#include <string>
+using namespace HASH_NAMESPACE;
+using namespace std;
+          ]],[[
+string teststr("test");
+HASH_SET_CLASS<string> test_hash;
+HASH_SET_CLASS<string>::iterator iter= test_hash.find(teststr);
+if (iter != test_hash.end())
+  return 1;
+          ]])],
+       [ac_cv_redefine_hash_string=no],
+       [ac_cv_redefine_hash_string=yes])])
+   AS_IF([test $ac_cv_redefine_hash_string = yes],[
+      AC_DEFINE(REDEFINE_HASH_STRING, 1, [if hash<string> needs to be defined])
+   ])
+   CXXFLAGS="${save_CXXFLAGS}"
+   AC_LANG_POP()
+])
index d84b96767f3b499619c57c8e677eb2433c1e16ed..9bff083511ab34fa50f1327b392094bc7f374e7e 100644 (file)
@@ -52,6 +52,72 @@ AC_DEFUN([PANDORA_EXPORT_BZR_INFO],[
   AC_DEFINE(PEBI_PREFIX[RELEASE_VERSION], ["RELEASE_VERSION"], [$1 version number formatted for display])
   AC_DEFINE(PEBI_PREFIX[RELEASE_COMMENT], ["RELEASE_COMMENT"], [Set to trunk if the branch is the main $1 branch])
   AC_DEFINE(PEBI_PREFIX[RELEASE_ID], [RELEASE_ID], [$1 version number formatted for numerical comparison])
 ])
 
+AC_DEFUN([_PANDORA_READ_FROM_FILE],[
+  $1=`grep $1 $2 | cut -f2 -d=`
+])
+
+AC_DEFUN([PANDORA_VC_VERSION],[
+  AC_REQUIRE([PANDORA_BUILDING_FROM_VC])
+
+  PANDORA_RELEASE_DATE=`date +%Y.%m`
+  PANDORA_RELEASE_NODOTS_DATE=`date +%Y%m`
+
+  dnl Set some defaults
+  PANDORA_VC_REVNO="0"
+  PANDORA_VC_REVID="unknown"
+  PANDORA_VC_BRANCH="bzr-export"
+
+  AS_IF([test -f ${srcdir}/config/bzr_revinfo],[
+    _PANDORA_READ_FROM_FILE([PANDORA_VC_REVNO],${srcdir}/config/bzr_revinfo)
+    _PANDORA_READ_FROM_FILE([PANDORA_VC_REVID],${srcdir}/config/bzr_revinfo)
+    _PANDORA_READ_FROM_FILE([PANDORA_VC_BRANCH],
+                            ${srcdir}/config/bzr_revinfo)
+    _PANDORA_READ_FROM_FILE([PANDORA_RELEASE_DATE],
+                            ${srcdir}/config/bzr_revinfo)
+    _PANDORA_READ_FROM_FILE([PANDORA_RELEASE_NODOTS_DATE],
+                            ${srcdir}/config/bzr_revinfo)
+    _PANDORA_READ_FROM_FILE([PANDORA_RELEASE_COMMENT],
+                            ${srcdir}/config/bzr_revinfo)
+  ])
+  AS_IF([test "${ac_cv_building_from_bzr}" = "yes"],[
+dnl  echo "Grabbing changelog and version information from bzr"
+dnl  bzr log --short > ChangeLog || touch ChangeLog
+    PANDORA_BZR_REVNO=`bzr revno`
+    AS_IF([test "x$PANDORA_BZR_REVNO" != "${PANDORA_VC_REVNO}"],[
+      PANDORA_VC_REVNO="${PANDORA_BZR_REVNO}"
+      PANDORA_VC_REVID=`bzr log -r-1 --show-ids | grep revision-id | awk '{print $[]2}' | head -1`
+      PANDORA_VC_BRANCH=`bzr nick`
+      AS_IF([test "x${PANDORA_VC_BRANCH}" != "${PACKAGE}"],[
+        PANDORA_RELEASE_COMMENT="${PANDORA_VC_BRANCH}"
+      ],[
+        PANDORA_RELEASE_COMMENT="trunk"
+      ])
+    ])
+  ])
+  AS_IF([! test -d config],[mkdir -p config])
+  cat > "config/bzr_revinfo" <<EOF
+PANDORA_VC_REVNO=${PANDORA_VC_REVNO}
+PANDORA_VC_REVID=${PANDORA_VC_REVID}
+PANDORA_VC_BRANCH=${PANDORA_VC_BRANCH}
+PANDORA_RELEASE_DATE=${PANDORA_RELEASE_DATE}
+PANDORA_RELEASE_NODOTS_DATE=${PANDORA_RELEASE_NODOTS_DATE}
+PANDORA_RELEASE_COMMENT=${PANDORA_RELEASE_COMMENT}
+EOF
+    
+  PANDORA_RELEASE_VERSION="${PANDORA_RELEASE_DATE}.${PANDORA_VC_REVNO}"
+  PANDORA_RELEASE_ID="${PANDORA_RELEASE_NODOTS_DATE}${PANDORA_VC_REVNO}"
+
+  VERSION="${PANDORA_RELEASE_VERSION}"
+  AC_DEFINE_UNQUOTED([PANDORA_RELEASE_VERSION],["${PANDORA_RELEASE_VERSION}"],
+                     [The real version of the software])
+  AC_SUBST(PANDORA_VC_REVNO)
+  AC_SUBST(PANDORA_VC_REVID)
+  AC_SUBST(PANDORA_VC_BRANCH)
+  AC_SUBST(PANDORA_RELEASE_DATE)
+  AC_SUBST(PANDORA_RELEASE_NODOTS_DATE)
+  AC_SUBST(PANDORA_RELEASE_COMMENT)
+  AC_SUBST(PANDORA_RELEASE_VERSION)
+  AC_SUBST(PANDORA_RELEASE_ID)
+])
diff --git a/m4/pandora_version.m4 b/m4/pandora_version.m4
new file mode 100644 (file)
index 0000000..3a62798
--- /dev/null
@@ -0,0 +1,11 @@
+dnl  Copyright (C) 2009 Sun Microsystems
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([PANDORA_VERSION],[
+
+  PANDORA_HEX_VERSION=`echo $VERSION | sed 's|[\-a-z0-9]*$||' | \
+    awk -F. '{printf "0x%0.2d%0.3d%0.3d", $[]1, $[]2, $[]3}'`
+  AC_SUBST([PANDORA_HEX_VERSION])
+])
diff --git a/m4/pandora_visibility.m4 b/m4/pandora_visibility.m4
new file mode 100644 (file)
index 0000000..cb68644
--- /dev/null
@@ -0,0 +1,57 @@
+dnl Copyright (C) 2005, 2008 Free Software Foundation, Inc.
+dnl Copyright (C) 2009 Monty Taylor
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+dnl Tests whether the compiler supports the command-line option
+dnl -fvisibility=hidden and the function and variable attributes
+dnl __attribute__((__visibility__("hidden"))) and
+dnl __attribute__((__visibility__("default"))).
+dnl Does *not* test for __visibility__("protected") - which has tricky
+dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on
+dnl MacOS X.
+dnl Does *not* test for __visibility__("internal") - which has processor
+dnl dependent semantics.
+dnl Does *not* test for #pragma GCC visibility push(hidden) - which is
+dnl "really only recommended for legacy code".
+dnl Set the variable CFLAG_VISIBILITY.
+dnl Defines and sets the variable HAVE_VISIBILITY.
+
+AC_DEFUN([PANDORA_VISIBILITY],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([PANDORA_PLATFORM])
+  CFLAG_VISIBILITY=
+  HAVE_VISIBILITY=0
+  AS_IF([test -n "$GCC"],[
+    AC_MSG_CHECKING([for simple visibility declarations])
+    AC_CACHE_VAL([gl_cv_cc_visibility], [
+      gl_save_CFLAGS="$CFLAGS"
+      CFLAGS="$CFLAGS -fvisibility=hidden"
+      AC_TRY_COMPILE(
+        [extern __attribute__((__visibility__("hidden"))) int hiddenvar;
+         extern __attribute__((__visibility__("default"))) int exportedvar;
+         extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void);
+         extern __attribute__((__visibility__("default"))) int exportedfunc (void);],
+        [],
+        [gl_cv_cc_visibility=yes],
+        [gl_cv_cc_visibility=no])
+      CFLAGS="$gl_save_CFLAGS"])
+    AC_MSG_RESULT([$gl_cv_cc_visibility])
+    if test $gl_cv_cc_visibility = yes; then
+      CFLAG_VISIBILITY="-fvisibility=hidden"
+      HAVE_VISIBILITY=1
+    fi
+  ])
+  AS_IF([test "x$SUNCC" = "xyes"],[
+    CFLAG_VISIBILITY="-xldscope=hidden"
+    HAVE_VISIBILITY=1
+  ])
+  AC_SUBST([CFLAG_VISIBILITY])
+  AC_SUBST([HAVE_VISIBILITY])
+  AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY],
+    [Define to 1 or 0, depending whether the compiler supports simple visibility declarations.])
+])
index 7241ba7cb9d7f611951d9bdc6511e3add4efa29b..eb0f7b4cf7334196986c20528ecb7db4889ea347 100644 (file)
@@ -50,6 +50,7 @@ AC_DEFUN([PANDORA_WARNINGS],[
 
     AS_IF([test "$ac_profiling" = "yes"],[
       CC_PROFILING="-pg"
+      GCOV_LIBS="-pg -lgcov"
       save_LIBS="${LIBS}"
       LIBS=""
       AC_CHECK_LIB(c_p, read)
@@ -61,7 +62,12 @@ AC_DEFUN([PANDORA_WARNINGS],[
     ])
 
     AS_IF([test "$ac_coverage" = "yes"],
-          [CC_COVERAGE="-fprofile-arcs -ftest-coverage"])
+          [
+            CC_COVERAGE="--coverage"
+            GCOV_LIBS="-lgcov"
+          ])
+
+
         
     AS_IF([test "$ac_cv_warnings_as_errors" = "yes"],
           [W_FAIL="-Werror"])
@@ -129,9 +135,9 @@ uint16_t x= htons(80);
 
     AS_IF([test "$INTELCC" = "yes"],[
       m4_if(PW_LESS_WARNINGS,[no],[
-        BASE_WARNINGS="-w1 -Wall -Werror -Wcheck -Wformat -Wp64 -Woverloaded-virtual -Wcast-qual"
+        BASE_WARNINGS="-w1 -Werror -Wcheck -Wformat -Wp64 -Woverloaded-virtual -Wcast-qual"
       ],[
-        BASE_WARNINGS="-w1 -Wall -Wcheck -Wformat -Wp64 -Woverloaded-virtual -Wcast-qual -diag-disable 981"
+        BASE_WARNINGS="-w1 -Wcheck -Wformat -Wp64 -Woverloaded-virtual -Wcast-qual -diag-disable 981"
       ])
       CC_WARNINGS="${BASE_WARNINGS}"
       CXX_WARNINGS="${BASE_WARNINGS}"
@@ -147,7 +153,25 @@ uint16_t x= htons(80);
       AS_IF([test "${ac_cv_assert}" = "no"],
             [NO_UNUSED="-Wno-unused-variable -Wno-unused-parameter"])
   
-      BASE_WARNINGS="${W_FAIL} -pedantic -Wall -Wextra -Wundef -Wshadow ${NO_UNUSED} ${F_DIAGNOSTICS_SHOW_OPTION} ${CFLAG_VISIBILITY} ${BASE_WARNINGS_FULL}"
+      AC_CACHE_CHECK([whether it is safe to use -Wextra],
+        [ac_cv_safe_to_use_Wextra_],
+        [save_CFLAGS="$CFLAGS"
+         CFLAGS="${W_FAIL} -pedantic -Wextra ${AM_CFLAGS} ${CFLAGS}"
+         AC_COMPILE_IFELSE([
+           AC_LANG_PROGRAM(
+           [[
+#include <stdio.h>
+           ]], [[]])
+        ],
+        [ac_cv_safe_to_use_Wextra_=yes],
+        [ac_cv_safe_to_use_Wextra_=no])
+      CFLAGS="$save_CFLAGS"])
+
+      BASE_WARNINGS="${W_FAIL} -pedantic -Wall -Wundef -Wshadow ${NO_UNUSED} ${F_DIAGNOSTICS_SHOW_OPTION} ${CFLAG_VISIBILITY} ${BASE_WARNINGS_FULL}"
+      AS_IF([test "$ac_cv_safe_to_use_Wextra_" = "yes"],
+            [BASE_WARNINGS="${BASE_WARNINGS} -Wextra"],
+            [BASE_WARNINGS="${BASE_WARNINGS} -W"])
+  
       CC_WARNINGS="${BASE_WARNINGS} -Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wmissing-declarations -Wcast-align ${CC_WARNINGS_FULL}"
       CXX_WARNINGS="${BASE_WARNINGS} -Woverloaded-virtual -Wnon-virtual-dtor -Wctor-dtor-privacy -Wno-long-long ${CXX_WARNINGS_FULL}"
 
@@ -199,8 +223,8 @@ template <> void C<int>::foo();
             AC_INCLUDES_DEFAULT])],
             [ac_cv_safe_to_use_Wredundant_decls_=yes],
             [ac_cv_safe_to_use_Wredundant_decls_=no])
-          CXXFLAGS="${save_CXXFLAGS}"
-          AC_LANG_POP()])
+         CXXFLAGS="${save_CXXFLAGS}"
+         AC_LANG_POP()])
       AS_IF([test "$ac_cv_safe_to_use_Wredundant_decls_" = "yes"],
             [CXX_WARNINGS="${CXX_WARNINGS} -Wredundant-decls"],
             [CXX_WARNINGS="${CXX_WARNINGS} -Wno-redundant-decls"])
@@ -240,13 +264,31 @@ inline const EnumDescriptor* GetEnumDescriptor<Table_TableOptions_RowType>() {
             [ac_cv_safe_to_use_Wattributes_=no])
           CXXFLAGS="${save_CXXFLAGS}"
           AC_LANG_POP()])
-      AS_IF([test "$ac_cv_safe_to_use_Wattributes_" = "yes"],
-            [],
-            [CXX_WARNINGS="${CXX_WARNINGS} -Wno-attributes"])
+      AC_CACHE_CHECK([whether it is safe to use -Wno-attributes],
+        [ac_cv_safe_to_use_Wno_attributes_],
+        [save_CFLAGS="$CFLAGS"
+         CFLAGS="${W_FAIL} -pedantic -Wno_attributes_ ${AM_CFLAGS} ${CFLAGS}"
+         AC_COMPILE_IFELSE([
+           AC_LANG_PROGRAM(
+           [[
+#include <stdio.h>
+           ]], [[]])
+        ],
+        [ac_cv_safe_to_use_Wno_attributes_=yes],
+        [ac_cv_safe_to_use_Wno_attributes_=no])
+      CFLAGS="$save_CFLAGS"])
+
+      dnl GCC 3.4 doesn't have -Wno-attributes, so we can't turn them off
+      dnl by using that. 
+      AS_IF([test "$ac_cv_safe_to_use_Wattributes_" != "yes"],[
+        AS_IF([test "$ac_cv_safe_to_use_Wno_attributes_" = "yes"],[
+          CC_WARNINGS="${CC_WARNINGS} -Wno-attributes"
+          NO_ATTRIBUTES="-Wno-attributes"])])
+  
   
       NO_REDUNDANT_DECLS="-Wno-redundant-decls"
       dnl TODO: Figure out a better way to deal with this:
-      PROTOSKIP_WARNINGS="-Wno-effc++ -Wno-shadow -Wno-missing-braces -Wno-attributes"
+      PROTOSKIP_WARNINGS="-Wno-effc++ -Wno-shadow -Wno-missing-braces ${NO_ATTRIBUTES}"
       NO_WERROR="-Wno-error"
       INNOBASE_SKIP_WARNINGS="-Wno-shadow -Wno-cast-align"
       
@@ -287,8 +329,8 @@ inline const EnumDescriptor* GetEnumDescriptor<Table_TableOptions_RowType>() {
       CXX_WARNINGS_FULL="-erroff=attrskipunsup,doubunder,reftotemp,inllargeuse,truncwarn1,signextwarn,inllargeint"
     ])
 
-    CC_WARNINGS="-v -errtags=yes ${W_FAIL} ${CC_WARNINGS_FULL}"
-    CXX_WARNINGS="+w +w2 -xwe -xport64 -errtags=yes ${CXX_WARNINGS_FULL} ${W_FAIL}"
+    CC_WARNINGS="-v -errtags=yes ${W_FAIL} ${CC_WARNINGS_FULL} ${CFLAG_VISIBILITY}"
+    CXX_WARNINGS="+w +w2 -xwe -xport64 -errtags=yes ${CXX_WARNINGS_FULL} ${W_FAIL} ${CFLAG_VISIBILITY}"
     PROTOSKIP_WARNINGS="-erroff=attrskipunsup,doubunder,reftotemp,wbadinitl,identexpected,inllargeuse,truncwarn1,signextwarn,partinit,notused,badargtype2w,wbadinit"
     NO_UNREACHED="-erroff=E_STATEMENT_NOT_REACHED"
     NO_WERROR="-errwarn=%none"
@@ -303,5 +345,6 @@ inline const EnumDescriptor* GetEnumDescriptor<Table_TableOptions_RowType>() {
   AC_SUBST(PROTOSKIP_WARNINGS)
   AC_SUBST(INNOBASE_SKIP_WARNINGS)
   AC_SUBST(NO_WERROR)
+  AC_SUBST([GCOV_LIBS])
 
 ])
diff --git a/m4/pandora_with_gettext.m4 b/m4/pandora_with_gettext.m4
new file mode 100644 (file)
index 0000000..2b22d1b
--- /dev/null
@@ -0,0 +1,41 @@
+dnl -*- mode: m4; c-basic-offset: 2; indent-tabs-mode: nil; -*-
+dnl vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+dnl   
+dnl pandora-build: A pedantic build system
+dnl Copyright (C) 2009 Sun Microsystems, Inc.
+dnl This file is free software; Sun Microsystems
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl From Monty Taylor
+
+AC_DEFUN([PANDORA_WITH_GETTEXT],[
+
+  m4_syscmd([if test -d po ; then
+    echo "# This file is auto-generated from configure. Do not edit directly" > po/POTFILES.in.stamp
+    PACKAGE=`grep ^AC_INIT configure.ac | cut -f2-3 -d[ | cut -f1 -d]`
+    for f in `find . | grep -v "${PACKAGE}-" | egrep '\.(cc|c|h|yy)$' | cut -c3- | sort`
+    do
+      if grep gettext.h "$f" | grep include >/dev/null 2>&1
+      then
+        echo "$f" >> po/POTFILES.in.stamp
+      fi
+    done
+    if diff po/POTFILES.in.stamp po/POTFILES.in >/dev/null 2>&1
+    then
+      rm po/POTFILES.in.stamp
+    else
+      mv po/POTFILES.in.stamp po/POTFILES.in
+    fi
+  fi])
+
+  AM_GNU_GETTEXT(external, need-formatstring-macros)
+  AM_GNU_GETTEXT_VERSION([0.17])
+  AS_IF([test "x$MSGMERGE" = "x" -o "x$MSGMERGE" = "x:"],[
+    AM_PATH_PROG_WITH_TEST(GMSGMERGE, gmsgmerge,
+      [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :)
+    MSGMERGE="${GMSGMERGE}"
+  ])
+  AM_CONDITIONAL([BUILD_GETTEXT],[test "x$MSGMERGE" != "x" -a "x$MSGMERGE" != "x:"])
+
+])
index 8797393b258519eb736f901e49951554848b7fa7..81fc5955dcc82998bdc5d520420c07a25a6f7e48 100644 (file)
@@ -3,7 +3,7 @@ dnl This file is free software; Sun Microsystems
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-AC_DEFUN([PANDORA_WITH_MEMCACHED],[
+AC_DEFUN([_PANDORA_SEARCH_MEMCACHED],[
 
   AC_ARG_WITH([memcached],
     [AS_HELP_STRING([--with-memcached],
@@ -13,21 +13,29 @@ AC_DEFUN([PANDORA_WITH_MEMCACHED],[
 
   # just ignore the user if --without-memcached is passed.. it is
   # only used by make test
-  AS_IF([test "x$withval" = "xno"],[
+  AS_IF([test "x$ac_cv_with_memcached" = "xno"],[
     ac_cv_with_memcached=memcached
     MEMCACHED_BINARY=memcached
   ],[
-    AS_IF([test -f "$withval"],[
-      ac_cv_with_memcached=$withval
-      MEMCACHED_BINARY=$withval
+    AS_IF([test -f "$ac_cv_with_memcached"],[
+      MEMCACHED_BINARY=$ac_cv_with_memcached
     ],[
       AC_PATH_PROG([MEMCACHED_BINARY], [$ac_cv_with_memcached], "no")
-      AS_IF([test "x$MEMCACHED_BINARY" = "xno"],[
-        AC_MSG_ERROR(["could not find memcached binary"])
-      ])
     ])
   ])
   AC_DEFINE_UNQUOTED([MEMCACHED_BINARY], "$MEMCACHED_BINARY", 
             [Name of the memcached binary used in make test])
+  AM_CONDITIONAL([HAVE_MEMCACHED],[test "x$MEMCACHED_BINARY" != "xno"])
+])
 
+AC_DEFUN([PANDORA_HAVE_MEMCACHED],[
+  AC_REQUIRE([_PANDORA_SEARCH_MEMCACHED])
 ])
+
+AC_DEFUN([PANDORA_REQUIRE_MEMCACHED],[
+  AC_REQUIRE([PANDORA_HAVE_MEMCACHED])
+  AS_IF([test "x$MEMCACHED_BINARY" = "xno"],[
+    AC_MSG_ERROR(["could not find memcached binary"])
+  ])
+])
+
index 348e7edd82b424d1e57c1755ccbcee4700091159..5b28c8ed0e233e28652bcdc0cb3d150a9ea9ddf2 100644 (file)
@@ -15,8 +15,12 @@ AC_DEFUN([PANDORA_WITH_PYTHON], [
   AC_ARG_WITH([python], 
     [AS_HELP_STRING([--with-python],
       [Build Python Bindings @<:@default=yes@:>@])],
-    [with_python=$withval], 
-    [with_python=yes])
+    [with_python=$withval
+     python_requested=$withval
+    ], 
+    [with_python=yes
+     python_requested=no
+    ])
 
   AS_IF([test "x$with_python" != "xno"],[
     AS_IF([test "x$with_python" != "xyes"],[PYTHON=$with_python])
@@ -24,5 +28,10 @@ AC_DEFUN([PANDORA_WITH_PYTHON], [
     AC_PYTHON_DEVEL()
     AS_IF([test "x$pythonexists" = "xno"],[with_python="no"])
   ])
+  AS_IF([test "x$with_python" = "xno" -a "$python_requested" = "yes"],[
+    AC_MSG_ERROR([Python support was explicity requested, but Python support
+                  was not found. Please correct your build environment and try
+                  again])
+  ])
   AM_CONDITIONAL(BUILD_PYTHON, [test "$with_python" = "yes"])
 ])
index 4ad67a9b2356ba45f231ee5975e8a7fd6f51616a..0119ed9408794082401c8829873c9a46c906f1c6 100644 (file)
@@ -17,7 +17,7 @@ AC_DEFUN([PANDORA_WITH_PYTHON3], [
     [AS_HELP_STRING([--with-python3],
       [Build Python3 Bindings @<:@default=yes@:>@])],[
         with_python3=$withval
-        python3_requested=yes
+        python3_requested=$withval
       ],[ 
         with_python3=yes
         python3_requested=no
diff --git a/m4/podchecker.m4 b/m4/podchecker.m4
new file mode 100644 (file)
index 0000000..ae10a6b
--- /dev/null
@@ -0,0 +1,7 @@
+AC_DEFUN([REQUIRE_PODCHECKER],[
+  AC_PATH_PROG([PODCHECKER], [podchecker],
+    "no", [$PATH:/usr/bin:/usr/local/bin:/usr/perl5/bin])
+  AS_IF([test "x$PODCHECKER" = "xno"],
+    AC_MSG_ERROR(["Could not find podchecker anywhere in path"]))
+  AC_SUBST(PODCHECKER)
+])
diff --git a/m4/visibility.m4 b/m4/visibility.m4
deleted file mode 100644 (file)
index 70bca56..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-# visibility.m4 serial 2 (gettext-0.18)
-dnl Copyright (C) 2005, 2008 Free Software Foundation, Inc.
-dnl This file is free software; the Free Software Foundation
-dnl gives unlimited permission to copy and/or distribute it,
-dnl with or without modifications, as long as this notice is preserved.
-
-dnl From Bruno Haible.
-
-dnl Tests whether the compiler supports the command-line option
-dnl -fvisibility=hidden and the function and variable attributes
-dnl __attribute__((__visibility__("hidden"))) and
-dnl __attribute__((__visibility__("default"))).
-dnl Does *not* test for __visibility__("protected") - which has tricky
-dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on
-dnl MacOS X.
-dnl Does *not* test for __visibility__("internal") - which has processor
-dnl dependent semantics.
-dnl Does *not* test for #pragma GCC visibility push(hidden) - which is
-dnl "really only recommended for legacy code".
-dnl Set the variable CFLAG_VISIBILITY.
-dnl Defines and sets the variable HAVE_VISIBILITY.
-
-AC_DEFUN([gl_VISIBILITY],
-[
-  AC_REQUIRE([AC_PROG_CC])
-  CFLAG_VISIBILITY=
-  HAVE_VISIBILITY=0
-  if test -n "$GCC"; then
-    AC_MSG_CHECKING([for simple visibility declarations])
-    AC_CACHE_VAL([gl_cv_cc_visibility], [
-      gl_save_CFLAGS="$CFLAGS"
-      CFLAGS="$CFLAGS -fvisibility=hidden"
-      AC_TRY_COMPILE(
-        [extern __attribute__((__visibility__("hidden"))) int hiddenvar;
-         extern __attribute__((__visibility__("default"))) int exportedvar;
-         extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void);
-         extern __attribute__((__visibility__("default"))) int exportedfunc (void);],
-        [],
-        [gl_cv_cc_visibility=yes],
-        [gl_cv_cc_visibility=no])
-      CFLAGS="$gl_save_CFLAGS"])
-    AC_MSG_RESULT([$gl_cv_cc_visibility])
-    if test $gl_cv_cc_visibility = yes; then
-      CFLAG_VISIBILITY="-fvisibility=hidden"
-      HAVE_VISIBILITY=1
-    fi
-  fi
-  AC_SUBST([CFLAG_VISIBILITY])
-  AC_SUBST([HAVE_VISIBILITY])
-  AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY],
-    [Define to 1 or 0, depending whether the compiler supports simple visibility declarations.])
-])
diff --git a/support/Makefile.am b/support/Makefile.am
deleted file mode 100644 (file)
index 48fab4c..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-EXTRA_DIST = libmemcached.spec set_benchmark.sh libmemcached-fc.spec.in
-
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libmemcached.pc
diff --git a/support/include.am b/support/include.am
new file mode 100644 (file)
index 0000000..d9287e4
--- /dev/null
@@ -0,0 +1,11 @@
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+
+EXTRA_DIST += \
+       support/libmemcached.spec \
+       support/libmemcached-fc.spec.in \
+       support/set_benchmark.sh 
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = support/libmemcached.pc
index 1f340e468b85e6855f3a12a38f6e159a7a95c73d..ea4817aa6f0a295cff99f20436d074f941fdca3a 100644 (file)
@@ -4,7 +4,7 @@ Version: @VERSION@
 Release:   1
 License:   BSD
 Group:     System Environment/Libraries
-URL:       http://tangent.org/552/libmemcached.html
+URL:       http://launchpad.net/libmemcached
 Source0:   http://download.tangent.org/libmemcached-%{version}.tar.gz
 
 # For test suite
@@ -27,6 +27,7 @@ memstat - Dump the stats of your servers to standard output.
 memslap - Generate testing loads on a memcached cluster.
 memcp - Copy files to memcached servers.
 memerror - Creates human readable messages from libmemecached error codes.
+memcapable - Verify a memcached server for protocol behavior.
 
 
 %package devel
@@ -77,31 +78,155 @@ you will need to install %{name}-devel.
 %defattr (-,root,root,-) 
 %doc AUTHORS COPYING NEWS README THANKS TODO
 %{_bindir}/mem*
-%exclude %{_libdir}/libmemcached.a
 %exclude %{_libdir}/libmemcached.la
-%exclude %{_libdir}/libmemcachedutil.a
-%exclude %{_libdir}/libmemcachedprotocol.a
+%exclude %{_libdir}/libhashkit.la
 %exclude %{_libdir}/libmemcachedutil.la
 %exclude %{_libdir}/libmemcachedprotocol.la
+%{_libdir}/libhashkit.so.*
 %{_libdir}/libmemcached.so.*
 %{_libdir}/libmemcachedutil.so.*
 %{_libdir}/libmemcachedprotocol.so.*
-%{_mandir}/man1/mem*
+%{_mandir}/man1/memcapable.1.gz
+%{_mandir}/man1/memcat.1.gz
+%{_mandir}/man1/memcp.1.gz
+%{_mandir}/man1/memdump.1.gz
+%{_mandir}/man1/memerror.1.gz
+%{_mandir}/man1/memflush.1.gz
+%{_mandir}/man1/memrm.1.gz
+%{_mandir}/man1/memslap.1.gz
+%{_mandir}/man1/memstat.1.gz
 
 
 %files devel
 %defattr (-,root,root,-) 
 %doc examples
-%{_includedir}/libmemcached
+%{_includedir}/libhashkit/algorithm.h
+%{_includedir}/libhashkit/behavior.h
+%{_includedir}/libhashkit/hashkit.h
+%{_includedir}/libhashkit/strerror.h
+%{_includedir}/libhashkit/types.h
+%{_includedir}/libhashkit/visibility.h
+%{_includedir}/libmemcached/analyze.h
+%{_includedir}/libmemcached/auto.h
+%{_includedir}/libmemcached/behavior.h
+%{_includedir}/libmemcached/callback.h
+%{_includedir}/libmemcached/configure.h
+%{_includedir}/libmemcached/constants.h
+%{_includedir}/libmemcached/dump.h
+%{_includedir}/libmemcached/exception.hpp
+%{_includedir}/libmemcached/get.h
+%{_includedir}/libmemcached/memcached.h
+%{_includedir}/libmemcached/memcached.hpp
+%{_includedir}/libmemcached/memcached_util.h
+%{_includedir}/libmemcached/protocol/cache.h
+%{_includedir}/libmemcached/protocol/callback.h
+%{_includedir}/libmemcached/protocol_handler.h
+%{_includedir}/libmemcached/result.h
+%{_includedir}/libmemcached/server.h
+%{_includedir}/libmemcached/stats.h
+%{_includedir}/libmemcached/storage.h
+%{_includedir}/libmemcached/string.h
+%{_includedir}/libmemcached/types.h
+%{_includedir}/libmemcached/util/pool.h
+%{_includedir}/libmemcached/visibility.h
+%{_includedir}/libmemcached/watchpoint.h
+%{_includedir}/libmemcached/memcached/protocol_binary.h
+%{_libdir}/libhashkit.so
 %{_libdir}/libmemcached.so
-%{_libdir}/libmemcachedutil.so
 %{_libdir}/libmemcachedprotocol.so
+%{_libdir}/libmemcachedutil.so
 %{_libdir}/pkgconfig/libmemcached.pc
-%{_mandir}/man3/libmemcached*.3.gz
-%{_mandir}/man3/memcached_*.3.gz
+%{_mandir}/man3/hashkit_clone.3.gz
+%{_mandir}/man3/hashkit_crc32.3.gz
+%{_mandir}/man3/hashkit_create.3.gz
+%{_mandir}/man3/hashkit_fnv1_32.3.gz
+%{_mandir}/man3/hashkit_fnv1_64.3.gz
+%{_mandir}/man3/hashkit_fnv1a_32.3.gz
+%{_mandir}/man3/hashkit_fnv1a_64.3.gz
+%{_mandir}/man3/hashkit_free.3.gz
+%{_mandir}/man3/hashkit_functions.3.gz
+%{_mandir}/man3/hashkit_hsieh.3.gz
+%{_mandir}/man3/hashkit_is_allocated.3.gz
+%{_mandir}/man3/hashkit_jenkins.3.gz
+%{_mandir}/man3/hashkit_md5.3.gz
+%{_mandir}/man3/hashkit_murmur.3.gz
+%{_mandir}/man3/hashkit_value.3.gz
+%{_mandir}/man3/libmemcached.3.gz
+%{_mandir}/man3/libmemcached_examples.3.gz
+%{_mandir}/man3/libmemcachedutil.3.gz
+%{_mandir}/man3/memcached_add.3.gz
+%{_mandir}/man3/memcached_add_by_key.3.gz
+%{_mandir}/man3/memcached_analyze.3.gz
+%{_mandir}/man3/memcached_append.3.gz
+%{_mandir}/man3/memcached_append_by_key.3.gz
+%{_mandir}/man3/memcached_behavior_get.3.gz
+%{_mandir}/man3/memcached_behavior_set.3.gz
+%{_mandir}/man3/memcached_callback_get.3.gz
+%{_mandir}/man3/memcached_callback_set.3.gz
+%{_mandir}/man3/memcached_cas.3.gz
+%{_mandir}/man3/memcached_cas_by_key.3.gz
+%{_mandir}/man3/memcached_clone.3.gz
+%{_mandir}/man3/memcached_create.3.gz
+%{_mandir}/man3/memcached_decrement.3.gz
+%{_mandir}/man3/memcached_decrement_with_initial.3.gz
+%{_mandir}/man3/memcached_delete.3.gz
+%{_mandir}/man3/memcached_delete_by_key.3.gz
+%{_mandir}/man3/memcached_dump.3.gz
+%{_mandir}/man3/memcached_fetch.3.gz
+%{_mandir}/man3/memcached_fetch_execute.3.gz
+%{_mandir}/man3/memcached_fetch_result.3.gz
+%{_mandir}/man3/memcached_flush_buffers.3.gz
+%{_mandir}/man3/memcached_free.3.gz
+%{_mandir}/man3/memcached_generate_hash_value.3.gz
+%{_mandir}/man3/memcached_get.3.gz
+%{_mandir}/man3/memcached_get_by_key.3.gz
+%{_mandir}/man3/memcached_get_memory_allocators.3.gz
+%{_mandir}/man3/memcached_get_user_data.3.gz
+%{_mandir}/man3/memcached_increment.3.gz
+%{_mandir}/man3/memcached_increment_with_initial.3.gz
+%{_mandir}/man3/memcached_lib_version.3.gz
+%{_mandir}/man3/memcached_mget.3.gz
+%{_mandir}/man3/memcached_mget_by_key.3.gz
+%{_mandir}/man3/memcached_mget_execute.3.gz
+%{_mandir}/man3/memcached_mget_execute_by_key.3.gz
+%{_mandir}/man3/memcached_pool_behavior_get.3.gz
+%{_mandir}/man3/memcached_pool_behavior_set.3.gz
+%{_mandir}/man3/memcached_pool_create.3.gz
+%{_mandir}/man3/memcached_pool_destroy.3.gz
+%{_mandir}/man3/memcached_pool_pop.3.gz
+%{_mandir}/man3/memcached_pool_push.3.gz
+%{_mandir}/man3/memcached_prepend.3.gz
+%{_mandir}/man3/memcached_prepend_by_key.3.gz
+%{_mandir}/man3/memcached_quit.3.gz
+%{_mandir}/man3/memcached_replace.3.gz
+%{_mandir}/man3/memcached_replace_by_key.3.gz
+%{_mandir}/man3/memcached_server_add.3.gz
+%{_mandir}/man3/memcached_server_count.3.gz
+%{_mandir}/man3/memcached_server_cursor.3.gz
+%{_mandir}/man3/memcached_server_list.3.gz
+%{_mandir}/man3/memcached_server_list_append.3.gz
+%{_mandir}/man3/memcached_server_list_count.3.gz
+%{_mandir}/man3/memcached_server_list_free.3.gz
+%{_mandir}/man3/memcached_server_push.3.gz
+%{_mandir}/man3/memcached_servers_parse.3.gz
+%{_mandir}/man3/memcached_set.3.gz
+%{_mandir}/man3/memcached_set_by_key.3.gz
+%{_mandir}/man3/memcached_set_memory_allocators.3.gz
+%{_mandir}/man3/memcached_set_user_data.3.gz
+%{_mandir}/man3/memcached_stat.3.gz
+%{_mandir}/man3/memcached_stat_get_keys.3.gz
+%{_mandir}/man3/memcached_stat_get_value.3.gz
+%{_mandir}/man3/memcached_stat_servername.3.gz
+%{_mandir}/man3/memcached_strerror.3.gz
+%{_mandir}/man3/memcached_verbosity.3.gz
+%{_mandir}/man3/memcached_version.3.gz
+
 
 
 %changelog
+* Fri Jan  8 2010 Brian Aker <brian@tangent.org> - 0.37-1
+- Modified to be explicit in install include files. 
+
 * Sat Apr 25 2009 Remi Collet <rpms@famillecollet.com> - 0.28-1
 - Initial RPM from Brian Aker spec
 - create -devel subpackage
diff --git a/tests/Makefile.am b/tests/Makefile.am
deleted file mode 100644 (file)
index 9cdda76..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-LDADDS = $(top_builddir)/libmemcached/libmemcached.la
-
-if BUILD_LIBMEMCACHEDUTIL
-LDADDS+= $(top_builddir)/libmemcached/libmemcachedutil.la
-endif
-
-EXTRA_DIST = output.res output2.res\
-               r/memcat.res\
-               r/memcp.res\
-               r/memrm.res\
-               r/memslap.res\
-               r/memstat.res\
-               t/memcat.test\
-               t/memcp.test\
-               t/memrm.test\
-               t/memslap.test\
-               t/memstat.test
-
-LIBS =
-
-noinst_HEADERS = test.h server.h ketama_test_cases.h ketama_test_cases_spy.h
-noinst_PROGRAMS = testapp testplus udptest atomsmasher startservers
-noinst_LTLIBRARIES= libserver.la libtest.la
-
-libserver_la_SOURCES= server.c
-libtest_la_SOURCES= test.c
-
-testapp_CFLAGS= $(AM_CFLAGS) $(NO_CONVERSION) $(NO_STRICT_ALIASING)
-testapp_SOURCES = function.c
-testapp_LDADD = $(top_builddir)/clients/libgenexec.la libtest.la libserver.la $(LDADDS)
-
-testplus_SOURCES = plus.cpp
-testplus_LDADD = libtest.la libserver.la $(LDADDS)
-
-udptest_SOURCES = udp.c
-udptest_LDADD = libtest.la libserver.la $(LDADDS)
-
-atomsmasher_SOURCES = atomsmasher.c
-atomsmasher_LDADD = $(top_builddir)/clients/libgenexec.la libtest.la libserver.la $(LDADDS)
-
-startservers_SOURCES = start.c
-startservers_LDADD = libserver.la $(LDADDS)
-
-record:
-       ./testapp > output.res
-       ./testplus > output_plus.res
-
-client-record:
-       sh t/memcat.test > r/memcat.res
-       sh t/memcp.test > r/memcp.res
-       sh t/memrm.test > r/memrm.res
-       sh t/memslap.test > r/memslap.res
-       sh t/memstat.test > r/memstat.res
-
-record-extended:
-       ./testapp extended > output2.res
-
-test: testapp testplus library_test memcapable
-       echo "Tests completed"
-
-library_test:
-       ./testapp > output.cmp
-       diff output.res output.cmp
-#      ./testplus > output_plus.cmp
-#      diff output_plus.res output_plus.cmp
-
-memcapable:
-       @MEMC_BINARY@ -d -P /tmp/Xumemc.pid -p 12555
-       @$(top_builddir)/clients/memcapable -p 12555 || echo "Your memcached server does not support all commands"
-       @cat /tmp/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
-       @rm /tmp/Xumemc.pid
-
-clients:
-       @MEMC_BINARY@ -d -P /tmp/Xumemc.pid -p 12555
-       export MEMCACHED_SERVERS="localhost:12555"
-       sh t/memcat.test > r/memcat.cmp
-       diff r/memcat.res r/memcat.cmp
-       sh t/memcp.test > r/memcp.cmp
-       diff r/memcp.res r/memcp.cmp
-       sh t/memrm.test > r/memrm.cmp
-       diff r/memrm.res r/memrm.cmp
-       sh t/memslap.test > r/memslap.cmp
-       diff r/memslap.res r/memslap.cmp
-       sh t/memstat.test > r/memstat.cmp
-       diff r/memstat.res r/memstat.cmp
-       cat /tmp/Xumemc.pid | xargs kill
-       rm /tmp/Xumemc.pid
-
-valgrind:
-       libtool --mode=execute valgrind --leak-check=yes --show-reachable=yes  testapp
-
-cachegrind:
-       rm -f cachegrind.out.*
-       libtool --mode=execute valgrind --tool=cachegrind  --branch-sim=yes testapp
-       cg_annotate cachegrind.out.* --auto=yes > /tmp/cachegrind.out
-
-callgrind:
-       rm -f callgrind.out.*
-       libtool --mode=execute valgrind --tool=callgrind  testapp
-       callgrind_annotate callgrind.out.* --auto=yes > /tmp/callgrind.out
-
-helgrind:
-       rm -f helgrind.out.*
-       libtool --mode=execute valgrind --tool=helgrind  testapp
-
-helgrind-slap:
-       libtool --mode=execute valgrind --tool=helgrind  ${top_builddir}/clients/memslap --server=localhost --concurrency=30
-
-test-no-outputdiff: testapp
-       ./testapp > /dev/null
-       @echo "Test completed"
index 19ad086ad624565330890fcdf0030e1ae39267f0..490a3f92f202ffc8d8317efee6253b8cd15dd80b 100644 (file)
@@ -1,9 +1,19 @@
+/* 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:
+ *
+ */
+
 /*
   Sample test application.
 */
 #include "libmemcached/common.h"
 
-#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -46,11 +56,10 @@ static test_return_t cleanup_pairs(memcached_st *memc __attribute__((unused)))
 
 static test_return_t generate_pairs(memcached_st *memc __attribute__((unused)))
 {
-  unsigned long long x;
   global_pairs= pairs_generate(GLOBAL_COUNT, 400);
   global_count= GLOBAL_COUNT;
 
-  for (x= 0; x < global_count; x++)
+  for (size_t x= 0; x < global_count; x++)
   {
     global_keys[x]= global_pairs[x].key; 
     global_keys_length[x]=  global_pairs[x].key_length;
@@ -61,14 +70,13 @@ static test_return_t generate_pairs(memcached_st *memc __attribute__((unused)))
 
 static test_return_t drizzle(memcached_st *memc)
 {
-  unsigned int x;
-  memcached_return rc;
+  memcached_return_t rc;
   char *return_value;
   size_t return_value_length;
   uint32_t flags;
 
 infinite:
-  for (x= 0; x < TEST_COUNTER; x++)
+  for (size_t x= 0; x < TEST_COUNTER; x++)
   {
     uint32_t test_bit;
     uint8_t which;
@@ -81,9 +89,13 @@ infinite:
       return_value= memcached_get(memc, global_keys[test_bit], global_keys_length[test_bit],
                                   &return_value_length, &flags, &rc);
       if (rc == MEMCACHED_SUCCESS && return_value)
+      {
         free(return_value);
+      }
       else if (rc == MEMCACHED_NOTFOUND)
+      {
         continue;
+      }
       else
       {
         WATCHPOINT_ERROR(rc);
@@ -108,45 +120,14 @@ infinite:
   if (getenv("MEMCACHED_ATOM_BURIN_IN"))
     goto infinite;
 
-  return 0;
+  return TEST_SUCCESS;
 }
 
-static memcached_return pre_nonblock(memcached_st *memc)
+static test_return_t pre_nonblock(memcached_st *memc)
 {
   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
 
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return pre_md5(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_MD5);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return pre_hsieh(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_HSIEH);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return enable_consistent(memcached_st *memc)
-{
-  memcached_server_distribution value= MEMCACHED_DISTRIBUTION_CONSISTENT;
-  memcached_hash hash;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, value);
-  pre_hsieh(memc);
-
-  value= (memcached_server_distribution)memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION);
-  assert(value == MEMCACHED_DISTRIBUTION_CONSISTENT);
-
-  hash= (memcached_hash)memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_HASH);
-  assert(hash == MEMCACHED_HASH_HSIEH);
-
-
-  return MEMCACHED_SUCCESS;
+  return TEST_SUCCESS;
 }
 
 /* 
@@ -155,7 +136,7 @@ static memcached_return enable_consistent(memcached_st *memc)
 */
 static test_return_t add_test(memcached_st *memc)
 {
-  memcached_return rc;
+  memcached_return_t rc;
   const char *key= "foo";
   const char *value= "when we sanitize";
   unsigned long long setting_value;
@@ -165,7 +146,7 @@ static test_return_t add_test(memcached_st *memc)
   rc= memcached_set(memc, key, strlen(key), 
                     value, strlen(value),
                     (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
   memcached_quit(memc);
   rc= memcached_add(memc, key, strlen(key), 
                     value, strlen(value),
@@ -173,9 +154,13 @@ static test_return_t add_test(memcached_st *memc)
 
   /* Too many broken OS'es have broken loopback in async, so we can't be sure of the result */
   if (setting_value)
-    assert(rc == MEMCACHED_NOTSTORED || rc == MEMCACHED_STORED);
+  {
+    test_truth(rc == MEMCACHED_NOTSTORED || rc == MEMCACHED_STORED);
+  }
   else
-    assert(rc == MEMCACHED_NOTSTORED);
+  {
+    test_truth(rc == MEMCACHED_NOTSTORED);
+  }
 
   return 0;
 }
@@ -186,8 +171,7 @@ static test_return_t add_test(memcached_st *memc)
  */
 static test_return_t many_adds(memcached_st *memc)
 {
-  unsigned int i;
-  for (i = 0; i < TEST_COUNTER; i++)
+  for (size_t x= 0; x < TEST_COUNTER; x++)
   {
     add_test(memc);
   }
@@ -195,51 +179,40 @@ static test_return_t many_adds(memcached_st *memc)
 }
 
 test_st smash_tests[] ={
-  {"generate_pairs", 1, generate_pairs },
-  {"drizzle", 1, drizzle },
-  {"cleanup", 1, cleanup_pairs },
-  {"many_adds", 1, many_adds },
+  {"generate_pairs", 1, (test_callback_fn)generate_pairs },
+  {"drizzle", 1, (test_callback_fn)drizzle },
+  {"cleanup", 1, (test_callback_fn)cleanup_pairs },
+  {"many_adds", 1, (test_callback_fn)many_adds },
   {0, 0, 0}
 };
 
 
 collection_st collection[] ={
   {"smash", 0, 0, smash_tests},
-  {"smash_hsieh", pre_hsieh, 0, smash_tests},
-  {"smash_hsieh_consistent", enable_consistent, 0, smash_tests},
-  {"smash_md5", pre_md5, 0, smash_tests},
-  {"smash_nonblock", pre_nonblock, 0, smash_tests},
+  {"smash_nonblock", (test_callback_fn)pre_nonblock, 0, smash_tests},
   {0, 0, 0, 0}
 };
 
+
 #define SERVERS_TO_CREATE 5
 
-static void *world_create(void)
-{
-  server_startup_st *construct;
+#include "libmemcached_world.h"
 
-  construct= (server_startup_st *)malloc(sizeof(server_startup_st));
-  memset(construct, 0, sizeof(server_startup_st));
-  construct->count= SERVERS_TO_CREATE;
-  construct->udp= 0;
-  server_startup(construct);
+void get_world(world_st *world)
+{
+  world->collections= collection;
 
-  return construct;
-}
+  world->create= (test_callback_create_fn)world_create;
+  world->destroy= (test_callback_fn)world_destroy;
 
-static void world_destroy(void *p)
-{
-  server_startup_st *construct= (server_startup_st *)p;
-  memcached_server_st *servers= (memcached_server_st *)construct->servers;
-  memcached_server_list_free(servers);
+  world->test.startup= (test_callback_fn)world_test_startup;
+  world->test.flush= (test_callback_fn)world_flush;
+  world->test.pre_run= (test_callback_fn)world_pre_run;
+  world->test.post_run= (test_callback_fn)world_post_run;
+  world->test.on_error= (test_callback_error_fn)world_on_error;
 
-  server_shutdown(construct);
-  free(construct);
-}
+  world->collection.startup= (test_callback_fn)world_container_startup;
+  world->collection.shutdown= (test_callback_fn)world_container_shutdown;
 
-void get_world(world_st *world)
-{
-  world->collections= collection;
-  world->create= world_create;
-  world->destroy= world_destroy;
+  world->runner= &defualt_libmemcached_runner;
 }
diff --git a/tests/function.c b/tests/function.c
deleted file mode 100644 (file)
index da103ca..0000000
+++ /dev/null
@@ -1,5675 +0,0 @@
-/*
-  Sample test application.
-*/
-
-#include "libmemcached/common.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <signal.h>
-#include <unistd.h>
-#include <time.h>
-#include "server.h"
-#include "clients/generator.h"
-#include "clients/execute.h"
-
-#ifndef INT64_MAX
-#define INT64_MAX LONG_MAX
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX INT_MAX
-#endif
-
-
-#include "test.h"
-
-#ifdef HAVE_LIBMEMCACHEDUTIL
-#include <pthread.h>
-#include "libmemcached/memcached_util.h"
-#endif
-
-#define GLOBAL_COUNT 10000
-#define GLOBAL2_COUNT 100
-#define SERVERS_TO_CREATE 5
-static uint32_t global_count;
-
-static pairs_st *global_pairs;
-static const char *global_keys[GLOBAL_COUNT];
-static size_t global_keys_length[GLOBAL_COUNT];
-
-static test_return_t  init_test(memcached_st *not_used __attribute__((unused)))
-{
-  memcached_st memc;
-
-  (void)memcached_create(&memc);
-  memcached_free(&memc);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  server_list_null_test(memcached_st *ptr __attribute__((unused)))
-{
-  memcached_server_st *server_list;
-  memcached_return rc;
-
-  server_list= memcached_server_list_append_with_weight(NULL, NULL, 0, 0, NULL);
-  assert(server_list == NULL);
-
-  server_list= memcached_server_list_append_with_weight(NULL, "localhost", 0, 0, NULL);
-  assert(server_list == NULL);
-
-  server_list= memcached_server_list_append_with_weight(NULL, NULL, 0, 0, &rc);
-  assert(server_list == NULL);
-
-  return TEST_SUCCESS;
-}
-
-#define TEST_PORT_COUNT 7
-uint32_t test_ports[TEST_PORT_COUNT];
-
-static memcached_return  server_display_function(memcached_st *ptr __attribute__((unused)), memcached_server_st *server, void *context)
-{
-  /* Do Nothing */
-  uint32_t bigger= *((uint32_t *)(context));
-  assert(bigger <= server->port);
-  *((uint32_t *)(context))= server->port;
-
-  return MEMCACHED_SUCCESS;
-}
-
-static test_return_t  server_sort_test(memcached_st *ptr __attribute__((unused)))
-{
-  uint32_t x;
-  uint32_t bigger= 0; /* Prime the value for the assert in server_display_function */
-  memcached_return rc;
-  memcached_server_function callbacks[1];
-  memcached_st *local_memc;
-
-  local_memc= memcached_create(NULL);
-  assert(local_memc);
-  memcached_behavior_set(local_memc, MEMCACHED_BEHAVIOR_SORT_HOSTS, 1);
-
-  for (x= 0; x < TEST_PORT_COUNT; x++)
-  {
-    test_ports[x]= (uint32_t)random() % 64000;
-    rc= memcached_server_add_with_weight(local_memc, "localhost", test_ports[x], 0);
-    assert(local_memc->number_of_hosts == x + 1);
-    assert(local_memc->hosts[0].count == x+1);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  callbacks[0]= server_display_function;
-  memcached_server_cursor(local_memc, callbacks, (void *)&bigger,  1);
-
-
-  memcached_free(local_memc);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  server_sort2_test(memcached_st *ptr __attribute__((unused)))
-{
-  uint32_t bigger= 0; /* Prime the value for the assert in server_display_function */
-  memcached_return rc;
-  memcached_server_function callbacks[1];
-  memcached_st *local_memc;
-
-  local_memc= memcached_create(NULL);
-  assert(local_memc);
-  rc= memcached_behavior_set(local_memc, MEMCACHED_BEHAVIOR_SORT_HOSTS, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_server_add_with_weight(local_memc, "MEMCACHED_BEHAVIOR_SORT_HOSTS", 43043, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(local_memc->hosts[0].port == 43043);
-
-  rc= memcached_server_add_with_weight(local_memc, "MEMCACHED_BEHAVIOR_SORT_HOSTS", 43042, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(local_memc->hosts[0].port == 43042);
-  assert(local_memc->hosts[1].port == 43043);
-
-  callbacks[0]= server_display_function;
-  memcached_server_cursor(local_memc, callbacks, (void *)&bigger,  1);
-
-
-  memcached_free(local_memc);
-
-  return TEST_SUCCESS;
-}
-
-static memcached_return  server_display_unsort_function(memcached_st *ptr __attribute__((unused)), memcached_server_st *server, void *context)
-{
-  /* Do Nothing */
-  uint32_t x= *((uint32_t *)(context));
-
-  assert(test_ports[x] == server->port);
-  *((uint32_t *)(context))= ++x;
-
-  return MEMCACHED_SUCCESS;
-}
-
-static test_return_t  server_unsort_test(memcached_st *ptr __attribute__((unused)))
-{
-  uint32_t x;
-  uint32_t counter= 0; /* Prime the value for the assert in server_display_function */
-  uint32_t bigger= 0; /* Prime the value for the assert in server_display_function */
-  memcached_return rc;
-  memcached_server_function callbacks[1];
-  memcached_st *local_memc;
-
-  local_memc= memcached_create(NULL);
-  assert(local_memc);
-
-  for (x= 0; x < TEST_PORT_COUNT; x++)
-  {
-    test_ports[x]= (uint32_t)(random() % 64000);
-    rc= memcached_server_add_with_weight(local_memc, "localhost", test_ports[x], 0);
-    assert(local_memc->number_of_hosts == x+1);
-    assert(local_memc->hosts[0].count == x+1);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  callbacks[0]= server_display_unsort_function;
-  memcached_server_cursor(local_memc, callbacks, (void *)&counter,  1);
-
-  /* Now we sort old data! */
-  memcached_behavior_set(local_memc, MEMCACHED_BEHAVIOR_SORT_HOSTS, 1);
-  callbacks[0]= server_display_function;
-  memcached_server_cursor(local_memc, callbacks, (void *)&bigger,  1);
-
-
-  memcached_free(local_memc);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  allocation_test(memcached_st *not_used __attribute__((unused)))
-{
-  memcached_st *memc;
-  memc= memcached_create(NULL);
-  assert(memc);
-  memcached_free(memc);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  clone_test(memcached_st *memc)
-{
-  /* All null? */
-  {
-    memcached_st *memc_clone;
-    memc_clone= memcached_clone(NULL, NULL);
-    assert(memc_clone);
-    memcached_free(memc_clone);
-  }
-
-  /* Can we init from null? */
-  {
-    memcached_st *memc_clone;
-    memc_clone= memcached_clone(NULL, memc);
-    assert(memc_clone);
-
-    assert(memc_clone->call_free == memc->call_free);
-    assert(memc_clone->call_malloc == memc->call_malloc);
-    assert(memc_clone->call_realloc == memc->call_realloc);
-    assert(memc_clone->call_calloc == memc->call_calloc);
-    assert(memc_clone->connect_timeout == memc->connect_timeout);
-    assert(memc_clone->delete_trigger == memc->delete_trigger);
-    assert(memc_clone->distribution == memc->distribution);
-    assert(memc_clone->flags == memc->flags);
-    assert(memc_clone->get_key_failure == memc->get_key_failure);
-    assert(memc_clone->hash == memc->hash);
-    assert(memc_clone->hash_continuum == memc->hash_continuum);
-    assert(memc_clone->io_bytes_watermark == memc->io_bytes_watermark);
-    assert(memc_clone->io_msg_watermark == memc->io_msg_watermark);
-    assert(memc_clone->io_key_prefetch == memc->io_key_prefetch);
-    assert(memc_clone->on_cleanup == memc->on_cleanup);
-    assert(memc_clone->on_clone == memc->on_clone);
-    assert(memc_clone->poll_timeout == memc->poll_timeout);
-    assert(memc_clone->rcv_timeout == memc->rcv_timeout);
-    assert(memc_clone->recv_size == memc->recv_size);
-    assert(memc_clone->retry_timeout == memc->retry_timeout);
-    assert(memc_clone->send_size == memc->send_size);
-    assert(memc_clone->server_failure_limit == memc->server_failure_limit);
-    assert(memc_clone->snd_timeout == memc->snd_timeout);
-    assert(memc_clone->user_data == memc->user_data);
-
-    memcached_free(memc_clone);
-  }
-
-  /* Can we init from struct? */
-  {
-    memcached_st declared_clone;
-    memcached_st *memc_clone;
-    memset(&declared_clone, 0 , sizeof(memcached_st));
-    memc_clone= memcached_clone(&declared_clone, NULL);
-    assert(memc_clone);
-    memcached_free(memc_clone);
-  }
-
-  /* Can we init from struct? */
-  {
-    memcached_st declared_clone;
-    memcached_st *memc_clone;
-    memset(&declared_clone, 0 , sizeof(memcached_st));
-    memc_clone= memcached_clone(&declared_clone, memc);
-    assert(memc_clone);
-    memcached_free(memc_clone);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t userdata_test(memcached_st *memc)
-{
-  void* foo= NULL;
-  assert(memcached_set_user_data(memc, foo) == NULL);
-  assert(memcached_get_user_data(memc) == foo);
-  assert(memcached_set_user_data(memc, NULL) == foo);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  connection_test(memcached_st *memc)
-{
-  memcached_return rc;
-
-  rc= memcached_server_add_with_weight(memc, "localhost", 0, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  error_test(memcached_st *memc)
-{
-  memcached_return rc;
-  uint32_t values[] = { 851992627U, 2337886783U, 3196981036U, 4001849190U,
-                        982370485U, 1263635348U, 4242906218U, 3829656100U,
-                        1891735253U, 334139633U, 2257084983U, 3088286104U,
-                        13199785U, 2542027183U, 1097051614U, 199566778U,
-                        2748246961U, 2465192557U, 1664094137U, 2405439045U,
-                        1842224848U, 692413798U, 3479807801U, 919913813U,
-                        4269430871U, 610793021U, 527273862U, 1437122909U,
-                        2300930706U, 2943759320U, 674306647U, 2400528935U,
-                        54481931U, 4186304426U, 1741088401U, 2979625118U,
-                        4159057246U, 3425930182U, 2593724503U};
-
-  // You have updated the memcache_error messages but not updated docs/tests.
-  assert(MEMCACHED_MAXIMUM_RETURN == 39);
-  for (rc= MEMCACHED_SUCCESS; rc < MEMCACHED_MAXIMUM_RETURN; rc++)
-  {
-    uint32_t hash_val;
-    const char *msg=  memcached_strerror(memc, rc);
-    hash_val= memcached_generate_hash_value(msg, strlen(msg),
-                                            MEMCACHED_HASH_JENKINS);
-    assert(values[rc] == hash_val);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  set_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  const char *value= "when we sanitize";
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  append_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "fig";
-  const char *in_value= "we";
-  char *out_value= NULL;
-  size_t value_length;
-  uint32_t flags;
-
-  rc= memcached_flush(memc, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_set(memc, key, strlen(key),
-                    in_value, strlen(in_value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_append(memc, key, strlen(key),
-                       " the", strlen(" the"),
-                       (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_append(memc, key, strlen(key),
-                       " people", strlen(" people"),
-                       (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  out_value= memcached_get(memc, key, strlen(key),
-                       &value_length, &flags, &rc);
-  assert(!memcmp(out_value, "we the people", strlen("we the people")));
-  assert(strlen("we the people") == value_length);
-  assert(rc == MEMCACHED_SUCCESS);
-  free(out_value);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  append_binary_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "numbers";
-  unsigned int *store_ptr;
-  unsigned int store_list[] = { 23, 56, 499, 98, 32847, 0 };
-  char *value;
-  size_t value_length;
-  uint32_t flags;
-  unsigned int x;
-
-  rc= memcached_flush(memc, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_set(memc,
-                    key, strlen(key),
-                    NULL, 0,
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  for (x= 0; store_list[x] ; x++)
-  {
-    rc= memcached_append(memc,
-                         key, strlen(key),
-                         (char *)&store_list[x], sizeof(unsigned int),
-                         (time_t)0, (uint32_t)0);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  value= memcached_get(memc, key, strlen(key),
-                       &value_length, &flags, &rc);
-  assert((value_length == (sizeof(unsigned int) * x)));
-  assert(rc == MEMCACHED_SUCCESS);
-
-  store_ptr= (unsigned int *)value;
-  x= 0;
-  while ((size_t)store_ptr < (size_t)(value + value_length))
-  {
-    assert(*store_ptr == store_list[x++]);
-    store_ptr++;
-  }
-  free(value);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  cas2_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *keys[]= {"fudge", "son", "food"};
-  size_t key_length[]= {5, 3, 4};
-  const char *value= "we the people";
-  size_t value_length= strlen("we the people");
-  unsigned int x;
-  memcached_result_st results_obj;
-  memcached_result_st *results;
-  unsigned int set= 1;
-
-  rc= memcached_flush(memc, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, set);
-
-  for (x= 0; x < 3; x++)
-  {
-    rc= memcached_set(memc, keys[x], key_length[x],
-                      keys[x], key_length[x],
-                      (time_t)50, (uint32_t)9);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  rc= memcached_mget(memc, keys, key_length, 3);
-
-  results= memcached_result_create(memc, &results_obj);
-
-  results= memcached_fetch_result(memc, &results_obj, &rc);
-  assert(results);
-  assert(results->cas);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(memcached_result_cas(results));
-
-  assert(!memcmp(value, "we the people", strlen("we the people")));
-  assert(strlen("we the people") == value_length);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  memcached_result_free(&results_obj);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  cas_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "fun";
-  size_t key_length= strlen(key);
-  const char *value= "we the people";
-  const char* keys[2] = { key, NULL };
-  size_t keylengths[2] = { strlen(key), 0 };
-  size_t value_length= strlen(value);
-  const char *value2= "change the value";
-  size_t value2_length= strlen(value2);
-
-  memcached_result_st results_obj;
-  memcached_result_st *results;
-  unsigned int set= 1;
-
-  rc= memcached_flush(memc, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, set);
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_mget(memc, keys, keylengths, 1);
-
-  results= memcached_result_create(memc, &results_obj);
-
-  results= memcached_fetch_result(memc, &results_obj, &rc);
-  assert(results);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(memcached_result_cas(results));
-  assert(!memcmp(value, memcached_result_value(results), value_length));
-  assert(strlen(memcached_result_value(results)) == value_length);
-  assert(rc == MEMCACHED_SUCCESS);
-  uint64_t cas = memcached_result_cas(results);
-
-  #if 0
-  results= memcached_fetch_result(memc, &results_obj, &rc);
-  assert(rc == MEMCACHED_END);
-  assert(results == NULL);
-#endif
-
-  rc= memcached_cas(memc, key, key_length, value2, value2_length, 0, 0, cas);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  /*
-   * The item will have a new cas value, so try to set it again with the old
-   * value. This should fail!
-   */
-  rc= memcached_cas(memc, key, key_length, value2, value2_length, 0, 0, cas);
-  assert(rc == MEMCACHED_DATA_EXISTS);
-
-  memcached_result_free(&results_obj);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  prepend_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "fig";
-  const char *value= "people";
-  char *out_value= NULL;
-  size_t value_length;
-  uint32_t flags;
-
-  rc= memcached_flush(memc, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_prepend(memc, key, strlen(key),
-                       "the ", strlen("the "),
-                       (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_prepend(memc, key, strlen(key),
-                       "we ", strlen("we "),
-                       (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  out_value= memcached_get(memc, key, strlen(key),
-                       &value_length, &flags, &rc);
-  assert(!memcmp(out_value, "we the people", strlen("we the people")));
-  assert(strlen("we the people") == value_length);
-  assert(rc == MEMCACHED_SUCCESS);
-  free(out_value);
-
-  return TEST_SUCCESS;
-}
-
-/*
-  Set the value, then quit to make sure it is flushed.
-  Come back in and test that add fails.
-*/
-static test_return_t  add_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  const char *value= "when we sanitize";
-  unsigned long long setting_value;
-
-  setting_value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK);
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-  memcached_quit(memc);
-  rc= memcached_add(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-
-  /* Too many broken OS'es have broken loopback in async, so we can't be sure of the result */
-  if (setting_value)
-    assert(rc == MEMCACHED_NOTSTORED || rc == MEMCACHED_STORED);
-  else
-    assert(rc == MEMCACHED_NOTSTORED || rc == MEMCACHED_DATA_EXISTS);
-
-  return TEST_SUCCESS;
-}
-
-/*
-** There was a problem of leaking filedescriptors in the initial release
-** of MacOSX 10.5. This test case triggers the problem. On some Solaris
-** systems it seems that the kernel is slow on reclaiming the resources
-** because the connects starts to time out (the test doesn't do much
-** anyway, so just loop 10 iterations)
-*/
-static test_return_t  add_wrapper(memcached_st *memc)
-{
-  unsigned int x;
-  unsigned int max= 10000;
-#ifdef __sun
-  max= 10;
-#endif
-#ifdef __APPLE__
-  max= 10;
-#endif
-
-  for (x= 0; x < max; x++)
-    add_test(memc);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  replace_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  const char *value= "when we sanitize";
-  const char *original= "first we insert some data";
-
-  rc= memcached_set(memc, key, strlen(key),
-                    original, strlen(original),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  rc= memcached_replace(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  delete_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  const char *value= "when we sanitize";
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  rc= memcached_delete(memc, key, strlen(key), (time_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  flush_test(memcached_st *memc)
-{
-  memcached_return rc;
-
-  rc= memcached_flush(memc, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  return TEST_SUCCESS;
-}
-
-static memcached_return  server_function(memcached_st *ptr __attribute__((unused)),
-                                         memcached_server_st *server __attribute__((unused)),
-                                         void *context __attribute__((unused)))
-{
-  /* Do Nothing */
-
-  return MEMCACHED_SUCCESS;
-}
-
-static test_return_t  memcached_server_cursor_test(memcached_st *memc)
-{
-  char context[8];
-  strcpy(context, "foo bad");
-  memcached_server_function callbacks[1];
-
-  callbacks[0]= server_function;
-  memcached_server_cursor(memc, callbacks, context,  1);
-  return TEST_SUCCESS;
-}
-
-static test_return_t  bad_key_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo bad";
-  char *string;
-  size_t string_length;
-  uint32_t flags;
-  memcached_st *memc_clone;
-  unsigned int set= 1;
-  size_t max_keylen= 0xffff;
-
-  memc_clone= memcached_clone(NULL, memc);
-  assert(memc_clone);
-
-  rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  /* All keys are valid in the binary protocol (except for length) */
-  if (memcached_behavior_get(memc_clone, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 0)
-  {
-    string= memcached_get(memc_clone, key, strlen(key),
-                          &string_length, &flags, &rc);
-    assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
-    assert(string_length ==  0);
-    assert(!string);
-
-    set= 0;
-    rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set);
-    assert(rc == MEMCACHED_SUCCESS);
-    string= memcached_get(memc_clone, key, strlen(key),
-                          &string_length, &flags, &rc);
-    assert(rc == MEMCACHED_NOTFOUND);
-    assert(string_length ==  0);
-    assert(!string);
-
-    /* Test multi key for bad keys */
-    const char *keys[] = { "GoodKey", "Bad Key", "NotMine" };
-    size_t key_lengths[] = { 7, 7, 7 };
-    set= 1;
-    rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set);
-    assert(rc == MEMCACHED_SUCCESS);
-
-    rc= memcached_mget(memc_clone, keys, key_lengths, 3);
-    assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
-
-    rc= memcached_mget_by_key(memc_clone, "foo daddy", 9, keys, key_lengths, 1);
-    assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
-
-    max_keylen= 250;
-
-    /* The following test should be moved to the end of this function when the
-       memcached server is updated to allow max size length of the keys in the
-       binary protocol
-    */
-    rc= memcached_callback_set(memc_clone, MEMCACHED_CALLBACK_PREFIX_KEY, NULL);
-    assert(rc == MEMCACHED_SUCCESS);
-
-    char *longkey= malloc(max_keylen + 1);
-    if (longkey != NULL)
-    {
-      memset(longkey, 'a', max_keylen + 1);
-      string= memcached_get(memc_clone, longkey, max_keylen,
-                            &string_length, &flags, &rc);
-      assert(rc == MEMCACHED_NOTFOUND);
-      assert(string_length ==  0);
-      assert(!string);
-
-      string= memcached_get(memc_clone, longkey, max_keylen + 1,
-                            &string_length, &flags, &rc);
-      assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
-      assert(string_length ==  0);
-      assert(!string);
-
-      free(longkey);
-    }
-  }
-
-  /* Make sure zero length keys are marked as bad */
-  set= 1;
-  rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set);
-  assert(rc == MEMCACHED_SUCCESS);
-  string= memcached_get(memc_clone, key, 0,
-                        &string_length, &flags, &rc);
-  assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
-  assert(string_length ==  0);
-  assert(!string);
-
-  memcached_free(memc_clone);
-
-  return TEST_SUCCESS;
-}
-
-#define READ_THROUGH_VALUE "set for me"
-static memcached_return  read_through_trigger(memcached_st *memc __attribute__((unused)),
-                                      char *key __attribute__((unused)),
-                                      size_t key_length __attribute__((unused)),
-                                      memcached_result_st *result)
-{
-
-  return memcached_result_set_value(result, READ_THROUGH_VALUE, strlen(READ_THROUGH_VALUE));
-}
-
-static test_return_t  read_through(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  char *string;
-  size_t string_length;
-  uint32_t flags;
-  memcached_trigger_key cb= (memcached_trigger_key)read_through_trigger;
-
-  string= memcached_get(memc, key, strlen(key),
-                        &string_length, &flags, &rc);
-
-  assert(rc == MEMCACHED_NOTFOUND);
-  assert(string_length ==  0);
-  assert(!string);
-
-  rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_GET_FAILURE,
-                             *(void **)&cb);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  string= memcached_get(memc, key, strlen(key),
-                        &string_length, &flags, &rc);
-
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(string_length ==  strlen(READ_THROUGH_VALUE));
-  assert(!strcmp(READ_THROUGH_VALUE, string));
-  free(string);
-
-  string= memcached_get(memc, key, strlen(key),
-                        &string_length, &flags, &rc);
-
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(string_length ==  strlen(READ_THROUGH_VALUE));
-  assert(!strcmp(READ_THROUGH_VALUE, string));
-  free(string);
-
-  return TEST_SUCCESS;
-}
-
-static memcached_return  delete_trigger(memcached_st *ptr __attribute__((unused)),
-                                        const char *key,
-                                        size_t key_length __attribute__((unused)))
-{
-  assert(key);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static test_return_t  delete_through(memcached_st *memc)
-{
-  memcached_trigger_delete_key callback;
-  memcached_return rc;
-
-  callback= (memcached_trigger_delete_key)delete_trigger;
-
-  rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_DELETE_TRIGGER, *(void**)&callback);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  get_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  char *string;
-  size_t string_length;
-  uint32_t flags;
-
-  rc= memcached_delete(memc, key, strlen(key), (time_t)0);
-  assert(rc == MEMCACHED_BUFFERED || rc == MEMCACHED_NOTFOUND);
-
-  string= memcached_get(memc, key, strlen(key),
-                        &string_length, &flags, &rc);
-
-  assert(rc == MEMCACHED_NOTFOUND);
-  assert(string_length ==  0);
-  assert(!string);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  get_test2(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  const char *value= "when we sanitize";
-  char *string;
-  size_t string_length;
-  uint32_t flags;
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  string= memcached_get(memc, key, strlen(key),
-                        &string_length, &flags, &rc);
-
-  assert(string);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(string_length == strlen(value));
-  assert(!memcmp(string, value, string_length));
-
-  free(string);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  set_test2(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  const char *value= "train in the brain";
-  size_t value_length= strlen(value);
-  unsigned int x;
-
-  for (x= 0; x < 10; x++)
-  {
-    rc= memcached_set(memc, key, strlen(key),
-                      value, value_length,
-                      (time_t)0, (uint32_t)0);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  set_test3(memcached_st *memc)
-{
-  memcached_return rc;
-  char *value;
-  size_t value_length= 8191;
-  unsigned int x;
-
-  value = (char*)malloc(value_length);
-  assert(value);
-
-  for (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++)
-  {
-    char key[16];
-
-    sprintf(key, "foo%u", x);
-
-    rc= memcached_set(memc, key, strlen(key),
-                      value, value_length,
-                      (time_t)0, (uint32_t)0);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-  }
-
-  free(value);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  get_test3(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  char *value;
-  size_t value_length= 8191;
-  char *string;
-  size_t string_length;
-  uint32_t flags;
-  uint32_t x;
-
-  value = (char*)malloc(value_length);
-  assert(value);
-
-  for (x= 0; x < value_length; x++)
-    value[x] = (char) (x % 127);
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, value_length,
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  string= memcached_get(memc, key, strlen(key),
-                        &string_length, &flags, &rc);
-
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(string);
-  assert(string_length == value_length);
-  assert(!memcmp(string, value, string_length));
-
-  free(string);
-  free(value);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  get_test4(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  char *value;
-  size_t value_length= 8191;
-  char *string;
-  size_t string_length;
-  uint32_t flags;
-  uint32_t x;
-
-  value = (char*)malloc(value_length);
-  assert(value);
-
-  for (x= 0; x < value_length; x++)
-    value[x] = (char) (x % 127);
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, value_length,
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  for (x= 0; x < 10; x++)
-  {
-    string= memcached_get(memc, key, strlen(key),
-                          &string_length, &flags, &rc);
-
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(string);
-    assert(string_length == value_length);
-    assert(!memcmp(string, value, string_length));
-    free(string);
-  }
-
-  free(value);
-
-  return TEST_SUCCESS;
-}
-
-/*
- * This test verifies that memcached_read_one_response doesn't try to
- * dereference a NIL-pointer if you issue a multi-get and don't read out all
- * responses before you execute a storage command.
- */
-static test_return_t get_test5(memcached_st *memc)
-{
-  /*
-  ** Request the same key twice, to ensure that we hash to the same server
-  ** (so that we have multiple response values queued up) ;-)
-  */
-  const char *keys[]= { "key", "key" };
-  size_t lengths[]= { 3, 3 };
-  uint32_t flags;
-  size_t rlen;
-
-  memcached_return rc= memcached_set(memc, keys[0], lengths[0],
-                                     keys[0], lengths[0], 0, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-  rc= memcached_mget(memc, keys, lengths, 2);
-
-  memcached_result_st results_obj;
-  memcached_result_st *results;
-  results=memcached_result_create(memc, &results_obj);
-  assert(results);
-  results=memcached_fetch_result(memc, &results_obj, &rc);
-  assert(results);
-  memcached_result_free(&results_obj);
-
-  /* Don't read out the second result, but issue a set instead.. */
-  rc= memcached_set(memc, keys[0], lengths[0], keys[0], lengths[0], 0, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  char *val= memcached_get_by_key(memc, keys[0], lengths[0], "yek", 3,
-                                  &rlen, &flags, &rc);
-  assert(val == NULL);
-  assert(rc == MEMCACHED_NOTFOUND);
-  val= memcached_get(memc, keys[0], lengths[0], &rlen, &flags, &rc);
-  assert(val != NULL);
-  assert(rc == MEMCACHED_SUCCESS);
-  free(val);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  mget_end(memcached_st *memc)
-{
-  const char *keys[]= { "foo", "foo2" };
-  size_t lengths[]= { 3, 4 };
-  const char *values[]= { "fjord", "41" };
-
-  memcached_return rc;
-
-  // Set foo and foo2
-  for (int i= 0; i < 2; i++)
-  {
-    rc= memcached_set(memc, keys[i], lengths[i], values[i], strlen(values[i]),
-                     (time_t)0, (uint32_t)0);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  char *string;
-  size_t string_length;
-  uint32_t flags;
-
-  // retrieve both via mget
-  rc= memcached_mget(memc, keys, lengths, 2);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  char key[MEMCACHED_MAX_KEY];
-  size_t key_length;
-
-  // this should get both
-  for (int i = 0; i < 2; i++)
-  {
-    string= memcached_fetch(memc, key, &key_length, &string_length,
-                            &flags, &rc);
-    assert(rc == MEMCACHED_SUCCESS);
-    int val = 0;
-    if (key_length == 4)
-      val= 1;
-    assert(string_length == strlen(values[val]));
-    assert(strncmp(values[val], string, string_length) == 0);
-    free(string);
-  }
-
-  // this should indicate end
-  string= memcached_fetch(memc, key, &key_length, &string_length, &flags, &rc);
-  assert(rc == MEMCACHED_END);
-
-  // now get just one
-  rc= memcached_mget(memc, keys, lengths, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  string= memcached_fetch(memc, key, &key_length, &string_length, &flags, &rc);
-  assert(key_length == lengths[0]);
-  assert(strncmp(keys[0], key, key_length) == 0);
-  assert(string_length == strlen(values[0]));
-  assert(strncmp(values[0], string, string_length) == 0);
-  assert(rc == MEMCACHED_SUCCESS);
-  free(string);
-
-  // this should indicate end
-  string= memcached_fetch(memc, key, &key_length, &string_length, &flags, &rc);
-  assert(rc == MEMCACHED_END);
-
-  return TEST_SUCCESS;
-}
-
-/* Do not copy the style of this code, I just access hosts to testthis function */
-static test_return_t  stats_servername_test(memcached_st *memc)
-{
-  memcached_return rc;
-  memcached_stat_st memc_stat;
-  rc= memcached_stat_servername(&memc_stat, NULL,
-                                 memc->hosts[0].hostname,
-                                 memc->hosts[0].port);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  increment_test(memcached_st *memc)
-{
-  uint64_t new_number;
-  memcached_return rc;
-  const char *key= "number";
-  const char *value= "0";
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  rc= memcached_increment(memc, key, strlen(key),
-                          1, &new_number);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(new_number == 1);
-
-  rc= memcached_increment(memc, key, strlen(key),
-                          1, &new_number);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(new_number == 2);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  increment_with_initial_test(memcached_st *memc)
-{
-  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0)
-  {
-    uint64_t new_number;
-    memcached_return rc;
-    const char *key= "number";
-    uint64_t initial= 0;
-
-    rc= memcached_increment_with_initial(memc, key, strlen(key),
-                                         1, initial, 0, &new_number);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(new_number == initial);
-
-    rc= memcached_increment_with_initial(memc, key, strlen(key),
-                                         1, initial, 0, &new_number);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(new_number == (initial + 1));
-  }
-  return TEST_SUCCESS;
-}
-
-static test_return_t  decrement_test(memcached_st *memc)
-{
-  uint64_t new_number;
-  memcached_return rc;
-  const char *key= "number";
-  const char *value= "3";
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  rc= memcached_decrement(memc, key, strlen(key),
-                          1, &new_number);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(new_number == 2);
-
-  rc= memcached_decrement(memc, key, strlen(key),
-                          1, &new_number);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(new_number == 1);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  decrement_with_initial_test(memcached_st *memc)
-{
-  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0)
-  {
-    uint64_t new_number;
-    memcached_return rc;
-    const char *key= "number";
-    uint64_t initial= 3;
-
-    rc= memcached_decrement_with_initial(memc, key, strlen(key),
-                                         1, initial, 0, &new_number);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(new_number == initial);
-
-    rc= memcached_decrement_with_initial(memc, key, strlen(key),
-                                         1, initial, 0, &new_number);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(new_number == (initial - 1));
-  }
-  return TEST_SUCCESS;
-}
-
-static test_return_t  increment_by_key_test(memcached_st *memc)
-{
-  uint64_t new_number;
-  memcached_return rc;
-  const char *master_key= "foo";
-  const char *key= "number";
-  const char *value= "0";
-
-  rc= memcached_set_by_key(memc, master_key, strlen(master_key),
-                           key, strlen(key),
-                           value, strlen(value),
-                           (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  rc= memcached_increment_by_key(memc, master_key, strlen(master_key), key, strlen(key),
-                                 1, &new_number);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(new_number == 1);
-
-  rc= memcached_increment_by_key(memc, master_key, strlen(master_key), key, strlen(key),
-                                 1, &new_number);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(new_number == 2);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  increment_with_initial_by_key_test(memcached_st *memc)
-{
-  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0)
-  {
-    uint64_t new_number;
-    memcached_return rc;
-    const char *master_key= "foo";
-    const char *key= "number";
-    uint64_t initial= 0;
-
-    rc= memcached_increment_with_initial_by_key(memc, master_key, strlen(master_key),
-                                                key, strlen(key),
-                                                1, initial, 0, &new_number);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(new_number == initial);
-
-    rc= memcached_increment_with_initial_by_key(memc, master_key, strlen(master_key),
-                                                key, strlen(key),
-                                                1, initial, 0, &new_number);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(new_number == (initial + 1));
-  }
-  return TEST_SUCCESS;
-}
-
-static test_return_t  decrement_by_key_test(memcached_st *memc)
-{
-  uint64_t new_number;
-  memcached_return rc;
-  const char *master_key= "foo";
-  const char *key= "number";
-  const char *value= "3";
-
-  rc= memcached_set_by_key(memc, master_key, strlen(master_key),
-                           key, strlen(key),
-                           value, strlen(value),
-                           (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  rc= memcached_decrement_by_key(memc, master_key, strlen(master_key),
-                                 key, strlen(key),
-                                 1, &new_number);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(new_number == 2);
-
-  rc= memcached_decrement_by_key(memc, master_key, strlen(master_key),
-                                 key, strlen(key),
-                                 1, &new_number);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(new_number == 1);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  decrement_with_initial_by_key_test(memcached_st *memc)
-{
-  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0)
-  {
-    uint64_t new_number;
-    memcached_return rc;
-    const char *master_key= "foo";
-    const char *key= "number";
-    uint64_t initial= 3;
-
-    rc= memcached_decrement_with_initial_by_key(memc, master_key, strlen(master_key),
-                                                key, strlen(key),
-                                                1, initial, 0, &new_number);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(new_number == initial);
-
-    rc= memcached_decrement_with_initial_by_key(memc, master_key, strlen(master_key),
-                                                key, strlen(key),
-                                                1, initial, 0, &new_number);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(new_number == (initial - 1));
-  }
-  return TEST_SUCCESS;
-}
-
-static test_return_t  quit_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "fudge";
-  const char *value= "sanford and sun";
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)10, (uint32_t)3);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-  memcached_quit(memc);
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)50, (uint32_t)9);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  mget_result_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *keys[]= {"fudge", "son", "food"};
-  size_t key_length[]= {5, 3, 4};
-  unsigned int x;
-
-  memcached_result_st results_obj;
-  memcached_result_st *results;
-
-  results= memcached_result_create(memc, &results_obj);
-  assert(results);
-  assert(&results_obj == results);
-
-  /* We need to empty the server before continueing test */
-  rc= memcached_flush(memc, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_mget(memc, keys, key_length, 3);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL)
-  {
-    assert(results);
-  }
-
-  while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL)
-  assert(!results);
-  assert(rc == MEMCACHED_END);
-
-  for (x= 0; x < 3; x++)
-  {
-    rc= memcached_set(memc, keys[x], key_length[x],
-                      keys[x], key_length[x],
-                      (time_t)50, (uint32_t)9);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-  }
-
-  rc= memcached_mget(memc, keys, key_length, 3);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  while ((results= memcached_fetch_result(memc, &results_obj, &rc)))
-  {
-    assert(results);
-    assert(&results_obj == results);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(memcached_result_key_length(results) == memcached_result_length(results));
-    assert(!memcmp(memcached_result_key_value(results),
-                   memcached_result_value(results),
-                   memcached_result_length(results)));
-  }
-
-  memcached_result_free(&results_obj);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  mget_result_alloc_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *keys[]= {"fudge", "son", "food"};
-  size_t key_length[]= {5, 3, 4};
-  unsigned int x;
-
-  memcached_result_st *results;
-
-  /* We need to empty the server before continueing test */
-  rc= memcached_flush(memc, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_mget(memc, keys, key_length, 3);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  while ((results= memcached_fetch_result(memc, NULL, &rc)) != NULL)
-  {
-    assert(results);
-  }
-  assert(!results);
-  assert(rc == MEMCACHED_END);
-
-  for (x= 0; x < 3; x++)
-  {
-    rc= memcached_set(memc, keys[x], key_length[x],
-                      keys[x], key_length[x],
-                      (time_t)50, (uint32_t)9);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-  }
-
-  rc= memcached_mget(memc, keys, key_length, 3);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  x= 0;
-  while ((results= memcached_fetch_result(memc, NULL, &rc)))
-  {
-    assert(results);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(memcached_result_key_length(results) == memcached_result_length(results));
-    assert(!memcmp(memcached_result_key_value(results),
-                   memcached_result_value(results),
-                   memcached_result_length(results)));
-    memcached_result_free(results);
-    x++;
-  }
-
-  return TEST_SUCCESS;
-}
-
-/* Count the results */
-static memcached_return callback_counter(memcached_st *ptr __attribute__((unused)),
-                                     memcached_result_st *result __attribute__((unused)),
-                                     void *context)
-{
-  unsigned int *counter= (unsigned int *)context;
-
-  *counter= *counter + 1;
-
-  return MEMCACHED_SUCCESS;
-}
-
-static test_return_t  mget_result_function(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *keys[]= {"fudge", "son", "food"};
-  size_t key_length[]= {5, 3, 4};
-  unsigned int x;
-  unsigned int counter;
-  memcached_execute_function callbacks[1];
-
-  /* We need to empty the server before continueing test */
-  rc= memcached_flush(memc, 0);
-  for (x= 0; x < 3; x++)
-  {
-    rc= memcached_set(memc, keys[x], key_length[x],
-                      keys[x], key_length[x],
-                      (time_t)50, (uint32_t)9);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-  }
-
-  rc= memcached_mget(memc, keys, key_length, 3);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  callbacks[0]= &callback_counter;
-  counter= 0;
-  rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
-
-  assert(counter == 3);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  mget_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *keys[]= {"fudge", "son", "food"};
-  size_t key_length[]= {5, 3, 4};
-  unsigned int x;
-  uint32_t flags;
-
-  char return_key[MEMCACHED_MAX_KEY];
-  size_t return_key_length;
-  char *return_value;
-  size_t return_value_length;
-
-  /* We need to empty the server before continueing test */
-  rc= memcached_flush(memc, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  rc= memcached_mget(memc, keys, key_length, 3);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
-                      &return_value_length, &flags, &rc)) != NULL)
-  {
-    assert(return_value);
-  }
-  assert(!return_value);
-  assert(return_value_length == 0);
-  assert(rc == MEMCACHED_END);
-
-  for (x= 0; x < 3; x++)
-  {
-    rc= memcached_set(memc, keys[x], key_length[x],
-                      keys[x], key_length[x],
-                      (time_t)50, (uint32_t)9);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-  }
-
-  rc= memcached_mget(memc, keys, key_length, 3);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  x= 0;
-  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
-                                        &return_value_length, &flags, &rc)))
-  {
-    assert(return_value);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(return_key_length == return_value_length);
-    assert(!memcmp(return_value, return_key, return_value_length));
-    free(return_value);
-    x++;
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t mget_execute(memcached_st *memc)
-{
-  bool binary= false;
-  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0)
-    binary= true;
-
-  /*
-   * I only want to hit _one_ server so I know the number of requests I'm
-   * sending in the pipeline.
-   */
-  uint32_t number_of_hosts= memc->number_of_hosts;
-  memc->number_of_hosts= 1;
-
-  int max_keys= binary ? 20480 : 1;
-
-
-  char **keys= calloc((size_t)max_keys, sizeof(char*));
-  size_t *key_length=calloc((size_t)max_keys, sizeof(size_t));
-
-  /* First add all of the items.. */
-  char blob[1024] = {0};
-  memcached_return rc;
-  for (int x= 0; x < max_keys; ++x)
-  {
-    char k[251];
-    key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%u", x);
-    keys[x]= strdup(k);
-    assert(keys[x] != NULL);
-    rc= memcached_add(memc, keys[x], key_length[x], blob, sizeof(blob), 0, 0);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-  }
-
-  /* Try to get all of them with a large multiget */
-  unsigned int counter= 0;
-  memcached_execute_function callbacks[1]= { [0]= &callback_counter };
-  rc= memcached_mget_execute(memc, (const char**)keys, key_length,
-                             (size_t)max_keys, callbacks, &counter, 1);
-
-  if (binary)
-  {
-    assert(rc == MEMCACHED_SUCCESS);
-
-    rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
-    assert(rc == MEMCACHED_END);
-
-    /* Verify that we got all of the items */
-    assert(counter == (unsigned int)max_keys);
-  }
-  else
-  {
-    assert(rc == MEMCACHED_NOT_SUPPORTED);
-    assert(counter == 0);
-  }
-
-  /* Release all allocated resources */
-  for (int x= 0; x < max_keys; ++x)
-    free(keys[x]);
-  free(keys);
-  free(key_length);
-
-  memc->number_of_hosts= number_of_hosts;
-  return TEST_SUCCESS;
-}
-
-static test_return_t  get_stats_keys(memcached_st *memc)
-{
- char **list;
- char **ptr;
- memcached_stat_st memc_stat;
- memcached_return rc;
-
- list= memcached_stat_get_keys(memc, &memc_stat, &rc);
- assert(rc == MEMCACHED_SUCCESS);
- for (ptr= list; *ptr; ptr++)
-   assert(*ptr);
- fflush(stdout);
-
- free(list);
-
- return TEST_SUCCESS;
-}
-
-static test_return_t  version_string_test(memcached_st *memc __attribute__((unused)))
-{
-  const char *version_string;
-
-  version_string= memcached_lib_version();
-
-  assert(!strcmp(version_string, LIBMEMCACHED_VERSION_STRING));
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  get_stats(memcached_st *memc)
-{
- unsigned int x;
- char **list;
- char **ptr;
- memcached_return rc;
- memcached_stat_st *memc_stat;
-
- memc_stat= memcached_stat(memc, NULL, &rc);
- assert(rc == MEMCACHED_SUCCESS);
-
- assert(rc == MEMCACHED_SUCCESS);
- assert(memc_stat);
-
- for (x= 0; x < memcached_server_count(memc); x++)
- {
-   list= memcached_stat_get_keys(memc, memc_stat+x, &rc);
-   assert(rc == MEMCACHED_SUCCESS);
-   for (ptr= list; *ptr; ptr++);
-
-   free(list);
- }
-
- memcached_stat_free(NULL, memc_stat);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  add_host_test(memcached_st *memc)
-{
-  unsigned int x;
-  memcached_server_st *servers;
-  memcached_return rc;
-  char servername[]= "0.example.com";
-
-  servers= memcached_server_list_append_with_weight(NULL, servername, 400, 0, &rc);
-  assert(servers);
-  assert(1 == memcached_server_list_count(servers));
-
-  for (x= 2; x < 20; x++)
-  {
-    char buffer[SMALL_STRING_LEN];
-
-    snprintf(buffer, SMALL_STRING_LEN, "%u.example.com", 400+x);
-    servers= memcached_server_list_append_with_weight(servers, buffer, 401, 0,
-                                     &rc);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(x == memcached_server_list_count(servers));
-  }
-
-  rc= memcached_server_push(memc, servers);
-  assert(rc == MEMCACHED_SUCCESS);
-  rc= memcached_server_push(memc, servers);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  memcached_server_list_free(servers);
-
-  return TEST_SUCCESS;
-}
-
-static memcached_return  clone_test_callback(memcached_st *parent __attribute__((unused)), memcached_st *memc_clone __attribute__((unused)))
-{
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  cleanup_test_callback(memcached_st *ptr __attribute__((unused)))
-{
-  return MEMCACHED_SUCCESS;
-}
-
-static test_return_t  callback_test(memcached_st *memc)
-{
-  /* Test User Data */
-  {
-    int x= 5;
-    int *test_ptr;
-    memcached_return rc;
-
-    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_USER_DATA, &x);
-    assert(rc == MEMCACHED_SUCCESS);
-    test_ptr= (int *)memcached_callback_get(memc, MEMCACHED_CALLBACK_USER_DATA, &rc);
-    assert(*test_ptr == x);
-  }
-
-  /* Test Clone Callback */
-  {
-    memcached_clone_func clone_cb= (memcached_clone_func)clone_test_callback;
-    void *clone_cb_ptr= *(void **)&clone_cb;
-    void *temp_function= NULL;
-    memcached_return rc;
-
-    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_CLONE_FUNCTION,
-                               clone_cb_ptr);
-    assert(rc == MEMCACHED_SUCCESS);
-    temp_function= memcached_callback_get(memc, MEMCACHED_CALLBACK_CLONE_FUNCTION, &rc);
-    assert(temp_function == clone_cb_ptr);
-  }
-
-  /* Test Cleanup Callback */
-  {
-    memcached_cleanup_func cleanup_cb=
-      (memcached_cleanup_func)cleanup_test_callback;
-    void *cleanup_cb_ptr= *(void **)&cleanup_cb;
-    void *temp_function= NULL;
-    memcached_return rc;
-
-    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_CLONE_FUNCTION,
-                               cleanup_cb_ptr);
-    assert(rc == MEMCACHED_SUCCESS);
-    temp_function= memcached_callback_get(memc, MEMCACHED_CALLBACK_CLONE_FUNCTION, &rc);
-    assert(temp_function == cleanup_cb_ptr);
-  }
-
-  return TEST_SUCCESS;
-}
-
-/* We don't test the behavior itself, we test the switches */
-static test_return_t  behavior_test(memcached_st *memc)
-{
-  uint64_t value;
-  uint32_t set= 1;
-
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, set);
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK);
-  assert(value == 1);
-
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, set);
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY);
-  assert(value == 1);
-
-  set= MEMCACHED_HASH_MD5;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_HASH);
-  assert(value == MEMCACHED_HASH_MD5);
-
-  set= 0;
-
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, set);
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK);
-  assert(value == 0);
-
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, set);
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY);
-  assert(value == 0);
-
-  set= MEMCACHED_HASH_DEFAULT;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_HASH);
-  assert(value == MEMCACHED_HASH_DEFAULT);
-
-  set= MEMCACHED_HASH_CRC;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_HASH);
-  assert(value == MEMCACHED_HASH_CRC);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE);
-  assert(value > 0);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
-  assert(value > 0);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, value + 1);
-  assert((value + 1) == memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS));
-  return TEST_SUCCESS;
-}
-
-static test_return_t fetch_all_results(memcached_st *memc)
-{
-  memcached_return rc= MEMCACHED_SUCCESS;
-  char return_key[MEMCACHED_MAX_KEY];
-  size_t return_key_length;
-  char *return_value;
-  size_t return_value_length;
-  uint32_t flags;
-
-  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
-                                        &return_value_length, &flags, &rc)))
-  {
-    assert(return_value);
-    assert(rc == MEMCACHED_SUCCESS);
-    free(return_value);
-  }
-
-  return ((rc == MEMCACHED_END) || (rc == MEMCACHED_SUCCESS)) ? TEST_SUCCESS : TEST_FAILURE;
-}
-
-/* Test case provided by Cal Haldenbrand */
-static test_return_t  user_supplied_bug1(memcached_st *memc)
-{
-  unsigned int setter= 1;
-  unsigned int x;
-
-  unsigned long long total= 0;
-  uint32_t size= 0;
-  char key[10];
-  char randomstuff[6 * 1024];
-  memcached_return rc;
-
-  memset(randomstuff, 0, 6 * 1024);
-
-  /* We just keep looking at the same values over and over */
-  srandom(10);
-
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, setter);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, setter);
-
-
-  /* add key */
-  for (x= 0 ; total < 20 * 1024576 ; x++ )
-  {
-    unsigned int j= 0;
-
-    size= (uint32_t)(rand() % ( 5 * 1024 ) ) + 400;
-    memset(randomstuff, 0, 6 * 1024);
-    assert(size < 6 * 1024); /* Being safe here */
-
-    for (j= 0 ; j < size ;j++)
-      randomstuff[j] = (signed char) ((rand() % 26) + 97);
-
-    total += size;
-    sprintf(key, "%d", x);
-    rc = memcached_set(memc, key, strlen(key),
-                       randomstuff, strlen(randomstuff), 10, 0);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-    /* If we fail, lets try again */
-    if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
-      rc = memcached_set(memc, key, strlen(key),
-                         randomstuff, strlen(randomstuff), 10, 0);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-  }
-
-  return TEST_SUCCESS;
-}
-
-/* Test case provided by Cal Haldenbrand */
-static test_return_t  user_supplied_bug2(memcached_st *memc)
-{
-  int errors;
-  unsigned int setter;
-  unsigned int x;
-  unsigned long long total;
-
-  setter= 1;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, setter);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, setter);
-#ifdef NOT_YET
-  setter = 20 * 1024576;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE, setter);
-  setter = 20 * 1024576;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE, setter);
-  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE);
-  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
-
-  for (x= 0, errors= 0, total= 0 ; total < 20 * 1024576 ; x++)
-#endif
-
-  for (x= 0, errors= 0, total= 0 ; total < 24576 ; x++)
-  {
-    memcached_return rc= MEMCACHED_SUCCESS;
-    char buffer[SMALL_STRING_LEN];
-    uint32_t flags= 0;
-    size_t val_len= 0;
-    char *getval;
-
-    memset(buffer, 0, SMALL_STRING_LEN);
-
-    snprintf(buffer, SMALL_STRING_LEN, "%u", x);
-    getval= memcached_get(memc, buffer, strlen(buffer),
-                           &val_len, &flags, &rc);
-    if (rc != MEMCACHED_SUCCESS)
-    {
-      if (rc == MEMCACHED_NOTFOUND)
-        errors++;
-      else
-      {
-        assert(rc);
-      }
-
-      continue;
-    }
-    total+= val_len;
-    errors= 0;
-    free(getval);
-  }
-
-  return TEST_SUCCESS;
-}
-
-/* Do a large mget() over all the keys we think exist */
-#define KEY_COUNT 3000 // * 1024576
-static test_return_t  user_supplied_bug3(memcached_st *memc)
-{
-  memcached_return rc;
-  unsigned int setter;
-  unsigned int x;
-  char **keys;
-  size_t key_lengths[KEY_COUNT];
-
-  setter= 1;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, setter);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, setter);
-#ifdef NOT_YET
-  setter = 20 * 1024576;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE, setter);
-  setter = 20 * 1024576;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE, setter);
-  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE);
-  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
-#endif
-
-  keys= calloc(KEY_COUNT, sizeof(char *));
-  assert(keys);
-  for (x= 0; x < KEY_COUNT; x++)
-  {
-    char buffer[30];
-
-    snprintf(buffer, 30, "%u", x);
-    keys[x]= strdup(buffer);
-    key_lengths[x]= strlen(keys[x]);
-  }
-
-  rc= memcached_mget(memc, (const char **)keys, key_lengths, KEY_COUNT);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  assert(fetch_all_results(memc) == TEST_SUCCESS);
-
-  for (x= 0; x < KEY_COUNT; x++)
-    free(keys[x]);
-  free(keys);
-
-  return TEST_SUCCESS;
-}
-
-/* Make sure we behave properly if server list has no values */
-static test_return_t  user_supplied_bug4(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *keys[]= {"fudge", "son", "food"};
-  size_t key_length[]= {5, 3, 4};
-  unsigned int x;
-  uint32_t flags;
-  char return_key[MEMCACHED_MAX_KEY];
-  size_t return_key_length;
-  char *return_value;
-  size_t return_value_length;
-
-  /* Here we free everything before running a bunch of mget tests */
-  {
-    memcached_server_list_free(memc->hosts);
-    memc->hosts= NULL;
-    memc->number_of_hosts= 0;
-  }
-
-
-  /* We need to empty the server before continueing test */
-  rc= memcached_flush(memc, 0);
-  assert(rc == MEMCACHED_NO_SERVERS);
-
-  rc= memcached_mget(memc, keys, key_length, 3);
-  assert(rc == MEMCACHED_NO_SERVERS);
-
-  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
-                      &return_value_length, &flags, &rc)) != NULL)
-  {
-    assert(return_value);
-  }
-  assert(!return_value);
-  assert(return_value_length == 0);
-  assert(rc == MEMCACHED_NO_SERVERS);
-
-  for (x= 0; x < 3; x++)
-  {
-    rc= memcached_set(memc, keys[x], key_length[x],
-                      keys[x], key_length[x],
-                      (time_t)50, (uint32_t)9);
-    assert(rc == MEMCACHED_NO_SERVERS);
-  }
-
-  rc= memcached_mget(memc, keys, key_length, 3);
-  assert(rc == MEMCACHED_NO_SERVERS);
-
-  x= 0;
-  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
-                                        &return_value_length, &flags, &rc)))
-  {
-    assert(return_value);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(return_key_length == return_value_length);
-    assert(!memcmp(return_value, return_key, return_value_length));
-    free(return_value);
-    x++;
-  }
-
-  return TEST_SUCCESS;
-}
-
-#define VALUE_SIZE_BUG5 1048064
-static test_return_t  user_supplied_bug5(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *keys[]= {"036790384900", "036790384902", "036790384904", "036790384906"};
-  size_t key_length[]=  {strlen("036790384900"), strlen("036790384902"), strlen("036790384904"), strlen("036790384906")};
-  char return_key[MEMCACHED_MAX_KEY];
-  size_t return_key_length;
-  char *value;
-  size_t value_length;
-  uint32_t flags;
-  unsigned int count;
-  unsigned int x;
-  char insert_data[VALUE_SIZE_BUG5];
-
-  for (x= 0; x < VALUE_SIZE_BUG5; x++)
-    insert_data[x]= (signed char)rand();
-
-  memcached_flush(memc, 0);
-  value= memcached_get(memc, keys[0], key_length[0],
-                        &value_length, &flags, &rc);
-  assert(value == NULL);
-  rc= memcached_mget(memc, keys, key_length, 4);
-
-  count= 0;
-  while ((value= memcached_fetch(memc, return_key, &return_key_length,
-                                        &value_length, &flags, &rc)))
-    count++;
-  assert(count == 0);
-
-  for (x= 0; x < 4; x++)
-  {
-    rc= memcached_set(memc, keys[x], key_length[x],
-                      insert_data, VALUE_SIZE_BUG5,
-                      (time_t)0, (uint32_t)0);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  for (x= 0; x < 10; x++)
-  {
-    value= memcached_get(memc, keys[0], key_length[0],
-                         &value_length, &flags, &rc);
-    assert(value);
-    free(value);
-
-    rc= memcached_mget(memc, keys, key_length, 4);
-    count= 0;
-    while ((value= memcached_fetch(memc, return_key, &return_key_length,
-                                          &value_length, &flags, &rc)))
-    {
-      count++;
-      free(value);
-    }
-    assert(count == 4);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  user_supplied_bug6(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *keys[]= {"036790384900", "036790384902", "036790384904", "036790384906"};
-  size_t key_length[]=  {strlen("036790384900"), strlen("036790384902"), strlen("036790384904"), strlen("036790384906")};
-  char return_key[MEMCACHED_MAX_KEY];
-  size_t return_key_length;
-  char *value;
-  size_t value_length;
-  uint32_t flags;
-  unsigned int count;
-  unsigned int x;
-  char insert_data[VALUE_SIZE_BUG5];
-
-  for (x= 0; x < VALUE_SIZE_BUG5; x++)
-    insert_data[x]= (signed char)rand();
-
-  memcached_flush(memc, 0);
-  value= memcached_get(memc, keys[0], key_length[0],
-                        &value_length, &flags, &rc);
-  assert(value == NULL);
-  assert(rc == MEMCACHED_NOTFOUND);
-  rc= memcached_mget(memc, keys, key_length, 4);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  count= 0;
-  while ((value= memcached_fetch(memc, return_key, &return_key_length,
-                                        &value_length, &flags, &rc)))
-    count++;
-  assert(count == 0);
-  assert(rc == MEMCACHED_END);
-
-  for (x= 0; x < 4; x++)
-  {
-    rc= memcached_set(memc, keys[x], key_length[x],
-                      insert_data, VALUE_SIZE_BUG5,
-                      (time_t)0, (uint32_t)0);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  for (x= 0; x < 2; x++)
-  {
-    value= memcached_get(memc, keys[0], key_length[0],
-                         &value_length, &flags, &rc);
-    assert(value);
-    free(value);
-
-    rc= memcached_mget(memc, keys, key_length, 4);
-    assert(rc == MEMCACHED_SUCCESS);
-    count= 3;
-    /* We test for purge of partial complete fetches */
-    for (count= 3; count; count--)
-    {
-      value= memcached_fetch(memc, return_key, &return_key_length,
-                             &value_length, &flags, &rc);
-      assert(rc == MEMCACHED_SUCCESS);
-      assert(!(memcmp(value, insert_data, value_length)));
-      assert(value_length);
-      free(value);
-    }
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  user_supplied_bug8(memcached_st *memc __attribute__((unused)))
-{
-  memcached_return rc;
-  memcached_st *mine;
-  memcached_st *memc_clone;
-
-  memcached_server_st *servers;
-  const char *server_list= "memcache1.memcache.bk.sapo.pt:11211, memcache1.memcache.bk.sapo.pt:11212, memcache1.memcache.bk.sapo.pt:11213, memcache1.memcache.bk.sapo.pt:11214, memcache2.memcache.bk.sapo.pt:11211, memcache2.memcache.bk.sapo.pt:11212, memcache2.memcache.bk.sapo.pt:11213, memcache2.memcache.bk.sapo.pt:11214";
-
-  servers= memcached_servers_parse(server_list);
-  assert(servers);
-
-  mine= memcached_create(NULL);
-  rc= memcached_server_push(mine, servers);
-  assert(rc == MEMCACHED_SUCCESS);
-  memcached_server_list_free(servers);
-
-  assert(mine);
-  memc_clone= memcached_clone(NULL, mine);
-
-  memcached_quit(mine);
-  memcached_quit(memc_clone);
-
-
-  memcached_free(mine);
-  memcached_free(memc_clone);
-
-  return TEST_SUCCESS;
-}
-
-/* Test flag store/retrieve */
-static test_return_t  user_supplied_bug7(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *keys= "036790384900";
-  size_t key_length=  strlen(keys);
-  char return_key[MEMCACHED_MAX_KEY];
-  size_t return_key_length;
-  char *value;
-  size_t value_length;
-  uint32_t flags;
-  unsigned int x;
-  char insert_data[VALUE_SIZE_BUG5];
-
-  for (x= 0; x < VALUE_SIZE_BUG5; x++)
-    insert_data[x]= (signed char)rand();
-
-  memcached_flush(memc, 0);
-
-  flags= 245;
-  rc= memcached_set(memc, keys, key_length,
-                    insert_data, VALUE_SIZE_BUG5,
-                    (time_t)0, flags);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  flags= 0;
-  value= memcached_get(memc, keys, key_length,
-                        &value_length, &flags, &rc);
-  assert(flags == 245);
-  assert(value);
-  free(value);
-
-  rc= memcached_mget(memc, &keys, &key_length, 1);
-
-  flags= 0;
-  value= memcached_fetch(memc, return_key, &return_key_length,
-                         &value_length, &flags, &rc);
-  assert(flags == 245);
-  assert(value);
-  free(value);
-
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  user_supplied_bug9(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *keys[]= {"UDATA:edevil@sapo.pt", "fudge&*@#", "for^#@&$not"};
-  size_t key_length[3];
-  unsigned int x;
-  uint32_t flags;
-  unsigned count= 0;
-
-  char return_key[MEMCACHED_MAX_KEY];
-  size_t return_key_length;
-  char *return_value;
-  size_t return_value_length;
-
-
-  key_length[0]= strlen("UDATA:edevil@sapo.pt");
-  key_length[1]= strlen("fudge&*@#");
-  key_length[2]= strlen("for^#@&$not");
-
-
-  for (x= 0; x < 3; x++)
-  {
-    rc= memcached_set(memc, keys[x], key_length[x],
-                      keys[x], key_length[x],
-                      (time_t)50, (uint32_t)9);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  rc= memcached_mget(memc, keys, key_length, 3);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  /* We need to empty the server before continueing test */
-  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
-                      &return_value_length, &flags, &rc)) != NULL)
-  {
-    assert(return_value);
-    free(return_value);
-    count++;
-  }
-  assert(count == 3);
-
-  return TEST_SUCCESS;
-}
-
-/* We are testing with aggressive timeout to get failures */
-static test_return_t  user_supplied_bug10(memcached_st *memc)
-{
-  const char *key= "foo";
-  char *value;
-  size_t value_length= 512;
-  unsigned int x;
-  size_t key_len= 3;
-  memcached_return rc;
-  unsigned int set= 1;
-  memcached_st *mclone= memcached_clone(NULL, memc);
-  int32_t timeout;
-
-  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_NO_BLOCK, set);
-  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_TCP_NODELAY, set);
-  timeout= 2;
-  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_POLL_TIMEOUT,
-                         (uint64_t)timeout);
-
-  value = (char*)malloc(value_length * sizeof(char));
-
-  for (x= 0; x < value_length; x++)
-    value[x]= (char) (x % 127);
-
-  for (x= 1; x <= 100000; ++x)
-  {
-    rc= memcached_set(mclone, key, key_len,value, value_length, 0, 0);
-
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_WRITE_FAILURE ||
-           rc == MEMCACHED_BUFFERED || rc == MEMCACHED_TIMEOUT);
-
-    if (rc == MEMCACHED_WRITE_FAILURE || rc == MEMCACHED_TIMEOUT)
-      x--;
-  }
-
-  free(value);
-  memcached_free(mclone);
-
-  return TEST_SUCCESS;
-}
-
-/*
-  We are looking failures in the async protocol
-*/
-static test_return_t  user_supplied_bug11(memcached_st *memc)
-{
-  const char *key= "foo";
-  char *value;
-  size_t value_length= 512;
-  unsigned int x;
-  size_t key_len= 3;
-  memcached_return rc;
-  unsigned int set= 1;
-  int32_t timeout;
-  memcached_st *mclone= memcached_clone(NULL, memc);
-
-  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_NO_BLOCK, set);
-  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_TCP_NODELAY, set);
-  timeout= -1;
-  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_POLL_TIMEOUT,
-                         (size_t)timeout);
-
-  timeout= (int32_t)memcached_behavior_get(mclone, MEMCACHED_BEHAVIOR_POLL_TIMEOUT);
-
-  assert(timeout == -1);
-
-  value = (char*)malloc(value_length * sizeof(char));
-
-  for (x= 0; x < value_length; x++)
-    value[x]= (char) (x % 127);
-
-  for (x= 1; x <= 100000; ++x)
-  {
-    rc= memcached_set(mclone, key, key_len,value, value_length, 0, 0);
-  }
-
-  free(value);
-  memcached_free(mclone);
-
-  return TEST_SUCCESS;
-}
-
-/*
-  Bug found where incr was not returning MEMCACHED_NOTFOUND when object did not exist.
-*/
-static test_return_t  user_supplied_bug12(memcached_st *memc)
-{
-  memcached_return rc;
-  uint32_t flags;
-  size_t value_length;
-  char *value;
-  uint64_t number_value;
-
-  value= memcached_get(memc, "autoincrement", strlen("autoincrement"),
-                        &value_length, &flags, &rc);
-  assert(value == NULL);
-  assert(rc == MEMCACHED_NOTFOUND);
-
-  rc= memcached_increment(memc, "autoincrement", strlen("autoincrement"),
-                          1, &number_value);
-
-  assert(value == NULL);
-  /* The binary protocol will set the key if it doesn't exist */
-  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1)
-    assert(rc == MEMCACHED_SUCCESS);
-  else
-    assert(rc == MEMCACHED_NOTFOUND);
-
-  rc= memcached_set(memc, "autoincrement", strlen("autoincrement"), "1", 1, 0, 0);
-
-  value= memcached_get(memc, "autoincrement", strlen("autoincrement"),
-                        &value_length, &flags, &rc);
-  assert(value);
-  assert(rc == MEMCACHED_SUCCESS);
-  free(value);
-
-  rc= memcached_increment(memc, "autoincrement", strlen("autoincrement"),
-                          1, &number_value);
-  assert(number_value == 2);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  return TEST_SUCCESS;
-}
-
-/*
-  Bug found where command total one more than MEMCACHED_MAX_BUFFER
-  set key34567890 0 0 8169 \r\n is sent followed by buffer of size 8169, followed by 8169
- */
-static test_return_t  user_supplied_bug13(memcached_st *memc)
-{
-  char key[] = "key34567890";
-  char *overflow;
-  memcached_return rc;
-  size_t overflowSize;
-
-  char commandFirst[]= "set key34567890 0 0 ";
-  char commandLast[] = " \r\n"; /* first line of command sent to server */
-  size_t commandLength;
-  size_t testSize;
-
-  commandLength = strlen(commandFirst) + strlen(commandLast) + 4; /* 4 is number of characters in size, probably 8196 */
-
-  overflowSize = MEMCACHED_MAX_BUFFER - commandLength;
-
-  for (testSize= overflowSize - 1; testSize < overflowSize + 1; testSize++)
-  {
-    overflow= malloc(testSize);
-    assert(overflow != NULL);
-
-    memset(overflow, 'x', testSize);
-    rc= memcached_set(memc, key, strlen(key),
-                      overflow, testSize, 0, 0);
-    assert(rc == MEMCACHED_SUCCESS);
-    free(overflow);
-  }
-
-  return TEST_SUCCESS;
-}
-
-
-/*
-  Test values of many different sizes
-  Bug found where command total one more than MEMCACHED_MAX_BUFFER
-  set key34567890 0 0 8169 \r\n
-  is sent followed by buffer of size 8169, followed by 8169
- */
-static test_return_t  user_supplied_bug14(memcached_st *memc)
-{
-  size_t setter= 1;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, setter);
-  memcached_return rc;
-  const char *key= "foo";
-  char *value;
-  size_t value_length= 18000;
-  char *string;
-  size_t string_length;
-  uint32_t flags;
-  unsigned int x;
-  size_t current_length;
-
-  value = (char*)malloc(value_length);
-  assert(value);
-
-  for (x= 0; x < value_length; x++)
-    value[x] = (char) (x % 127);
-
-  for (current_length= 0; current_length < value_length; current_length++)
-  {
-    rc= memcached_set(memc, key, strlen(key),
-                      value, current_length,
-                      (time_t)0, (uint32_t)0);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-    string= memcached_get(memc, key, strlen(key),
-                          &string_length, &flags, &rc);
-
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(string_length == current_length);
-    assert(!memcmp(string, value, string_length));
-
-    free(string);
-  }
-
-  free(value);
-
-  return TEST_SUCCESS;
-}
-
-/*
-  Look for zero length value problems
-  */
-static test_return_t  user_supplied_bug15(memcached_st *memc)
-{
-  uint32_t x;
-  memcached_return rc;
-  const char *key= "mykey";
-  char *value;
-  size_t length;
-  uint32_t flags;
-
-  for (x= 0; x < 2; x++)
-  {
-    rc= memcached_set(memc, key, strlen(key),
-                      NULL, 0,
-                      (time_t)0, (uint32_t)0);
-
-    assert(rc == MEMCACHED_SUCCESS);
-
-    value= memcached_get(memc, key, strlen(key),
-                         &length, &flags, &rc);
-
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(value == NULL);
-    assert(length == 0);
-    assert(flags == 0);
-
-    value= memcached_get(memc, key, strlen(key),
-                         &length, &flags, &rc);
-
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(value == NULL);
-    assert(length == 0);
-    assert(flags == 0);
-  }
-
-  return TEST_SUCCESS;
-}
-
-/* Check the return sizes on FLAGS to make sure it stores 32bit unsigned values correctly */
-static test_return_t  user_supplied_bug16(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "mykey";
-  char *value;
-  size_t length;
-  uint32_t flags;
-
-  rc= memcached_set(memc, key, strlen(key),
-                    NULL, 0,
-                    (time_t)0, UINT32_MAX);
-
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_get(memc, key, strlen(key),
-                       &length, &flags, &rc);
-
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(value == NULL);
-  assert(length == 0);
-  assert(flags == UINT32_MAX);
-
-  return TEST_SUCCESS;
-}
-
-#ifndef __sun
-/* Check the validity of chinese key*/
-static test_return_t  user_supplied_bug17(memcached_st *memc)
-{
-    memcached_return rc;
-    const char *key= "豆瓣";
-    const char *value="我们在炎热抑郁的夏天无法停止豆瓣";
-    char *value2;
-    size_t length;
-    uint32_t flags;
-
-    rc= memcached_set(memc, key, strlen(key),
-            value, strlen(value),
-            (time_t)0, 0);
-
-    assert(rc == MEMCACHED_SUCCESS);
-
-    value2= memcached_get(memc, key, strlen(key),
-            &length, &flags, &rc);
-
-    assert(length==strlen(value));
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(memcmp(value, value2, length)==0);
-    free(value2);
-
-    return TEST_SUCCESS;
-}
-#endif
-
-/*
-  From Andrei on IRC
-*/
-
-static test_return_t user_supplied_bug19(memcached_st *memc)
-{
-  memcached_st *m;
-  memcached_server_st *s;
-  memcached_return res;
-
-  (void)memc;
-
-  m= memcached_create(NULL);
-  memcached_server_add_with_weight(m, "localhost", 11311, 100);
-  memcached_server_add_with_weight(m, "localhost", 11312, 100);
-
-  s= memcached_server_by_key(m, "a", 1, &res);
-  memcached_server_free(s);
-
-  memcached_free(m);
-
-  return TEST_SUCCESS;
-}
-
-/* CAS test from Andei */
-static test_return_t user_supplied_bug20(memcached_st *memc)
-{
-  memcached_return status;
-  memcached_result_st *result, result_obj;
-  const char *key = "abc";
-  size_t key_len = strlen("abc");
-  const char *value = "foobar";
-  size_t value_len = strlen(value);
-
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1);
-
-  status = memcached_set(memc, key, key_len, value, value_len, (time_t)0, (uint32_t)0);
-  assert(status == MEMCACHED_SUCCESS);
-
-  status = memcached_mget(memc, &key, &key_len, 1);
-  assert(status == MEMCACHED_SUCCESS);
-
-  result= memcached_result_create(memc, &result_obj);
-  assert(result);
-
-  memcached_result_create(memc, &result_obj);
-  result= memcached_fetch_result(memc, &result_obj, &status);
-
-  assert(result);
-  assert(status == MEMCACHED_SUCCESS);
-
-  memcached_result_free(result);
-
-  return TEST_SUCCESS;
-}
-
-#include "ketama_test_cases.h"
-static test_return_t user_supplied_bug18(memcached_st *trash)
-{
-  memcached_return rc;
-  uint64_t value;
-  int x;
-  memcached_server_st *server_pool;
-  memcached_st *memc;
-
-  (void)trash;
-
-  memc= memcached_create(NULL);
-  assert(memc);
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
-  assert(value == 1);
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
-  assert(value == MEMCACHED_HASH_MD5);
-
-  server_pool = memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
-  memcached_server_push(memc, server_pool);
-
-  /* verify that the server list was parsed okay. */
-  assert(memc->number_of_hosts == 8);
-  assert(strcmp(server_pool[0].hostname, "10.0.1.1") == 0);
-  assert(server_pool[0].port == 11211);
-  assert(server_pool[0].weight == 600);
-  assert(strcmp(server_pool[2].hostname, "10.0.1.3") == 0);
-  assert(server_pool[2].port == 11211);
-  assert(server_pool[2].weight == 200);
-  assert(strcmp(server_pool[7].hostname, "10.0.1.8") == 0);
-  assert(server_pool[7].port == 11211);
-  assert(server_pool[7].weight == 100);
-
-  /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
-   * us test the boundary wraparound.
-   */
-  assert(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->continuum[0].index);
-
-  /* verify the standard ketama set. */
-  for (x= 0; x < 99; x++)
-  {
-    uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
-    char *hostname = memc->hosts[server_idx].hostname;
-    assert(strcmp(hostname, ketama_test_cases[x].server) == 0);
-  }
-
-  memcached_server_list_free(server_pool);
-  memcached_free(memc);
-
-  return TEST_SUCCESS;
-}
-
-/* Large mget() of missing keys with binary proto
- *
- * If many binary quiet commands (such as getq's in an mget) fill the output
- * buffer and the server chooses not to respond, memcached_flush hangs. See
- * http://lists.tangent.org/pipermail/libmemcached/2009-August/000918.html
- */
-
-/* sighandler_t function that always asserts false */
-static void fail(int unused __attribute__((unused)))
-{
-  assert(0);
-}
-
-
-static test_return_t  _user_supplied_bug21(memcached_st* memc, size_t key_count)
-{
-  memcached_return rc;
-  unsigned int x;
-  char **keys;
-  size_t* key_lengths;
-  void (*oldalarm)(int);
-  memcached_st *memc_clone;
-
-  memc_clone= memcached_clone(NULL, memc);
-  assert(memc_clone);
-
-  /* only binproto uses getq for mget */
-  memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
-
-  /* empty the cache to ensure misses (hence non-responses) */
-  rc= memcached_flush(memc_clone, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  key_lengths= calloc(key_count, sizeof(size_t));
-  keys= calloc(key_count, sizeof(char *));
-  assert(keys);
-  for (x= 0; x < key_count; x++)
-  {
-    char buffer[30];
-
-    snprintf(buffer, 30, "%u", x);
-    keys[x]= strdup(buffer);
-    key_lengths[x]= strlen(keys[x]);
-  }
-
-  oldalarm= signal(SIGALRM, fail);
-  alarm(5);
-
-  rc= memcached_mget(memc_clone, (const char **)keys, key_lengths, key_count);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  alarm(0);
-  signal(SIGALRM, oldalarm);
-
-  assert(fetch_all_results(memc) == TEST_SUCCESS);
-
-  for (x= 0; x < key_count; x++)
-    free(keys[x]);
-  free(keys);
-  free(key_lengths);
-
-  memcached_free(memc_clone);
-
-  return TEST_SUCCESS;
-}
-
-static memcached_return pre_binary(memcached_st *memc);
-
-static test_return_t user_supplied_bug21(memcached_st *memc)
-{
-  if (pre_binary(memc) != MEMCACHED_SUCCESS)
-    return TEST_SKIPPED;
-
-  test_return_t rc;
-
-  /* should work as of r580 */
-  rc= _user_supplied_bug21(memc, 10);
-  assert(rc == TEST_SUCCESS);
-
-  /* should fail as of r580 */
-  rc= _user_supplied_bug21(memc, 1000);
-  assert(rc == TEST_SUCCESS);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t auto_eject_hosts(memcached_st *trash)
-{
-  (void) trash;
-
-  memcached_return rc;
-  memcached_st *memc= memcached_create(NULL);
-  assert(memc);
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  uint64_t value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
-  assert(value == 1);
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
-  assert(value == MEMCACHED_HASH_MD5);
-
-    /* server should be removed when in delay */
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS);
-  assert(value == 1);
-
-  memcached_server_st *server_pool;
-  server_pool = memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
-  memcached_server_push(memc, server_pool);
-
-  /* verify that the server list was parsed okay. */
-  assert(memc->number_of_hosts == 8);
-  assert(strcmp(server_pool[0].hostname, "10.0.1.1") == 0);
-  assert(server_pool[0].port == 11211);
-  assert(server_pool[0].weight == 600);
-  assert(strcmp(server_pool[2].hostname, "10.0.1.3") == 0);
-  assert(server_pool[2].port == 11211);
-  assert(server_pool[2].weight == 200);
-  assert(strcmp(server_pool[7].hostname, "10.0.1.8") == 0);
-  assert(server_pool[7].port == 11211);
-  assert(server_pool[7].weight == 100);
-
-  memc->hosts[2].next_retry = time(NULL) + 15;
-  memc->next_distribution_rebuild= time(NULL) - 1;
-
-  for (int x= 0; x < 99; x++)
-  {
-    uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
-    assert(server_idx != 2);
-  }
-
-  /* and re-added when it's back. */
-  memc->hosts[2].next_retry = time(NULL) - 1;
-  memc->next_distribution_rebuild= time(NULL) - 1;
-  run_distribution(memc);
-  for (int x= 0; x < 99; x++)
-  {
-    uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
-    char *hostname = memc->hosts[server_idx].hostname;
-    assert(strcmp(hostname, ketama_test_cases[x].server) == 0);
-  }
-
-  memcached_server_list_free(server_pool);
-  memcached_free(memc);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t output_ketama_weighted_keys(memcached_st *trash)
-{
-  (void) trash;
-
-  memcached_return rc;
-  memcached_st *memc= memcached_create(NULL);
-  assert(memc);
-
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  uint64_t value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
-  assert(value == 1);
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
-  assert(value == MEMCACHED_HASH_MD5);
-
-
-  assert(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE,
-                                MEMCACHED_KETAMA_COMPAT_SPY) == MEMCACHED_SUCCESS);
-
-  memcached_server_st *server_pool;
-  server_pool = memcached_servers_parse("10.0.1.1:11211,10.0.1.2:11211,10.0.1.3:11211,10.0.1.4:11211,10.0.1.5:11211,10.0.1.6:11211,10.0.1.7:11211,10.0.1.8:11211,192.168.1.1:11211,192.168.100.1:11211");
-  memcached_server_push(memc, server_pool);
-
-  FILE *fp;
-  if ((fp = fopen("ketama_keys.txt", "w")))
-  {
-    // noop
-  } else {
-    printf("cannot write to file ketama_keys.txt");
-    return TEST_FAILURE;
-  }
-
-  for (int x= 0; x < 10000; x++)
-  {
-    char key[10];
-    sprintf(key, "%d", x);
-
-    uint32_t server_idx = memcached_generate_hash(memc, key, strlen(key));
-    char *hostname = memc->hosts[server_idx].hostname;
-    unsigned int port = memc->hosts[server_idx].port;
-    fprintf(fp, "key %s is on host /%s:%u\n", key, hostname, port);
-  }
-  fclose(fp);
-  memcached_server_list_free(server_pool);
-  memcached_free(memc);
-
-  return TEST_SUCCESS;
-}
-
-
-static test_return_t  result_static(memcached_st *memc)
-{
-  memcached_result_st result;
-  memcached_result_st *result_ptr;
-
-  result_ptr= memcached_result_create(memc, &result);
-  assert(result.is_allocated == false);
-  assert(result_ptr);
-  memcached_result_free(&result);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  result_alloc(memcached_st *memc)
-{
-  memcached_result_st *result;
-
-  result= memcached_result_create(memc, NULL);
-  assert(result);
-  memcached_result_free(result);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  string_static_null(memcached_st *memc)
-{
-  memcached_string_st string;
-  memcached_string_st *string_ptr;
-
-  string_ptr= memcached_string_create(memc, &string, 0);
-  assert(string.is_allocated == false);
-  assert(string_ptr);
-  memcached_string_free(&string);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  string_alloc_null(memcached_st *memc)
-{
-  memcached_string_st *string;
-
-  string= memcached_string_create(memc, NULL, 0);
-  assert(string);
-  memcached_string_free(string);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  string_alloc_with_size(memcached_st *memc)
-{
-  memcached_string_st *string;
-
-  string= memcached_string_create(memc, NULL, 1024);
-  assert(string);
-  memcached_string_free(string);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  string_alloc_with_size_toobig(memcached_st *memc)
-{
-  memcached_string_st *string;
-
-  string= memcached_string_create(memc, NULL, SIZE_MAX);
-  assert(string == NULL);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  string_alloc_append(memcached_st *memc)
-{
-  unsigned int x;
-  char buffer[SMALL_STRING_LEN];
-  memcached_string_st *string;
-
-  /* Ring the bell! */
-  memset(buffer, 6, SMALL_STRING_LEN);
-
-  string= memcached_string_create(memc, NULL, 100);
-  assert(string);
-
-  for (x= 0; x < 1024; x++)
-  {
-    memcached_return rc;
-    rc= memcached_string_append(string, buffer, SMALL_STRING_LEN);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-  memcached_string_free(string);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  string_alloc_append_toobig(memcached_st *memc)
-{
-  memcached_return rc;
-  unsigned int x;
-  char buffer[SMALL_STRING_LEN];
-  memcached_string_st *string;
-
-  /* Ring the bell! */
-  memset(buffer, 6, SMALL_STRING_LEN);
-
-  string= memcached_string_create(memc, NULL, 100);
-  assert(string);
-
-  for (x= 0; x < 1024; x++)
-  {
-    rc= memcached_string_append(string, buffer, SMALL_STRING_LEN);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-  rc= memcached_string_append(string, buffer, SIZE_MAX);
-  assert(rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE);
-  memcached_string_free(string);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  cleanup_pairs(memcached_st *memc __attribute__((unused)))
-{
-  pairs_free(global_pairs);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  generate_pairs(memcached_st *memc __attribute__((unused)))
-{
-  unsigned long long x;
-  global_pairs= pairs_generate(GLOBAL_COUNT, 400);
-  global_count= GLOBAL_COUNT;
-
-  for (x= 0; x < global_count; x++)
-  {
-    global_keys[x]= global_pairs[x].key;
-    global_keys_length[x]=  global_pairs[x].key_length;
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  generate_large_pairs(memcached_st *memc __attribute__((unused)))
-{
-  unsigned long long x;
-  global_pairs= pairs_generate(GLOBAL2_COUNT, MEMCACHED_MAX_BUFFER+10);
-  global_count= GLOBAL2_COUNT;
-
-  for (x= 0; x < global_count; x++)
-  {
-    global_keys[x]= global_pairs[x].key;
-    global_keys_length[x]=  global_pairs[x].key_length;
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  generate_data(memcached_st *memc)
-{
-  execute_set(memc, global_pairs, global_count);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  generate_data_with_stats(memcached_st *memc)
-{
-  memcached_stat_st *stat_p;
-  memcached_return rc;
-  uint32_t host_index= 0;
-  execute_set(memc, global_pairs, global_count);
-
-  //TODO: hosts used size stats
-  stat_p= memcached_stat(memc, NULL, &rc);
-  assert(stat_p);
-
-  for (host_index= 0; host_index < SERVERS_TO_CREATE; host_index++)
-  {
-    /* This test was changes so that "make test" would work properlly */
-#ifdef DEBUG
-    printf("\nserver %u|%s|%u bytes: %llu\n", host_index, (memc->hosts)[host_index].hostname, (memc->hosts)[host_index].port, (unsigned long long)(stat_p + host_index)->bytes);
-#endif
-    assert((unsigned long long)(stat_p + host_index)->bytes);
-  }
-
-  memcached_stat_free(NULL, stat_p);
-
-  return TEST_SUCCESS;
-}
-static test_return_t  generate_buffer_data(memcached_st *memc)
-{
-  size_t latch= 0;
-
-  latch= 1;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, latch);
-  generate_data(memc);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  get_read_count(memcached_st *memc)
-{
-  unsigned int x;
-  memcached_return rc;
-  memcached_st *memc_clone;
-
-  memc_clone= memcached_clone(NULL, memc);
-  assert(memc_clone);
-
-  memcached_server_add_with_weight(memc_clone, "localhost", 6666, 0);
-
-  {
-    char *return_value;
-    size_t return_value_length;
-    uint32_t flags;
-    uint32_t count;
-
-    for (x= count= 0; x < global_count; x++)
-    {
-      return_value= memcached_get(memc_clone, global_keys[x], global_keys_length[x],
-                                  &return_value_length, &flags, &rc);
-      if (rc == MEMCACHED_SUCCESS)
-      {
-        count++;
-        if (return_value)
-          free(return_value);
-      }
-    }
-  }
-
-  memcached_free(memc_clone);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  get_read(memcached_st *memc)
-{
-  unsigned int x;
-  memcached_return rc;
-
-  {
-    char *return_value;
-    size_t return_value_length;
-    uint32_t flags;
-
-    for (x= 0; x < global_count; x++)
-    {
-      return_value= memcached_get(memc, global_keys[x], global_keys_length[x],
-                                  &return_value_length, &flags, &rc);
-      /*
-      assert(return_value);
-      assert(rc == MEMCACHED_SUCCESS);
-    */
-      if (rc == MEMCACHED_SUCCESS && return_value)
-        free(return_value);
-    }
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  mget_read(memcached_st *memc)
-{
-  memcached_return rc;
-
-  rc= memcached_mget(memc, global_keys, global_keys_length, global_count);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(fetch_all_results(memc) == TEST_SUCCESS);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  mget_read_result(memcached_st *memc)
-{
-  memcached_return rc;
-
-  rc= memcached_mget(memc, global_keys, global_keys_length, global_count);
-  assert(rc == MEMCACHED_SUCCESS);
-  /* Turn this into a help function */
-  {
-    memcached_result_st results_obj;
-    memcached_result_st *results;
-
-    results= memcached_result_create(memc, &results_obj);
-
-    while ((results= memcached_fetch_result(memc, &results_obj, &rc)))
-    {
-      assert(results);
-      assert(rc == MEMCACHED_SUCCESS);
-    }
-
-    memcached_result_free(&results_obj);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  mget_read_function(memcached_st *memc)
-{
-  memcached_return rc;
-  unsigned int counter;
-  memcached_execute_function callbacks[1];
-
-  rc= memcached_mget(memc, global_keys, global_keys_length, global_count);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  callbacks[0]= &callback_counter;
-  counter= 0;
-  rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  delete_generate(memcached_st *memc)
-{
-  unsigned int x;
-
-  for (x= 0; x < global_count; x++)
-  {
-    (void)memcached_delete(memc, global_keys[x], global_keys_length[x], (time_t)0);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  delete_buffer_generate(memcached_st *memc)
-{
-  size_t latch= 0;
-  unsigned int x;
-
-  latch= 1;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, latch);
-
-  for (x= 0; x < global_count; x++)
-  {
-    (void)memcached_delete(memc, global_keys[x], global_keys_length[x], (time_t)0);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t  add_host_test1(memcached_st *memc)
-{
-  unsigned int x;
-  memcached_return rc;
-  char servername[]= "0.example.com";
-  memcached_server_st *servers;
-
-  servers= memcached_server_list_append_with_weight(NULL, servername, 400, 0, &rc);
-  assert(servers);
-  assert(1 == memcached_server_list_count(servers));
-
-  for (x= 2; x < 20; x++)
-  {
-    char buffer[SMALL_STRING_LEN];
-
-    snprintf(buffer, SMALL_STRING_LEN, "%u.example.com", 400+x);
-    servers= memcached_server_list_append_with_weight(servers, buffer, 401, 0,
-                                     &rc);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(x == memcached_server_list_count(servers));
-  }
-
-  rc= memcached_server_push(memc, servers);
-  assert(rc == MEMCACHED_SUCCESS);
-  rc= memcached_server_push(memc, servers);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  memcached_server_list_free(servers);
-
-  return TEST_SUCCESS;
-}
-
-static memcached_return  pre_nonblock(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  pre_nonblock_binary(memcached_st *memc)
-{
-  memcached_return rc= MEMCACHED_FAILURE;
-  memcached_st *memc_clone;
-
-  memc_clone= memcached_clone(NULL, memc);
-  assert(memc_clone);
-  // The memcached_version needs to be done on a clone, because the server
-  // will not toggle protocol on an connection.
-  memcached_version(memc_clone);
-
-  if (memc_clone->hosts[0].major_version >= 1 && memc_clone->hosts[0].minor_version > 2)
-  {
-    memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
-    rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1);
-  }
-
-  memcached_free(memc_clone);
-  return rc;
-}
-
-static memcached_return  pre_murmur(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_MURMUR);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return pre_jenkins(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_JENKINS);
-
-  return MEMCACHED_SUCCESS;
-}
-
-
-static memcached_return  pre_md5(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_MD5);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  pre_crc(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_CRC);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  pre_hsieh(memcached_st *memc)
-{
-#ifdef HAVE_HSIEH_HASH
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_HSIEH);
-  return MEMCACHED_SUCCESS;
-#else
-  (void) memc;
-  return MEMCACHED_FAILURE;
-#endif
-}
-
-static memcached_return  pre_hash_fnv1_64(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_FNV1_64);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  pre_hash_fnv1a_64(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_FNV1A_64);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  pre_hash_fnv1_32(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_FNV1_32);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  pre_hash_fnv1a_32(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_FNV1A_32);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  pre_behavior_ketama(memcached_st *memc)
-{
-  memcached_return rc;
-  uint64_t value;
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA);
-  assert(value == 1);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  pre_behavior_ketama_weighted(memcached_st *memc)
-{
-  memcached_return rc;
-  uint64_t value;
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
-  assert(value == 1);
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
-  assert(value == MEMCACHED_HASH_MD5);
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  pre_binary(memcached_st *memc)
-{
-  memcached_return rc= MEMCACHED_FAILURE;
-  memcached_st *memc_clone;
-
-  memc_clone= memcached_clone(NULL, memc);
-  assert(memc_clone);
-  // The memcached_version needs to be done on a clone, because the server
-  // will not toggle protocol on an connection.
-  memcached_version(memc_clone);
-
-  if (memc_clone->hosts[0].major_version >= 1 && memc_clone->hosts[0].minor_version > 2)
-  {
-    rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1);
-  }
-
-  memcached_free(memc_clone);
-
-  return rc;
-}
-
-static memcached_return pre_replication(memcached_st *memc)
-{
-  if (pre_binary(memc) != MEMCACHED_SUCCESS)
-    return MEMCACHED_FAILURE;
-
-  /*
-   * Make sure that we store the item on all servers
-   * (master + replicas == number of servers)
-   */
-  memcached_return rc;
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS,
-                             memc->number_of_hosts - 1);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS) == memc->number_of_hosts - 1);
-
-  return rc;
-}
-
-static memcached_return pre_replication_noblock(memcached_st *memc)
-{
-  memcached_return rc= MEMCACHED_FAILURE;
-  if (pre_replication(memc) == MEMCACHED_SUCCESS &&
-      pre_nonblock(memc) == MEMCACHED_SUCCESS)
-    rc= MEMCACHED_SUCCESS;
-
-  return rc;
-}
-
-static void my_free(memcached_st *ptr __attribute__((unused)), void *mem)
-{
-  free(mem);
-}
-
-static void *my_malloc(memcached_st *ptr __attribute__((unused)), const size_t size)
-{
-  void *ret= malloc(size);
-  if (ret != NULL)
-    memset(ret, 0xff, size);
-
-  return ret;
-}
-
-static void *my_realloc(memcached_st *ptr __attribute__((unused)), void *mem, const size_t size)
-{
-  return realloc(mem, size);
-}
-
-static void *my_calloc(memcached_st *ptr __attribute__((unused)), size_t nelem, const size_t size)
-{
-  return calloc(nelem, size);
-}
-
-static memcached_return set_prefix(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "mine";
-  char *value;
-
-  /* Make sure be default none exists */
-  value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
-  assert(rc == MEMCACHED_FAILURE);
-
-  /* Test a clean set */
-  rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, (void *)key);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
-  assert(memcmp(value, key, 4) == 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  /* Test that we can turn it off */
-  rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, NULL);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
-  assert(rc == MEMCACHED_FAILURE);
-
-  /* Now setup for main test */
-  rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, (void *)key);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(memcmp(value, key, 4) == 0);
-
-  /* Set to Zero, and then Set to something too large */
-  {
-    char long_key[255];
-    memset(long_key, 0, 255);
-
-    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, NULL);
-    assert(rc == MEMCACHED_SUCCESS);
-
-    value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
-    assert(rc == MEMCACHED_FAILURE);
-    assert(value == NULL);
-
-    /* Test a long key for failure */
-    /* TODO, extend test to determine based on setting, what result should be */
-    strcpy(long_key, "Thisismorethentheallottednumberofcharacters");
-    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, long_key);
-    //assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
-    assert(rc == MEMCACHED_SUCCESS);
-
-    /* Now test a key with spaces (which will fail from long key, since bad key is not set) */
-    strcpy(long_key, "This is more then the allotted number of characters");
-    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, long_key);
-    assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
-
-    /* Test for a bad prefix, but with a short key */
-    rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_VERIFY_KEY, 1);
-    assert(rc == MEMCACHED_SUCCESS);
-
-    strcpy(long_key, "dog cat");
-    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, long_key);
-    assert(rc == MEMCACHED_BAD_KEY_PROVIDED);
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-#ifdef MEMCACHED_ENABLE_DEPRECATED
-static memcached_return deprecated_set_memory_alloc(memcached_st *memc)
-{
-  void *test_ptr= NULL;
-  void *cb_ptr= NULL;
-  {
-    memcached_malloc_function malloc_cb=
-      (memcached_malloc_function)my_malloc;
-    cb_ptr= *(void **)&malloc_cb;
-    memcached_return rc;
-
-    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_MALLOC_FUNCTION, cb_ptr);
-    assert(rc == MEMCACHED_SUCCESS);
-    test_ptr= memcached_callback_get(memc, MEMCACHED_CALLBACK_MALLOC_FUNCTION, &rc);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(test_ptr == cb_ptr);
-  }
-
-  {
-    memcached_realloc_function realloc_cb=
-      (memcached_realloc_function)my_realloc;
-    cb_ptr= *(void **)&realloc_cb;
-    memcached_return rc;
-
-    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_REALLOC_FUNCTION, cb_ptr);
-    assert(rc == MEMCACHED_SUCCESS);
-    test_ptr= memcached_callback_get(memc, MEMCACHED_CALLBACK_REALLOC_FUNCTION, &rc);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(test_ptr == cb_ptr);
-  }
-
-  {
-    memcached_free_function free_cb=
-      (memcached_free_function)my_free;
-    cb_ptr= *(void **)&free_cb;
-    memcached_return rc;
-
-    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_FREE_FUNCTION, cb_ptr);
-    assert(rc == MEMCACHED_SUCCESS);
-    test_ptr= memcached_callback_get(memc, MEMCACHED_CALLBACK_FREE_FUNCTION, &rc);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(test_ptr == cb_ptr);
-  }
-  return MEMCACHED_SUCCESS;
-}
-#endif
-
-static memcached_return set_memory_alloc(memcached_st *memc)
-{
-  memcached_return rc;
-  rc= memcached_set_memory_allocators(memc, NULL, my_free,
-                                      my_realloc, my_calloc);
-  assert(rc == MEMCACHED_FAILURE);
-
-  rc= memcached_set_memory_allocators(memc, my_malloc, my_free,
-                                      my_realloc, my_calloc);
-
-  memcached_malloc_function mem_malloc;
-  memcached_free_function mem_free;
-  memcached_realloc_function mem_realloc;
-  memcached_calloc_function mem_calloc;
-  memcached_get_memory_allocators(memc, &mem_malloc, &mem_free,
-                                  &mem_realloc, &mem_calloc);
-
-  assert(mem_malloc == my_malloc);
-  assert(mem_realloc == my_realloc);
-  assert(mem_calloc == my_calloc);
-  assert(mem_free == my_free);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  enable_consistent(memcached_st *memc)
-{
-  memcached_server_distribution value= MEMCACHED_DISTRIBUTION_CONSISTENT;
-  memcached_hash hash;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, value);
-  if (pre_hsieh(memc) != MEMCACHED_SUCCESS)
-    return MEMCACHED_FAILURE;
-
-  value= (memcached_server_distribution)memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION);
-  assert(value == MEMCACHED_DISTRIBUTION_CONSISTENT);
-
-  hash= (memcached_hash)memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_HASH);
-  assert(hash == MEMCACHED_HASH_HSIEH);
-
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  enable_cas(memcached_st *memc)
-{
-  unsigned int set= 1;
-
-  memcached_version(memc);
-
-  if ((memc->hosts[0].major_version >= 1 && (memc->hosts[0].minor_version == 2 && memc->hosts[0].micro_version >= 4))
-      || memc->hosts[0].minor_version > 2)
-  {
-    memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, set);
-
-    return MEMCACHED_SUCCESS;
-  }
-
-  return MEMCACHED_FAILURE;
-}
-
-static memcached_return  check_for_1_2_3(memcached_st *memc)
-{
-  memcached_version(memc);
-
-  if ((memc->hosts[0].major_version >= 1 && (memc->hosts[0].minor_version == 2 && memc->hosts[0].micro_version >= 4))
-      || memc->hosts[0].minor_version > 2)
-    return MEMCACHED_SUCCESS;
-
-  return MEMCACHED_FAILURE;
-}
-
-static memcached_return  pre_unix_socket(memcached_st *memc)
-{
-  memcached_return rc;
-  struct stat buf;
-
-  memcached_server_list_free(memc->hosts);
-  memc->hosts= NULL;
-  memc->number_of_hosts= 0;
-
-  if (stat("/tmp/memcached.socket", &buf))
-    return MEMCACHED_FAILURE;
-
-  rc= memcached_server_add_unix_socket_with_weight(memc, "/tmp/memcached.socket", 0);
-
-  return rc;
-}
-
-static memcached_return  pre_nodelay(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 0);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  pre_settimer(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SND_TIMEOUT, 1000);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RCV_TIMEOUT, 1000);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return  poll_timeout(memcached_st *memc)
-{
-  size_t timeout;
-
-  timeout= 100;
-
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, timeout);
-
-  timeout= (size_t)memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT);
-
-  assert(timeout == 100);
-
-  return MEMCACHED_SUCCESS;
-}
-
-static test_return_t noreply_test(memcached_st *memc)
-{
-  memcached_return ret;
-  ret= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 1);
-  assert(ret == MEMCACHED_SUCCESS);
-  ret= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
-  assert(ret == MEMCACHED_SUCCESS);
-  ret= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1);
-  assert(ret == MEMCACHED_SUCCESS);
-  assert(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NOREPLY) == 1);
-  assert(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS) == 1);
-  assert(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS) == 1);
-
-  for (int count=0; count < 5; ++count)
-  {
-    for (int x=0; x < 100; ++x)
-    {
-      char key[10];
-      size_t len= (size_t)sprintf(key, "%d", x);
-      switch (count)
-      {
-      case 0:
-        ret=memcached_add(memc, key, len, key, len, 0, 0);
-        break;
-      case 1:
-        ret=memcached_replace(memc, key, len, key, len, 0, 0);
-        break;
-      case 2:
-        ret=memcached_set(memc, key, len, key, len, 0, 0);
-        break;
-      case 3:
-        ret=memcached_append(memc, key, len, key, len, 0, 0);
-        break;
-      case 4:
-        ret=memcached_prepend(memc, key, len, key, len, 0, 0);
-        break;
-      default:
-        assert(count);
-        break;
-      }
-      assert(ret == MEMCACHED_SUCCESS || ret == MEMCACHED_BUFFERED);
-    }
-
-    /*
-    ** NOTE: Don't ever do this in your code! this is not a supported use of the
-    ** API and is _ONLY_ done this way to verify that the library works the
-    ** way it is supposed to do!!!!
-    */
-    int no_msg=0;
-    for (uint32_t x=0; x < memc->number_of_hosts; ++x)
-      no_msg+=(int)(memc->hosts[x].cursor_active);
-
-    assert(no_msg == 0);
-    assert(memcached_flush_buffers(memc) == MEMCACHED_SUCCESS);
-
-    /*
-     ** Now validate that all items was set properly!
-     */
-    for (int x=0; x < 100; ++x)
-    {
-      char key[10];
-      size_t len= (size_t)sprintf(key, "%d", x);
-      size_t length;
-      uint32_t flags;
-      char* value=memcached_get(memc, key, strlen(key),
-                                &length, &flags, &ret);
-      assert(ret == MEMCACHED_SUCCESS && value != NULL);
-      switch (count)
-      {
-      case 0: /* FALLTHROUGH */
-      case 1: /* FALLTHROUGH */
-      case 2:
-        assert(strncmp(value, key, len) == 0);
-        assert(len == length);
-        break;
-      case 3:
-        assert(length == len * 2);
-        break;
-      case 4:
-        assert(length == len * 3);
-        break;
-      default:
-        assert(count);
-        break;
-      }
-      free(value);
-    }
-  }
-
-  /* Try setting an illegal cas value (should not return an error to
-   * the caller (because we don't expect a return message from the server)
-   */
-  const char* keys[]= {"0"};
-  size_t lengths[]= {1};
-  size_t length;
-  uint32_t flags;
-  memcached_result_st results_obj;
-  memcached_result_st *results;
-  ret= memcached_mget(memc, keys, lengths, 1);
-  assert(ret == MEMCACHED_SUCCESS);
-
-  results= memcached_result_create(memc, &results_obj);
-  assert(results);
-  results= memcached_fetch_result(memc, &results_obj, &ret);
-  assert(results);
-  assert(ret == MEMCACHED_SUCCESS);
-  uint64_t cas= memcached_result_cas(results);
-  memcached_result_free(&results_obj);
-
-  ret= memcached_cas(memc, keys[0], lengths[0], keys[0], lengths[0], 0, 0, cas);
-  assert(ret == MEMCACHED_SUCCESS);
-
-  /*
-   * The item will have a new cas value, so try to set it again with the old
-   * value. This should fail!
-   */
-  ret= memcached_cas(memc, keys[0], lengths[0], keys[0], lengths[0], 0, 0, cas);
-  assert(ret == MEMCACHED_SUCCESS);
-  assert(memcached_flush_buffers(memc) == MEMCACHED_SUCCESS);
-  char* value=memcached_get(memc, keys[0], lengths[0], &length, &flags, &ret);
-  assert(ret == MEMCACHED_SUCCESS && value != NULL);
-  free(value);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t analyzer_test(memcached_st *memc)
-{
-  memcached_return rc;
-  memcached_stat_st *memc_stat;
-  memcached_analysis_st *report;
-
-  memc_stat= memcached_stat(memc, NULL, &rc);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(memc_stat);
-
-  report= memcached_analyze(memc, memc_stat, &rc);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(report);
-
-  free(report);
-  memcached_stat_free(NULL, memc_stat);
-
-  return TEST_SUCCESS;
-}
-
-/* Count the objects */
-static memcached_return callback_dump_counter(memcached_st *ptr __attribute__((unused)),
-                                              const char *key __attribute__((unused)),
-                                              size_t key_length __attribute__((unused)),
-                                              void *context)
-{
-  uint32_t *counter= (uint32_t *)context;
-
-  *counter= *counter + 1;
-
-  return MEMCACHED_SUCCESS;
-}
-
-static test_return_t dump_test(memcached_st *memc)
-{
-  memcached_return rc;
-  uint32_t counter= 0;
-  memcached_dump_func callbacks[1];
-  test_return_t main_rc;
-
-  callbacks[0]= &callback_dump_counter;
-
-  /* No support for Binary protocol yet */
-  if (memc->flags & MEM_BINARY_PROTOCOL)
-    return TEST_SUCCESS;
-
-  main_rc= set_test3(memc);
-
-  assert (main_rc == TEST_SUCCESS);
-
-  rc= memcached_dump(memc, callbacks, (void *)&counter, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  /* We may have more then 32 if our previous flush has not completed */
-  assert(counter >= 32);
-
-  return TEST_SUCCESS;
-}
-
-#ifdef HAVE_LIBMEMCACHEDUTIL
-static void* connection_release(void *arg) {
-  struct {
-    memcached_pool_st* pool;
-    memcached_st* mmc;
-  } *resource= arg;
-
-  usleep(250);
-  assert(memcached_pool_push(resource->pool, resource->mmc) == MEMCACHED_SUCCESS);
-  return arg;
-}
-
-static test_return_t connection_pool_test(memcached_st *memc)
-{
-  memcached_pool_st* pool= memcached_pool_create(memc, 5, 10);
-  assert(pool != NULL);
-  memcached_st* mmc[10];
-  memcached_return rc;
-
-  for (int x= 0; x < 10; ++x) {
-    mmc[x]= memcached_pool_pop(pool, false, &rc);
-    assert(mmc[x] != NULL);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  assert(memcached_pool_pop(pool, false, &rc) == NULL);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  pthread_t tid;
-  struct {
-    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);
-  assert(rc == MEMCACHED_SUCCESS);
-  pthread_join(tid, NULL);
-  assert(mmc[9] == item.mmc);
-  const char *key= "key";
-  size_t keylen= strlen(key);
-
-  // verify that I can do ops with all connections
-  rc= memcached_set(mmc[0], key, keylen, "0", 1, 0, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  for (unsigned int x= 0; x < 10; ++x) {
-    uint64_t number_value;
-    rc= memcached_increment(mmc[x], key, keylen, 1, &number_value);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(number_value == (x+1));
-  }
-
-  // Release them..
-  for (int x= 0; x < 10; ++x)
-    assert(memcached_pool_push(pool, mmc[x]) == MEMCACHED_SUCCESS);
-
-
-  /* verify that I can set behaviors on the pool when I don't have all
-   * of the connections in the pool. It should however be enabled
-   * when I push the item into the pool
-   */
-  mmc[0]= memcached_pool_pop(pool, false, &rc);
-  assert(mmc[0] != NULL);
-
-  rc= memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK, 9999);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  mmc[1]= memcached_pool_pop(pool, false, &rc);
-  assert(mmc[1] != NULL);
-
-  assert(memcached_behavior_get(mmc[1], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK) == 9999);
-  assert(memcached_pool_push(pool, mmc[1]) == MEMCACHED_SUCCESS);
-  assert(memcached_pool_push(pool, mmc[0]) == MEMCACHED_SUCCESS);
-
-  mmc[0]= memcached_pool_pop(pool, false, &rc);
-  assert(memcached_behavior_get(mmc[0], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK) == 9999);
-  assert(memcached_pool_push(pool, mmc[0]) == MEMCACHED_SUCCESS);
-
-
-  assert(memcached_pool_destroy(pool) == memc);
-  return TEST_SUCCESS;
-}
-#endif
-
-static test_return_t replication_set_test(memcached_st *memc)
-{
-  memcached_return rc;
-  memcached_st *memc_clone= memcached_clone(NULL, memc);
-  memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 0);
-
-  rc= memcached_set(memc, "bubba", 5, "0", 1, 0, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  /*
-  ** We are using the quiet commands to store the replicas, so we need
-  ** to ensure that all of them are processed before we can continue.
-  ** In the test we go directly from storing the object to trying to
-  ** receive the object from all of the different servers, so we
-  ** could end up in a race condition (the memcached server hasn't yet
-  ** processed the quiet command from the replication set when it process
-  ** the request from the other client (created by the clone)). As a
-  ** workaround for that we call memcached_quit to send the quit command
-  ** to the server and wait for the response ;-) If you use the test code
-  ** as an example for your own code, please note that you shouldn't need
-  ** to do this ;-)
-  */
-  memcached_quit(memc);
-
-  /*
-  ** "bubba" should now be stored on all of our servers. We don't have an
-  ** easy to use API to address each individual server, so I'll just iterate
-  ** through a bunch of "master keys" and I should most likely hit all of the
-  ** servers...
-  */
-  for (int x= 'a'; x <= 'z'; ++x)
-  {
-    char key[2]= { [0]= (char)x };
-    size_t len;
-    uint32_t flags;
-    char *val= memcached_get_by_key(memc_clone, key, 1, "bubba", 5,
-                                    &len, &flags, &rc);
-    assert(rc == MEMCACHED_SUCCESS);
-    assert(val != NULL);
-    free(val);
-  }
-
-  memcached_free(memc_clone);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t replication_get_test(memcached_st *memc)
-{
-  memcached_return rc;
-
-  /*
-   * Don't do the following in your code. I am abusing the internal details
-   * within the library, and this is not a supported interface.
-   * This is to verify correct behavior in the library
-   */
-  for (uint32_t host= 0; host < memc->number_of_hosts; ++host)
-  {
-    memcached_st *memc_clone= memcached_clone(NULL, memc);
-    memc_clone->hosts[host].port= 0;
-
-    for (int x= 'a'; x <= 'z'; ++x)
-    {
-      char key[2]= { [0]= (char)x };
-      size_t len;
-      uint32_t flags;
-      char *val= memcached_get_by_key(memc_clone, key, 1, "bubba", 5,
-                                      &len, &flags, &rc);
-      assert(rc == MEMCACHED_SUCCESS);
-      assert(val != NULL);
-      free(val);
-    }
-
-    memcached_free(memc_clone);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t replication_mget_test(memcached_st *memc)
-{
-  memcached_return rc;
-  memcached_st *memc_clone= memcached_clone(NULL, memc);
-  memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 0);
-
-  const char *keys[]= { "bubba", "key1", "key2", "key3" };
-  size_t len[]= { 5, 4, 4, 4 };
-
-  for (int x=0; x< 4; ++x)
-  {
-    rc= memcached_set(memc, keys[x], len[x], "0", 1, 0, 0);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  /*
-  ** We are using the quiet commands to store the replicas, so we need
-  ** to ensure that all of them are processed before we can continue.
-  ** In the test we go directly from storing the object to trying to
-  ** receive the object from all of the different servers, so we
-  ** could end up in a race condition (the memcached server hasn't yet
-  ** processed the quiet command from the replication set when it process
-  ** the request from the other client (created by the clone)). As a
-  ** workaround for that we call memcached_quit to send the quit command
-  ** to the server and wait for the response ;-) If you use the test code
-  ** as an example for your own code, please note that you shouldn't need
-  ** to do this ;-)
-  */
-  memcached_quit(memc);
-
-  /*
-   * Don't do the following in your code. I am abusing the internal details
-   * within the library, and this is not a supported interface.
-   * This is to verify correct behavior in the library
-   */
-  memcached_result_st result_obj;
-  for (uint32_t host= 0; host < memc_clone->number_of_hosts; host++)
-  {
-    memcached_st *new_clone= memcached_clone(NULL, memc);
-    new_clone->hosts[host].port= 0;
-
-    for (int x= 'a'; x <= 'z'; ++x)
-    {
-      const char key[2]= { [0]= (const char)x };
-
-      rc= memcached_mget_by_key(new_clone, key, 1, keys, len, 4);
-      assert(rc == MEMCACHED_SUCCESS);
-
-      memcached_result_st *results= memcached_result_create(new_clone, &result_obj);
-      assert(results);
-
-      int hits= 0;
-      while ((results= memcached_fetch_result(new_clone, &result_obj, &rc)) != NULL)
-      {
-        hits++;
-      }
-      assert(hits == 4);
-      memcached_result_free(&result_obj);
-    }
-
-    memcached_free(new_clone);
-  }
-
-  memcached_free(memc_clone);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t replication_delete_test(memcached_st *memc)
-{
-  memcached_return rc;
-  memcached_st *memc_clone= memcached_clone(NULL, memc);
-  /* Delete the items from all of the servers except 1 */
-  uint64_t repl= memcached_behavior_get(memc,
-                                        MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, --repl);
-
-  const char *keys[]= { "bubba", "key1", "key2", "key3" };
-  size_t len[]= { 5, 4, 4, 4 };
-
-  for (int x=0; x< 4; ++x)
-  {
-    rc= memcached_delete_by_key(memc, keys[0], len[0], keys[x], len[x], 0);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  /*
-   * Don't do the following in your code. I am abusing the internal details
-   * within the library, and this is not a supported interface.
-   * This is to verify correct behavior in the library
-   */
-  uint32_t hash= memcached_generate_hash(memc, keys[0], len[0]);
-  for (uint32_t x= 0; x < (repl + 1); ++x)
-  {
-    memc_clone->hosts[hash].port= 0;
-    if (++hash == memc_clone->number_of_hosts)
-      hash= 0;
-  }
-
-  memcached_result_st result_obj;
-  for (uint32_t host= 0; host < memc_clone->number_of_hosts; ++host)
-  {
-    for (int x= 'a'; x <= 'z'; ++x)
-    {
-      const char key[2]= { [0]= (const char)x };
-
-      rc= memcached_mget_by_key(memc_clone, key, 1, keys, len, 4);
-      assert(rc == MEMCACHED_SUCCESS);
-
-      memcached_result_st *results= memcached_result_create(memc_clone, &result_obj);
-      assert(results);
-
-      int hits= 0;
-      while ((results= memcached_fetch_result(memc_clone, &result_obj, &rc)) != NULL)
-      {
-        ++hits;
-      }
-      assert(hits == 4);
-      memcached_result_free(&result_obj);
-    }
-  }
-  memcached_free(memc_clone);
-
-  return TEST_SUCCESS;
-}
-
-static void increment_request_id(uint16_t *id)
-{
-  (*id)++;
-  if ((*id & UDP_REQUEST_ID_THREAD_MASK) != 0)
-    *id= 0;
-}
-
-static uint16_t *get_udp_request_ids(memcached_st *memc)
-{
-  uint16_t *ids= malloc(sizeof(uint16_t) * memc->number_of_hosts);
-  assert(ids != NULL);
-  unsigned int x;
-
-  for (x= 0; x < memc->number_of_hosts; x++)
-    ids[x]= get_udp_datagram_request_id((struct udp_datagram_header_st *) memc->hosts[x].write_buffer);
-
-  return ids;
-}
-
-static test_return_t post_udp_op_check(memcached_st *memc, uint16_t *expected_req_ids)
-{
-  unsigned int x;
-  memcached_server_st *cur_server = memc->hosts;
-  uint16_t *cur_req_ids = get_udp_request_ids(memc);
-
-  for (x= 0; x < memc->number_of_hosts; x++)
-  {
-    assert(cur_server[x].cursor_active == 0);
-    assert(cur_req_ids[x] == expected_req_ids[x]);
-  }
-  free(expected_req_ids);
-  free(cur_req_ids);
-
-  return TEST_SUCCESS;
-}
-
-/*
-** There is a little bit of a hack here, instead of removing
-** the servers, I just set num host to 0 and them add then new udp servers
-**/
-static memcached_return init_udp(memcached_st *memc)
-{
-  memcached_version(memc);
-  /* For the time being, only support udp test for >= 1.2.6 && < 1.3 */
-  if (memc->hosts[0].major_version != 1 || memc->hosts[0].minor_version != 2
-          || memc->hosts[0].micro_version < 6)
-    return MEMCACHED_FAILURE;
-
-  uint32_t num_hosts= memc->number_of_hosts;
-  unsigned int x= 0;
-  memcached_server_st servers[num_hosts];
-  memcpy(servers, memc->hosts, sizeof(memcached_server_st) * num_hosts);
-  for (x= 0; x < num_hosts; x++)
-    memcached_server_free(&memc->hosts[x]);
-
-  memc->number_of_hosts= 0;
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, 1);
-  for (x= 0; x < num_hosts; x++)
-  {
-    assert(memcached_server_add_udp(memc, servers[x].hostname, servers[x].port) == MEMCACHED_SUCCESS);
-    assert(memc->hosts[x].write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH);
-  }
-
-  return MEMCACHED_SUCCESS;
-}
-
-static memcached_return binary_init_udp(memcached_st *memc)
-{
-  pre_binary(memc);
-  return init_udp(memc);
-}
-
-/* Make sure that I cant add a tcp server to a udp client */
-static test_return_t add_tcp_server_udp_client_test(memcached_st *memc)
-{
-  memcached_server_st server;
-  memcached_server_clone(&server, &memc->hosts[0]);
-  assert(memcached_server_remove(&(memc->hosts[0])) == MEMCACHED_SUCCESS);
-  assert(memcached_server_add(memc, server.hostname, server.port) == MEMCACHED_INVALID_HOST_PROTOCOL);
-  return TEST_SUCCESS;
-}
-
-/* Make sure that I cant add a udp server to a tcp client */
-static test_return_t add_udp_server_tcp_client_test(memcached_st *memc)
-{
-  memcached_server_st server;
-  memcached_server_clone(&server, &memc->hosts[0]);
-  assert(memcached_server_remove(&(memc->hosts[0])) == MEMCACHED_SUCCESS);
-
-  memcached_st tcp_client;
-  memcached_create(&tcp_client);
-  assert(memcached_server_add_udp(&tcp_client, server.hostname, server.port) == MEMCACHED_INVALID_HOST_PROTOCOL);
-  return TEST_SUCCESS;
-}
-
-static test_return_t set_udp_behavior_test(memcached_st *memc)
-{
-
-  memcached_quit(memc);
-  memc->number_of_hosts= 0;
-  run_distribution(memc);
-  assert(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, 1) == MEMCACHED_SUCCESS);
-  assert(memc->flags & MEM_USE_UDP);
-  assert(memc->flags & MEM_NOREPLY);;
-
-  assert(memc->number_of_hosts == 0);
-
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP,0);
-  assert(!(memc->flags & MEM_USE_UDP));
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY,0);
-  assert(!(memc->flags & MEM_NOREPLY));
-  return TEST_SUCCESS;
-}
-
-static test_return_t udp_set_test(memcached_st *memc)
-{
-  unsigned int x= 0;
-  unsigned int num_iters= 1025; //request id rolls over at 1024
-  for (x= 0; x < num_iters;x++)
-  {
-    memcached_return rc;
-    const char *key= "foo";
-    const char *value= "when we sanitize";
-    uint16_t *expected_ids= get_udp_request_ids(memc);
-    unsigned int server_key= memcached_generate_hash(memc,key,strlen(key));
-    size_t init_offset= memc->hosts[server_key].write_buffer_offset;
-    rc= memcached_set(memc, key, strlen(key),
-                      value, strlen(value),
-                      (time_t)0, (uint32_t)0);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-    /** NB, the check below assumes that if new write_ptr is less than
-     *  the original write_ptr that we have flushed. For large payloads, this
-     *  maybe an invalid assumption, but for the small payload we have it is OK
-     */
-    if (rc == MEMCACHED_SUCCESS ||
-            memc->hosts[server_key].write_buffer_offset < init_offset)
-      increment_request_id(&expected_ids[server_key]);
-
-    if (rc == MEMCACHED_SUCCESS)
-    {
-      assert(memc->hosts[server_key].write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH);
-    }
-    else
-    {
-      assert(memc->hosts[server_key].write_buffer_offset != UDP_DATAGRAM_HEADER_LENGTH);
-      assert(memc->hosts[server_key].write_buffer_offset <= MAX_UDP_DATAGRAM_LENGTH);
-    }
-    assert(post_udp_op_check(memc,expected_ids) == TEST_SUCCESS);
-  }
-  return TEST_SUCCESS;
-}
-
-static test_return_t udp_buffered_set_test(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
-  return udp_set_test(memc);
-}
-
-static test_return_t udp_set_too_big_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "bar";
-  char value[MAX_UDP_DATAGRAM_LENGTH];
-  uint16_t *expected_ids= get_udp_request_ids(memc);
-  rc= memcached_set(memc, key, strlen(key),
-                    value, MAX_UDP_DATAGRAM_LENGTH,
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_WRITE_FAILURE);
-  return post_udp_op_check(memc,expected_ids);
-}
-
-static test_return_t udp_delete_test(memcached_st *memc)
-{
-  unsigned int x= 0;
-  unsigned int num_iters= 1025; //request id rolls over at 1024
-  for (x= 0; x < num_iters;x++)
-  {
-    memcached_return rc;
-    const char *key= "foo";
-    uint16_t *expected_ids=get_udp_request_ids(memc);
-    unsigned int server_key= memcached_generate_hash(memc, key, strlen(key));
-    size_t init_offset= memc->hosts[server_key].write_buffer_offset;
-    rc= memcached_delete(memc, key, strlen(key), 0);
-    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-    if (rc == MEMCACHED_SUCCESS || memc->hosts[server_key].write_buffer_offset < init_offset)
-      increment_request_id(&expected_ids[server_key]);
-    if (rc == MEMCACHED_SUCCESS)
-      assert(memc->hosts[server_key].write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH);
-    else
-    {
-      assert(memc->hosts[server_key].write_buffer_offset != UDP_DATAGRAM_HEADER_LENGTH);
-      assert(memc->hosts[server_key].write_buffer_offset <= MAX_UDP_DATAGRAM_LENGTH);
-    }
-    assert(post_udp_op_check(memc,expected_ids) == TEST_SUCCESS);
-  }
-  return TEST_SUCCESS;
-}
-
-static test_return_t udp_buffered_delete_test(memcached_st *memc)
-{
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
-  return udp_delete_test(memc);
-}
-
-static test_return_t udp_verbosity_test(memcached_st *memc)
-{
-  memcached_return rc;
-  uint16_t *expected_ids= get_udp_request_ids(memc);
-  unsigned int x;
-  for (x= 0; x < memc->number_of_hosts;x++)
-    increment_request_id(&expected_ids[x]);
-
-  rc= memcached_verbosity(memc,3);
-  assert(rc == MEMCACHED_SUCCESS);
-  return post_udp_op_check(memc,expected_ids);
-}
-
-static test_return_t udp_quit_test(memcached_st *memc)
-{
-  uint16_t *expected_ids= get_udp_request_ids(memc);
-  memcached_quit(memc);
-  return post_udp_op_check(memc, expected_ids);
-}
-
-static test_return_t udp_flush_test(memcached_st *memc)
-{
-  memcached_return rc;
-  uint16_t *expected_ids= get_udp_request_ids(memc);
-  unsigned int x;
-  for (x= 0; x < memc->number_of_hosts;x++)
-    increment_request_id(&expected_ids[x]);
-
-  rc= memcached_flush(memc,0);
-  assert(rc == MEMCACHED_SUCCESS);
-  return post_udp_op_check(memc,expected_ids);
-}
-
-static test_return_t udp_incr_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "incr";
-  const char *value= "1";
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-
-  assert(rc == MEMCACHED_SUCCESS);
-  uint16_t *expected_ids= get_udp_request_ids(memc);
-  unsigned int server_key= memcached_generate_hash(memc, key, strlen(key));
-  increment_request_id(&expected_ids[server_key]);
-  uint64_t newvalue;
-  rc= memcached_increment(memc, key, strlen(key), 1, &newvalue);
-  assert(rc == MEMCACHED_SUCCESS);
-  return post_udp_op_check(memc, expected_ids);
-}
-
-static test_return_t udp_decr_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "decr";
-  const char *value= "1";
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-
-  assert(rc == MEMCACHED_SUCCESS);
-  uint16_t *expected_ids= get_udp_request_ids(memc);
-  unsigned int server_key= memcached_generate_hash(memc, key, strlen(key));
-  increment_request_id(&expected_ids[server_key]);
-  uint64_t newvalue;
-  rc= memcached_decrement(memc, key, strlen(key), 1, &newvalue);
-  assert(rc == MEMCACHED_SUCCESS);
-  return post_udp_op_check(memc, expected_ids);
-}
-
-
-static test_return_t udp_stat_test(memcached_st *memc)
-{
-  memcached_stat_st * rv= NULL;
-  memcached_return rc;
-  char args[]= "";
-  uint16_t *expected_ids = get_udp_request_ids(memc);
-  rv = memcached_stat(memc, args, &rc);
-  free(rv);
-  assert(rc == MEMCACHED_NOT_SUPPORTED);
-  return post_udp_op_check(memc, expected_ids);
-}
-
-static test_return_t udp_version_test(memcached_st *memc)
-{
-  memcached_return rc;
-  uint16_t *expected_ids = get_udp_request_ids(memc);
-  rc = memcached_version(memc);
-  assert(rc == MEMCACHED_NOT_SUPPORTED);
-  return post_udp_op_check(memc, expected_ids);
-}
-
-static test_return_t udp_get_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  size_t vlen;
-  uint16_t *expected_ids = get_udp_request_ids(memc);
-  char *val= memcached_get(memc, key, strlen(key), &vlen, (uint32_t)0, &rc);
-  assert(rc == MEMCACHED_NOT_SUPPORTED);
-  assert(val == NULL);
-  return post_udp_op_check(memc, expected_ids);
-}
-
-static test_return_t udp_mixed_io_test(memcached_st *memc)
-{
-  test_st current_op;
-  test_st mixed_io_ops [] ={
-    {"udp_set_test", 0, udp_set_test},
-    {"udp_set_too_big_test", 0, udp_set_too_big_test},
-    {"udp_delete_test", 0, udp_delete_test},
-    {"udp_verbosity_test", 0, udp_verbosity_test},
-    {"udp_quit_test", 0, udp_quit_test},
-    {"udp_flush_test", 0, udp_flush_test},
-    {"udp_incr_test", 0, udp_incr_test},
-    {"udp_decr_test", 0, udp_decr_test},
-    {"udp_version_test", 0, udp_version_test}
-  };
-  unsigned int x= 0;
-  for (x= 0; x < 500; x++)
-  {
-    current_op= mixed_io_ops[random() % 9];
-    assert(current_op.function(memc) == TEST_SUCCESS);
-  }
-  return TEST_SUCCESS;
-}
-
-static test_return_t hsieh_avaibility_test (memcached_st *memc)
-{
-  memcached_return expected_rc= MEMCACHED_FAILURE;
-#ifdef HAVE_HSIEH_HASH
-  expected_rc= MEMCACHED_SUCCESS;
-#endif
-  memcached_return rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH,
-                                            (uint64_t)MEMCACHED_HASH_HSIEH);
-  assert(rc == expected_rc);
-  return TEST_SUCCESS;
-}
-
-static const char *list[]=
-{
-  "apple",
-  "beat",
-  "carrot",
-  "daikon",
-  "eggplant",
-  "flower",
-  "green",
-  "hide",
-  "ick",
-  "jack",
-  "kick",
-  "lime",
-  "mushrooms",
-  "nectarine",
-  "orange",
-  "peach",
-  "quant",
-  "ripen",
-  "strawberry",
-  "tang",
-  "up",
-  "volumne",
-  "when",
-  "yellow",
-  "zip",
-  NULL
-};
-
-static test_return_t md5_run (memcached_st *memc __attribute__((unused)))
-{
-  uint32_t x;
-  const char **ptr;
-  uint32_t values[]= {  3195025439U, 2556848621U, 3724893440U, 3332385401U,
-                        245758794U, 2550894432U, 121710495U, 3053817768U,
-                        1250994555U, 1862072655U, 2631955953U, 2951528551U,
-                        1451250070U, 2820856945U, 2060845566U, 3646985608U,
-                        2138080750U, 217675895U, 2230934345U, 1234361223U,
-                        3968582726U, 2455685270U, 1293568479U, 199067604U,
-                        2042482093U };
-
-
-  for (ptr= list, x= 0; *ptr; ptr++, x++)
-  {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_MD5);
-    assert(values[x] == hash_val);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t crc_run (memcached_st *memc __attribute__((unused)))
-{
-  uint32_t x;
-  const char **ptr;
-  uint32_t values[]= {  10542U, 22009U, 14526U, 19510U, 19432U, 10199U, 20634U,
-                        9369U, 11511U, 10362U, 7893U, 31289U, 11313U, 9354U,
-                        7621U, 30628U, 15218U, 25967U, 2695U, 9380U,
-                        17300U, 28156U, 9192U, 20484U, 16925U };
-
-  for (ptr= list, x= 0; *ptr; ptr++, x++)
-  {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_CRC);
-    assert(values[x] == hash_val);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t fnv1_64_run (memcached_st *memc __attribute__((unused)))
-{
-  uint32_t x;
-  const char **ptr;
-  uint32_t values[]= {  473199127U, 4148981457U, 3971873300U, 3257986707U,
-                        1722477987U, 2991193800U, 4147007314U, 3633179701U,
-                        1805162104U, 3503289120U, 3395702895U, 3325073042U,
-                        2345265314U, 3340346032U, 2722964135U, 1173398992U,
-                        2815549194U, 2562818319U, 224996066U, 2680194749U,
-                        3035305390U, 246890365U, 2395624193U, 4145193337U,
-                        1801941682U };
-
-  for (ptr= list, x= 0; *ptr; ptr++, x++)
-  {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1_64);
-    assert(values[x] == hash_val);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t fnv1a_64_run (memcached_st *memc __attribute__((unused)))
-{
-  uint32_t x;
-  const char **ptr;
-  uint32_t values[]= {  1488911807U, 2500855813U, 1510099634U, 1390325195U,
-                        3647689787U, 3241528582U, 1669328060U, 2604311949U,
-                        734810122U, 1516407546U, 560948863U, 1767346780U,
-                        561034892U, 4156330026U, 3716417003U, 3475297030U,
-                        1518272172U, 227211583U, 3938128828U, 126112909U,
-                        3043416448U, 3131561933U, 1328739897U, 2455664041U,
-                        2272238452U };
-
-  for (ptr= list, x= 0; *ptr; ptr++, x++)
-  {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1A_64);
-    assert(values[x] == hash_val);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t fnv1_32_run (memcached_st *memc __attribute__((unused)))
-{
-  uint32_t x;
-  const char **ptr;
-  uint32_t values[]= {  67176023U, 1190179409U, 2043204404U, 3221866419U,
-                        2567703427U, 3787535528U, 4147287986U, 3500475733U,
-                        344481048U, 3865235296U, 2181839183U, 119581266U,
-                        510234242U, 4248244304U, 1362796839U, 103389328U,
-                        1449620010U, 182962511U, 3554262370U, 3206747549U,
-                        1551306158U, 4127558461U, 1889140833U, 2774173721U,
-                        1180552018U };
-
-
-  for (ptr= list, x= 0; *ptr; ptr++, x++)
-  {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1_32);
-    assert(values[x] == hash_val);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t fnv1a_32_run (memcached_st *memc __attribute__((unused)))
-{
-  uint32_t x;
-  const char **ptr;
-  uint32_t values[]= {  280767167U, 2421315013U, 3072375666U, 855001899U,
-                        459261019U, 3521085446U, 18738364U, 1625305005U,
-                        2162232970U, 777243802U, 3323728671U, 132336572U,
-                        3654473228U, 260679466U, 1169454059U, 2698319462U,
-                        1062177260U, 235516991U, 2218399068U, 405302637U,
-                        1128467232U, 3579622413U, 2138539289U, 96429129U,
-                        2877453236U };
-
-  for (ptr= list, x= 0; *ptr; ptr++, x++)
-  {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1A_32);
-    assert(values[x] == hash_val);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t hsieh_run (memcached_st *memc __attribute__((unused)))
-{
-  uint32_t x;
-  const char **ptr;
-#ifdef HAVE_HSIEH_HASH
-  uint32_t values[]= {  3738850110, 3636226060, 3821074029, 3489929160, 3485772682, 80540287,
-                        1805464076, 1895033657, 409795758, 979934958, 3634096985, 1284445480,
-                        2265380744, 707972988, 353823508, 1549198350, 1327930172, 9304163,
-                        4220749037, 2493964934, 2777873870, 2057831732, 1510213931, 2027828987,
-                        3395453351 };
-#else
-  uint32_t values[]= {  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
-#endif
-
-  for (ptr= list, x= 0; *ptr; ptr++, x++)
-  {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_HSIEH);
-    assert(values[x] == hash_val);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t murmur_run (memcached_st *memc __attribute__((unused)))
-{
-  uint32_t x;
-  const char **ptr;
-  uint32_t values[]= { 473199127U, 4148981457U, 3971873300U, 3257986707U,
-                       1722477987U, 2991193800U, 4147007314U, 3633179701U,
-                       1805162104U, 3503289120U, 3395702895U, 3325073042U,
-                       2345265314U, 3340346032U, 2722964135U, 1173398992U,
-                       2815549194U, 2562818319U, 224996066U, 2680194749U,
-                       3035305390U, 246890365U, 2395624193U, 4145193337U,
-                       1801941682U };
-
-  for (ptr= list, x= 0; *ptr; ptr++, x++)
-  {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1_64);
-    assert(values[x] == hash_val);
-  }
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t jenkins_run (memcached_st *memc __attribute__((unused)))
-{
-  uint32_t x;
-  const char **ptr;
-  uint32_t values[]= {  1442444624U, 4253821186U, 1885058256U, 2120131735U,
-                        3261968576U, 3515188778U, 4232909173U, 4288625128U,
-                        1812047395U, 3689182164U, 2502979932U, 1214050606U,
-                        2415988847U, 1494268927U, 1025545760U, 3920481083U,
-                        4153263658U, 3824871822U, 3072759809U, 798622255U,
-                        3065432577U, 1453328165U, 2691550971U, 3408888387U,
-                        2629893356U };
-
-
-  for (ptr= list, x= 0; *ptr; ptr++, x++)
-  {
-    uint32_t hash_val;
-
-    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_JENKINS);
-    assert(values[x] == hash_val);
-  }
-
-  return TEST_SUCCESS;
-}
-
-
-static test_return_t ketama_compatibility_libmemcached(memcached_st *trash)
-{
-  memcached_return rc;
-  uint64_t value;
-  int x;
-  memcached_server_st *server_pool;
-  memcached_st *memc;
-
-  (void)trash;
-
-  memc= memcached_create(NULL);
-  assert(memc);
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
-  assert(value == 1);
-
-  assert(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE,
-                                MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED) == MEMCACHED_SUCCESS);
-
-  assert(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE) ==
-         MEMCACHED_KETAMA_COMPAT_LIBMEMCACHED);
-
-  server_pool = memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
-  memcached_server_push(memc, server_pool);
-
-  /* verify that the server list was parsed okay. */
-  assert(memc->number_of_hosts == 8);
-  assert(strcmp(server_pool[0].hostname, "10.0.1.1") == 0);
-  assert(server_pool[0].port == 11211);
-  assert(server_pool[0].weight == 600);
-  assert(strcmp(server_pool[2].hostname, "10.0.1.3") == 0);
-  assert(server_pool[2].port == 11211);
-  assert(server_pool[2].weight == 200);
-  assert(strcmp(server_pool[7].hostname, "10.0.1.8") == 0);
-  assert(server_pool[7].port == 11211);
-  assert(server_pool[7].weight == 100);
-
-  /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
-   * us test the boundary wraparound.
-   */
-  assert(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->continuum[0].index);
-
-  /* verify the standard ketama set. */
-  for (x= 0; x < 99; x++)
-  {
-    uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
-    char *hostname = memc->hosts[server_idx].hostname;
-    assert(strcmp(hostname, ketama_test_cases[x].server) == 0);
-  }
-
-  memcached_server_list_free(server_pool);
-  memcached_free(memc);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t ketama_compatibility_spymemcached(memcached_st *trash)
-{
-  memcached_return rc;
-  uint64_t value;
-  int x;
-  memcached_server_st *server_pool;
-  memcached_st *memc;
-
-  (void)trash;
-
-  memc= memcached_create(NULL);
-  assert(memc);
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
-  assert(value == 1);
-
-  assert(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE,
-                                MEMCACHED_KETAMA_COMPAT_SPY) == MEMCACHED_SUCCESS);
-
-  assert(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_COMPAT_MODE) ==
-         MEMCACHED_KETAMA_COMPAT_SPY);
-
-  server_pool = memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
-  memcached_server_push(memc, server_pool);
-
-  /* verify that the server list was parsed okay. */
-  assert(memc->number_of_hosts == 8);
-  assert(strcmp(server_pool[0].hostname, "10.0.1.1") == 0);
-  assert(server_pool[0].port == 11211);
-  assert(server_pool[0].weight == 600);
-  assert(strcmp(server_pool[2].hostname, "10.0.1.3") == 0);
-  assert(server_pool[2].port == 11211);
-  assert(server_pool[2].weight == 200);
-  assert(strcmp(server_pool[7].hostname, "10.0.1.8") == 0);
-  assert(server_pool[7].port == 11211);
-  assert(server_pool[7].weight == 100);
-
-  /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
-   * us test the boundary wraparound.
-   */
-  assert(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->continuum[0].index);
-
-  /* verify the standard ketama set. */
-  for (x= 0; x < 99; x++)
-  {
-    uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases_spy[x].key, strlen(ketama_test_cases_spy[x].key));
-    char *hostname = memc->hosts[server_idx].hostname;
-    assert(strcmp(hostname, ketama_test_cases_spy[x].server) == 0);
-  }
-
-  memcached_server_list_free(server_pool);
-  memcached_free(memc);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t regression_bug_434484(memcached_st *memc)
-{
-  if (pre_binary(memc) != MEMCACHED_SUCCESS)
-    return TEST_SKIPPED;
-
-  memcached_return ret;
-  const char *key= "regression_bug_434484";
-  size_t keylen= strlen(key);
-
-  ret= memcached_append(memc, key, keylen, key, keylen, 0, 0);
-  assert(ret == MEMCACHED_NOTSTORED);
-
-  size_t size= 2048 * 1024;
-  void *data= calloc(1, size);
-  assert(data != NULL);
-  ret= memcached_set(memc, key, keylen, data, size, 0, 0);
-  assert(ret == MEMCACHED_E2BIG);
-  free(data);
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t regression_bug_434843(memcached_st *memc)
-{
-  if (pre_binary(memc) != MEMCACHED_SUCCESS)
-    return TEST_SKIPPED;
-
-  memcached_return rc;
-  unsigned int counter= 0;
-  memcached_execute_function callbacks[1]= { [0]= &callback_counter };
-
-  /*
-   * I only want to hit only _one_ server so I know the number of requests I'm
-   * sending in the pipleine to the server. Let's try to do a multiget of
-   * 1024 (that should satisfy most users don't you think?). Future versions
-   * will include a mget_execute function call if you need a higher number.
-   */
-  uint32_t number_of_hosts= memc->number_of_hosts;
-  memc->number_of_hosts= 1;
-  const size_t max_keys= 1024;
-  char **keys= calloc(max_keys, sizeof(char*));
-  size_t *key_length=calloc(max_keys, sizeof(size_t));
-
-  for (int x= 0; x < (int)max_keys; ++x)
-  {
-     char k[251];
-     key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%u", x);
-     keys[x]= strdup(k);
-     assert(keys[x] != NULL);
-  }
-
-  /*
-   * Run two times.. the first time we should have 100% cache miss,
-   * and the second time we should have 100% cache hits
-   */
-  for (int y= 0; y < 2; ++y)
-  {
-    rc= memcached_mget(memc, (const char**)keys, key_length, max_keys);
-    assert(rc == MEMCACHED_SUCCESS);
-    rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
-    if (y == 0)
-    {
-      /* The first iteration should give me a 100% cache miss. verify that*/
-      assert(counter == 0);
-      char blob[1024]= { 0 };
-      for (int x= 0; x < (int)max_keys; ++x)
-      {
-        rc= memcached_add(memc, keys[x], key_length[x],
-                          blob, sizeof(blob), 0, 0);
-        assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-      }
-    }
-    else
-    {
-      /* Verify that we received all of the key/value pairs */
-       assert(counter == (unsigned int)max_keys);
-    }
-  }
-
-  /* Release allocated resources */
-  for (size_t x= 0; x < max_keys; ++x)
-    free(keys[x]);
-  free(keys);
-  free(key_length);
-
-  memc->number_of_hosts= number_of_hosts;
-  return TEST_SUCCESS;
-}
-
-static test_return_t regression_bug_434843_buffered(memcached_st *memc)
-{
-  memcached_return rc;
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  return regression_bug_434843(memc);
-}
-
-static test_return_t regression_bug_421108(memcached_st *memc)
-{
-  memcached_return rc;
-  memcached_stat_st *memc_stat= memcached_stat(memc, NULL, &rc);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  char *bytes= memcached_stat_get_value(memc, memc_stat, "bytes", &rc);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(bytes != NULL);
-  char *bytes_read= memcached_stat_get_value(memc, memc_stat,
-                                             "bytes_read", &rc);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(bytes_read != NULL);
-
-  char *bytes_written= memcached_stat_get_value(memc, memc_stat,
-                                                "bytes_written", &rc);
-  assert(rc == MEMCACHED_SUCCESS);
-  assert(bytes_written != NULL);
-
-  assert(strcmp(bytes, bytes_read) != 0);
-  assert(strcmp(bytes, bytes_written) != 0);
-
-  /* Release allocated resources */
-  free(bytes);
-  free(bytes_read);
-  free(bytes_written);
-  memcached_stat_free(NULL, memc_stat);
-  return TEST_SUCCESS;
-}
-
-/*
- * The test case isn't obvious so I should probably document why
- * it works the way it does. Bug 442914 was caused by a bug
- * in the logic in memcached_purge (it did not handle the case
- * where the number of bytes sent was equal to the watermark).
- * In this test case, create messages so that we hit that case
- * and then disable noreply mode and issue a new command to
- * verify that it isn't stuck. If we change the format for the
- * delete command or the watermarks, we need to update this
- * test....
- */
-static test_return_t regression_bug_442914(memcached_st *memc)
-{
-  memcached_return rc;
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 1);
-  assert(rc == MEMCACHED_SUCCESS);
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);
-
-  uint32_t number_of_hosts= memc->number_of_hosts;
-  memc->number_of_hosts= 1;
-
-  char k[250];
-  size_t len;
-
-  for (int x= 0; x < 250; ++x)
-  {
-     len= (size_t)snprintf(k, sizeof(k), "%0250u", x);
-     rc= memcached_delete(memc, k, len, 0);
-     assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-  }
-
-  len= (size_t)snprintf(k, sizeof(k), "%037u", 251);
-  rc= memcached_delete(memc, k, len, 0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 0);
-  assert(rc == MEMCACHED_SUCCESS);
-  rc= memcached_delete(memc, k, len, 0);
-  assert(rc == MEMCACHED_NOTFOUND);
-
-  memc->number_of_hosts= number_of_hosts;
-
-  return TEST_SUCCESS;
-}
-
-static test_return_t regression_bug_447342(memcached_st *memc)
-{
-  if (memc->number_of_hosts < 3 || pre_replication(memc) != MEMCACHED_SUCCESS)
-    return TEST_SKIPPED;
-
-  memcached_return rc;
-
-  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 2);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  const size_t max_keys= 100;
-  char **keys= calloc(max_keys, sizeof(char*));
-  size_t *key_length=calloc(max_keys, sizeof(size_t));
-
-  for (int x= 0; x < (int)max_keys; ++x)
-  {
-    char k[251];
-    key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%u", x);
-    keys[x]= strdup(k);
-    assert(keys[x] != NULL);
-    rc= memcached_set(memc, k, key_length[x], k, key_length[x], 0, 0);
-    assert(rc == MEMCACHED_SUCCESS);
-  }
-
-  /*
-  ** We are using the quiet commands to store the replicas, so we need
-  ** to ensure that all of them are processed before we can continue.
-  ** In the test we go directly from storing the object to trying to
-  ** receive the object from all of the different servers, so we
-  ** could end up in a race condition (the memcached server hasn't yet
-  ** processed the quiet command from the replication set when it process
-  ** the request from the other client (created by the clone)). As a
-  ** workaround for that we call memcached_quit to send the quit command
-  ** to the server and wait for the response ;-) If you use the test code
-  ** as an example for your own code, please note that you shouldn't need
-  ** to do this ;-)
-  */
-  memcached_quit(memc);
-
-  /* Verify that all messages are stored, and we didn't stuff too much
-   * into the servers
-   */
-  rc= memcached_mget(memc, (const char* const *)keys, key_length, max_keys);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  unsigned int counter= 0;
-  memcached_execute_function callbacks[1]= { [0]= &callback_counter };
-  rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
-  /* Verify that we received all of the key/value pairs */
-  assert(counter == (unsigned int)max_keys);
-
-  memcached_quit(memc);
-  /*
-   * Don't do the following in your code. I am abusing the internal details
-   * within the library, and this is not a supported interface.
-   * This is to verify correct behavior in the library. Fake that two servers
-   * are dead..
-   */
-  unsigned int port0= memc->hosts[0].port;
-  unsigned int port2= memc->hosts[2].port;
-  memc->hosts[0].port= 0;
-  memc->hosts[2].port= 0;
-
-  rc= memcached_mget(memc, (const char* const *)keys, key_length, max_keys);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  counter= 0;
-  rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
-  assert(counter == (unsigned int)max_keys);
-
-  /* restore the memc handle */
-  memc->hosts[0].port= port0;
-  memc->hosts[2].port= port2;
-
-  memcached_quit(memc);
-
-  /* Remove half of the objects */
-  for (int x= 0; x < (int)max_keys; ++x)
-    if (x & 1)
-    {
-      rc= memcached_delete(memc, keys[x], key_length[x], 0);
-      assert(rc == MEMCACHED_SUCCESS);
-    }
-
-  memcached_quit(memc);
-  memc->hosts[0].port= 0;
-  memc->hosts[2].port= 0;
-
-  /* now retry the command, this time we should have cache misses */
-  rc= memcached_mget(memc, (const char* const *)keys, key_length, max_keys);
-  assert(rc == MEMCACHED_SUCCESS);
-
-  counter= 0;
-  rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
-  assert(counter == (unsigned int)(max_keys >> 1));
-
-  /* Release allocated resources */
-  for (size_t x= 0; x < max_keys; ++x)
-    free(keys[x]);
-  free(keys);
-  free(key_length);
-
-  /* restore the memc handle */
-  memc->hosts[0].port= port0;
-  memc->hosts[2].port= port2;
-  return TEST_SUCCESS;
-}
-
-static test_return_t regression_bug_463297(memcached_st *memc)
-{
-  memcached_st *memc_clone= memcached_clone(NULL, memc);
-  assert(memc_clone != NULL);
-  assert(memcached_version(memc_clone) == MEMCACHED_SUCCESS);
-
-  if (memc_clone->hosts[0].major_version > 1 ||
-      (memc_clone->hosts[0].major_version == 1 &&
-       memc_clone->hosts[0].minor_version > 2))
-  {
-     /* Binary protocol doesn't support deferred delete */
-     memcached_st *bin_clone= memcached_clone(NULL, memc);
-     assert(bin_clone != NULL);
-     assert(memcached_behavior_set(bin_clone, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1) == MEMCACHED_SUCCESS);
-     assert(memcached_delete(bin_clone, "foo", 3, 1) == MEMCACHED_INVALID_ARGUMENTS);
-     memcached_free(bin_clone);
-
-     memcached_quit(memc_clone);
-
-     /* If we know the server version, deferred delete should fail
-      * with invalid arguments */
-     assert(memcached_delete(memc_clone, "foo", 3, 1) == MEMCACHED_INVALID_ARGUMENTS);
-
-     /* If we don't know the server version, we should get a protocol error */
-     memcached_return rc= memcached_delete(memc, "foo", 3, 1);
-     /* but there is a bug in some of the memcached servers (1.4) that treats
-      * the counter as noreply so it doesn't send the proper error message
-      */
-     assert(rc == MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_NOTFOUND || rc == MEMCACHED_CLIENT_ERROR);
-
-     /* And buffered mode should be disabled and we should get protocol error */
-     assert(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1) == MEMCACHED_SUCCESS);
-     rc= memcached_delete(memc, "foo", 3, 1);
-     assert(rc == MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_NOTFOUND || rc == MEMCACHED_CLIENT_ERROR);
-
-     /* Same goes for noreply... */
-     assert(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 1) == MEMCACHED_SUCCESS);
-     rc= memcached_delete(memc, "foo", 3, 1);
-     assert(rc == MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_NOTFOUND || rc == MEMCACHED_CLIENT_ERROR);
-
-     /* but a normal request should go through (and be buffered) */
-     assert((rc= memcached_delete(memc, "foo", 3, 0)) == MEMCACHED_BUFFERED);
-     assert(memcached_flush_buffers(memc) == MEMCACHED_SUCCESS);
-
-     assert(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0) == MEMCACHED_SUCCESS);
-     /* unbuffered noreply should be success */
-     assert(memcached_delete(memc, "foo", 3, 0) == MEMCACHED_SUCCESS);
-     /* unbuffered with reply should be not found... */
-     assert(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 0) == MEMCACHED_SUCCESS);
-     assert(memcached_delete(memc, "foo", 3, 0) == MEMCACHED_NOTFOUND);
-  }
-
-  memcached_free(memc_clone);
-  return TEST_SUCCESS;
-}
-
-
-/* Test memcached_server_get_last_disconnect
- * For a working server set, shall be NULL
- * For a set of non existing server, shall not be NULL
- */
-static test_return_t  test_get_last_disconnect(memcached_st *memc)
-{
-  memcached_return rc;
-  memcached_server_st *disconnected_server;
-
-  /* With the working set of server */
-  const char *key= "marmotte";
-  const char *value= "milka";
-
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  disconnected_server = memcached_server_get_last_disconnect(memc);
-  assert(disconnected_server == NULL);
-
-  /* With a non existing server */
-  memcached_st *mine;
-  memcached_server_st *servers;
-
-  const char *server_list= "localhost:9";
-
-  servers= memcached_servers_parse(server_list);
-  assert(servers);
-  mine= memcached_create(NULL);
-  rc= memcached_server_push(mine, servers);
-  assert(rc == MEMCACHED_SUCCESS);
-  memcached_server_list_free(servers);
-  assert(mine);
-
-  rc= memcached_set(mine, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc != MEMCACHED_SUCCESS);
-
-  disconnected_server = memcached_server_get_last_disconnect(mine);
-  assert(disconnected_server != NULL);
-  assert(disconnected_server->port == 9);
-  assert(strncmp(disconnected_server->hostname,"localhost",9) == 0);
-
-  memcached_quit(mine);
-  memcached_free(mine);
-
-  return TEST_SUCCESS;
-}
-
-/*
- * This test ensures that the failure counter isn't incremented during
- * normal termination of the memcached instance.
- */
-static test_return_t wrong_failure_counter_test(memcached_st *memc)
-{
-  memcached_return rc;
-
-  /* Set value to force connection to the server */
-  const char *key= "marmotte";
-  const char *value= "milka";
-
-  /*
-   * Please note that I'm abusing the internal structures in libmemcached
-   * in a non-portable way and you shouldn't be doing this. I'm only
-   * doing this in order to verify that the library works the way it should
-   */
-  uint32_t number_of_hosts= memc->number_of_hosts;
-  memc->number_of_hosts= 1;
-
-  /* Ensure that we are connected to the server by setting a value */
-  rc= memcached_set(memc, key, strlen(key),
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-
-  /* The test is to see that the memcached_quit doesn't increase the
-   * the server failure conter, so let's ensure that it is zero
-   * before sending quit
-   */
-  memc->hosts[0].server_failure_counter= 0;
-
-  memcached_quit(memc);
-
-  /* Verify that it memcached_quit didn't increment the failure counter
-   * Please note that this isn't bullet proof, because an error could
-   * occur...
-   */
-  assert(memc->hosts[0].server_failure_counter == 0);
-
-  /* restore the instance */
-  memc->number_of_hosts= number_of_hosts;
-
-  return TEST_SUCCESS;
-}
-
-test_st udp_setup_server_tests[] ={
-  {"set_udp_behavior_test", 0, set_udp_behavior_test},
-  {"add_tcp_server_udp_client_test", 0, add_tcp_server_udp_client_test},
-  {"add_udp_server_tcp_client_test", 0, add_udp_server_tcp_client_test},
-  {0, 0, 0}
-};
-
-test_st upd_io_tests[] ={
-  {"udp_set_test", 0, udp_set_test},
-  {"udp_buffered_set_test", 0, udp_buffered_set_test},
-  {"udp_set_too_big_test", 0, udp_set_too_big_test},
-  {"udp_delete_test", 0, udp_delete_test},
-  {"udp_buffered_delete_test", 0, udp_buffered_delete_test},
-  {"udp_verbosity_test", 0, udp_verbosity_test},
-  {"udp_quit_test", 0, udp_quit_test},
-  {"udp_flush_test", 0, udp_flush_test},
-  {"udp_incr_test", 0, udp_incr_test},
-  {"udp_decr_test", 0, udp_decr_test},
-  {"udp_stat_test", 0, udp_stat_test},
-  {"udp_version_test", 0, udp_version_test},
-  {"udp_get_test", 0, udp_get_test},
-  {"udp_mixed_io_test", 0, udp_mixed_io_test},
-  {0, 0, 0}
-};
-
-/* Clean the server before beginning testing */
-test_st tests[] ={
-  {"flush", 0, flush_test },
-  {"init", 0, init_test },
-  {"allocation", 0, allocation_test },
-  {"server_list_null_test", 0, server_list_null_test},
-  {"server_unsort", 0, server_unsort_test},
-  {"server_sort", 0, server_sort_test},
-  {"server_sort2", 0, server_sort2_test},
-  {"clone_test", 0, clone_test },
-  {"connection_test", 0, connection_test},
-  {"callback_test", 0, callback_test},
-  {"behavior_test", 0, behavior_test},
-  {"userdata_test", 0, userdata_test},
-  {"error", 0, error_test },
-  {"set", 0, set_test },
-  {"set2", 0, set_test2 },
-  {"set3", 0, set_test3 },
-  {"dump", 1, dump_test},
-  {"add", 1, add_test },
-  {"replace", 1, replace_test },
-  {"delete", 1, delete_test },
-  {"get", 1, get_test },
-  {"get2", 0, get_test2 },
-  {"get3", 0, get_test3 },
-  {"get4", 0, get_test4 },
-  {"partial mget", 0, get_test5 },
-  {"stats_servername", 0, stats_servername_test },
-  {"increment", 0, increment_test },
-  {"increment_with_initial", 1, increment_with_initial_test },
-  {"decrement", 0, decrement_test },
-  {"decrement_with_initial", 1, decrement_with_initial_test },
-  {"increment_by_key", 0, increment_by_key_test },
-  {"increment_with_initial_by_key", 1, increment_with_initial_by_key_test },
-  {"decrement_by_key", 0, decrement_by_key_test },
-  {"decrement_with_initial_by_key", 1, decrement_with_initial_by_key_test },
-  {"quit", 0, quit_test },
-  {"mget", 1, mget_test },
-  {"mget_result", 1, mget_result_test },
-  {"mget_result_alloc", 1, mget_result_alloc_test },
-  {"mget_result_function", 1, mget_result_function },
-  {"mget_execute", 1, mget_execute },
-  {"mget_end", 0, mget_end },
-  {"get_stats", 0, get_stats },
-  {"add_host_test", 0, add_host_test },
-  {"add_host_test_1", 0, add_host_test1 },
-  {"get_stats_keys", 0, get_stats_keys },
-  {"behavior_test", 0, get_stats_keys },
-  {"callback_test", 0, get_stats_keys },
-  {"version_string_test", 0, version_string_test},
-  {"bad_key", 1, bad_key_test },
-  {"memcached_server_cursor", 1, memcached_server_cursor_test },
-  {"read_through", 1, read_through },
-  {"delete_through", 1, delete_through },
-  {"noreply", 1, noreply_test},
-  {"analyzer", 1, analyzer_test},
-#ifdef HAVE_LIBMEMCACHEDUTIL
-  {"connectionpool", 1, connection_pool_test },
-#endif
-  {"test_get_last_disconnect", 1, test_get_last_disconnect},
-  {0, 0, 0}
-};
-
-test_st async_tests[] ={
-  {"add", 1, add_wrapper },
-  {0, 0, 0}
-};
-
-test_st string_tests[] ={
-  {"string static with null", 0, string_static_null },
-  {"string alloc with null", 0, string_alloc_null },
-  {"string alloc with 1K", 0, string_alloc_with_size },
-  {"string alloc with malloc failure", 0, string_alloc_with_size_toobig },
-  {"string append", 0, string_alloc_append },
-  {"string append failure (too big)", 0, string_alloc_append_toobig },
-  {0, 0, 0}
-};
-
-test_st result_tests[] ={
-  {"result static", 0, result_static},
-  {"result alloc", 0, result_alloc},
-  {0, 0, 0}
-};
-
-test_st version_1_2_3[] ={
-  {"append", 0, append_test },
-  {"prepend", 0, prepend_test },
-  {"cas", 0, cas_test },
-  {"cas2", 0, cas2_test },
-  {"append_binary", 0, append_binary_test },
-  {0, 0, 0}
-};
-
-test_st user_tests[] ={
-  {"user_supplied_bug1", 0, user_supplied_bug1 },
-  {"user_supplied_bug2", 0, user_supplied_bug2 },
-  {"user_supplied_bug3", 0, user_supplied_bug3 },
-  {"user_supplied_bug4", 0, user_supplied_bug4 },
-  {"user_supplied_bug5", 1, user_supplied_bug5 },
-  {"user_supplied_bug6", 1, user_supplied_bug6 },
-  {"user_supplied_bug7", 1, user_supplied_bug7 },
-  {"user_supplied_bug8", 1, user_supplied_bug8 },
-  {"user_supplied_bug9", 1, user_supplied_bug9 },
-  {"user_supplied_bug10", 1, user_supplied_bug10 },
-  {"user_supplied_bug11", 1, user_supplied_bug11 },
-  {"user_supplied_bug12", 1, user_supplied_bug12 },
-  {"user_supplied_bug13", 1, user_supplied_bug13 },
-  {"user_supplied_bug14", 1, user_supplied_bug14 },
-  {"user_supplied_bug15", 1, user_supplied_bug15 },
-  {"user_supplied_bug16", 1, user_supplied_bug16 },
-#ifndef __sun
-  /*
-  ** It seems to be something weird with the character sets..
-  ** value_fetch is unable to parse the value line (iscntrl "fails"), so I
-  ** guess I need to find out how this is supposed to work.. Perhaps I need
-  ** to run the test in a specific locale (I tried zh_CN.UTF-8 without success,
-  ** so just disable the code for now...).
-  */
-  {"user_supplied_bug17", 1, user_supplied_bug17 },
-#endif
-  {"user_supplied_bug18", 1, user_supplied_bug18 },
-  {"user_supplied_bug19", 1, user_supplied_bug19 },
-  {"user_supplied_bug20", 1, user_supplied_bug20 },
-  {"user_supplied_bug21", 1, user_supplied_bug21 },
-  {"wrong_failure_counter_test", 1, wrong_failure_counter_test},
-  {0, 0, 0}
-};
-
-test_st replication_tests[]= {
-  {"set", 1, replication_set_test },
-  {"get", 0, replication_get_test },
-  {"mget", 0, replication_mget_test },
-  {"delete", 0, replication_delete_test },
-  {0, 0, 0}
-};
-
-/*
- * The following test suite is used to verify that we don't introduce
- * regression bugs. If you want more information about the bug / test,
- * you should look in the bug report at
- *   http://bugs.launchpad.net/libmemcached
- */
-test_st regression_tests[]= {
-  {"lp:434484", 1, regression_bug_434484 },
-  {"lp:434843", 1, regression_bug_434843 },
-  {"lp:434843 buffered", 1, regression_bug_434843_buffered },
-  {"lp:421108", 1, regression_bug_421108 },
-  {"lp:442914", 1, regression_bug_442914 },
-  {"lp:447342", 1, regression_bug_447342 },
-  {"lp:463297", 1, regression_bug_463297 },
-  {0, 0, 0}
-};
-
-test_st ketama_compatibility[]= {
-  {"libmemcached", 1, ketama_compatibility_libmemcached },
-  {"spymemcached", 1, ketama_compatibility_spymemcached },
-  {0, 0, 0}
-};
-
-test_st generate_tests[] ={
-  {"generate_pairs", 1, generate_pairs },
-  {"generate_data", 1, generate_data },
-  {"get_read", 0, get_read },
-  {"delete_generate", 0, delete_generate },
-  {"generate_buffer_data", 1, generate_buffer_data },
-  {"delete_buffer", 0, delete_buffer_generate},
-  {"generate_data", 1, generate_data },
-  {"mget_read", 0, mget_read },
-  {"mget_read_result", 0, mget_read_result },
-  {"mget_read_function", 0, mget_read_function },
-  {"cleanup", 1, cleanup_pairs },
-  {"generate_large_pairs", 1, generate_large_pairs },
-  {"generate_data", 1, generate_data },
-  {"generate_buffer_data", 1, generate_buffer_data },
-  {"cleanup", 1, cleanup_pairs },
-  {0, 0, 0}
-};
-
-test_st consistent_tests[] ={
-  {"generate_pairs", 1, generate_pairs },
-  {"generate_data", 1, generate_data },
-  {"get_read", 0, get_read_count },
-  {"cleanup", 1, cleanup_pairs },
-  {0, 0, 0}
-};
-
-test_st consistent_weighted_tests[] ={
-  {"generate_pairs", 1, generate_pairs },
-  {"generate_data", 1, generate_data_with_stats },
-  {"get_read", 0, get_read_count },
-  {"cleanup", 1, cleanup_pairs },
-  {0, 0, 0}
-};
-
-test_st hsieh_availability[] ={
-  {"hsieh_avaibility_test",0,hsieh_avaibility_test},
-  {0, 0, 0}
-};
-
-test_st ketama_auto_eject_hosts[] ={
-  {"auto_eject_hosts", 1, auto_eject_hosts },
-  {"output_ketama_weighted_keys", 1, output_ketama_weighted_keys },
-  {0, 0, 0}
-};
-
-test_st hash_tests[] ={
-  {"md5", 0, md5_run },
-  {"crc", 0, crc_run },
-  {"fnv1_64", 0, fnv1_64_run },
-  {"fnv1a_64", 0, fnv1a_64_run },
-  {"fnv1_32", 0, fnv1_32_run },
-  {"fnv1a_32", 0, fnv1a_32_run },
-  {"hsieh", 0, hsieh_run },
-  {"murmur", 0, murmur_run },
-  {"jenkis", 0, jenkins_run },
-  {0, 0, 0}
-};
-
-collection_st collection[] ={
-  {"hsieh_availability",0,0,hsieh_availability},
-  {"udp_setup", init_udp, 0, udp_setup_server_tests},
-  {"udp_io", init_udp, 0, upd_io_tests},
-  {"udp_binary_io", binary_init_udp, 0, upd_io_tests},
-  {"block", 0, 0, tests},
-  {"binary", pre_binary, 0, tests},
-  {"nonblock", pre_nonblock, 0, tests},
-  {"nodelay", pre_nodelay, 0, tests},
-  {"settimer", pre_settimer, 0, tests},
-  {"md5", pre_md5, 0, tests},
-  {"crc", pre_crc, 0, tests},
-  {"hsieh", pre_hsieh, 0, tests},
-  {"jenkins", pre_jenkins, 0, tests},
-  {"fnv1_64", pre_hash_fnv1_64, 0, tests},
-  {"fnv1a_64", pre_hash_fnv1a_64, 0, tests},
-  {"fnv1_32", pre_hash_fnv1_32, 0, tests},
-  {"fnv1a_32", pre_hash_fnv1a_32, 0, tests},
-  {"ketama", pre_behavior_ketama, 0, tests},
-  {"ketama_auto_eject_hosts", pre_behavior_ketama, 0, ketama_auto_eject_hosts},
-  {"unix_socket", pre_unix_socket, 0, tests},
-  {"unix_socket_nodelay", pre_nodelay, 0, tests},
-  {"poll_timeout", poll_timeout, 0, tests},
-  {"gets", enable_cas, 0, tests},
-  {"consistent", enable_consistent, 0, tests},
-#ifdef MEMCACHED_ENABLE_DEPRECATED
-  {"deprecated_memory_allocators", deprecated_set_memory_alloc, 0, tests},
-#endif
-  {"memory_allocators", set_memory_alloc, 0, tests},
-  {"prefix", set_prefix, 0, tests},
-  {"version_1_2_3", check_for_1_2_3, 0, version_1_2_3},
-  {"string", 0, 0, string_tests},
-  {"result", 0, 0, result_tests},
-  {"async", pre_nonblock, 0, async_tests},
-  {"async_binary", pre_nonblock_binary, 0, async_tests},
-  {"user", 0, 0, user_tests},
-  {"generate", 0, 0, generate_tests},
-  {"generate_hsieh", pre_hsieh, 0, generate_tests},
-  {"generate_ketama", pre_behavior_ketama, 0, generate_tests},
-  {"generate_hsieh_consistent", enable_consistent, 0, generate_tests},
-  {"generate_md5", pre_md5, 0, generate_tests},
-  {"generate_murmur", pre_murmur, 0, generate_tests},
-  {"generate_jenkins", pre_jenkins, 0, generate_tests},
-  {"generate_nonblock", pre_nonblock, 0, generate_tests},
-  {"consistent_not", 0, 0, consistent_tests},
-  {"consistent_ketama", pre_behavior_ketama, 0, consistent_tests},
-  {"consistent_ketama_weighted", pre_behavior_ketama_weighted, 0, consistent_weighted_tests},
-  {"ketama_compat", 0, 0, ketama_compatibility},
-  {"test_hashes", 0, 0, hash_tests},
-  {"replication", pre_replication, 0, replication_tests},
-  {"replication_noblock", pre_replication_noblock, 0, replication_tests},
-  {"regression", 0, 0, regression_tests},
-  {0, 0, 0, 0}
-};
-
-#define SERVERS_TO_CREATE 5
-
-/* Prototypes for functions we will pass to test framework */
-void *world_create(void);
-void world_destroy(void *p);
-
-void *world_create(void)
-{
-  server_startup_st *construct;
-
-  construct= calloc(sizeof(server_startup_st), 1);
-  construct->count= SERVERS_TO_CREATE;
-  construct->udp= 0;
-  server_startup(construct);
-
-  return construct;
-}
-
-
-void world_destroy(void *p)
-{
-  server_startup_st *construct= (server_startup_st *)p;
-  memcached_server_st *servers= (memcached_server_st *)construct->servers;
-  memcached_server_list_free(servers);
-
-  server_shutdown(construct);
-  free(construct);
-}
-
-void get_world(world_st *world)
-{
-  world->collections= collection;
-  world->create= world_create;
-  world->destroy= world_destroy;
-}
diff --git a/tests/hash_results.h b/tests/hash_results.h
new file mode 100644 (file)
index 0000000..da00e87
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+/**
+  @brief We list strings and results for testing different hashing algo in
+  this file.
+*/
+
+
+static const char *list_to_hash[]=
+{
+  "apple",
+  "beat",
+  "carrot",
+  "daikon",
+  "eggplant",
+  "flower",
+  "green",
+  "hide",
+  "ick",
+  "jack",
+  "kick",
+  "lime",
+  "mushrooms",
+  "nectarine",
+  "orange",
+  "peach",
+  "quant",
+  "ripen",
+  "strawberry",
+  "tang",
+  "up",
+  "volumne",
+  "when",
+  "yellow",
+  "zip",
+  NULL
+};
+
+static uint32_t md5_values[]= { 3195025439U, 2556848621U, 3724893440U, 3332385401U,
+                                245758794U, 2550894432U, 121710495U, 3053817768U,
+                                1250994555U, 1862072655U, 2631955953U, 2951528551U,
+                                1451250070U, 2820856945U, 2060845566U, 3646985608U,
+                                2138080750U, 217675895U, 2230934345U, 1234361223U,
+                                3968582726U, 2455685270U, 1293568479U, 199067604U,
+                                2042482093U };
+
+static uint32_t crc_values[]= { 10542U, 22009U, 14526U, 19510U, 19432U, 10199U, 20634U,
+                                9369U, 11511U, 10362U, 7893U, 31289U, 11313U, 9354U,
+                                7621U, 30628U, 15218U, 25967U, 2695U, 9380U,
+                                17300U, 28156U, 9192U, 20484U, 16925U };
+
+static uint32_t fnv1_64_values[]= { 473199127U, 4148981457U, 3971873300U, 3257986707U,
+                                    1722477987U, 2991193800U, 4147007314U, 3633179701U,
+                                    1805162104U, 3503289120U, 3395702895U, 3325073042U,
+                                    2345265314U, 3340346032U, 2722964135U, 1173398992U,
+                                    2815549194U, 2562818319U, 224996066U, 2680194749U,
+                                    3035305390U, 246890365U, 2395624193U, 4145193337U,
+                                    1801941682U };
+
+static uint32_t fnv1a_64_values[]= {  1488911807U, 2500855813U, 1510099634U, 1390325195U,
+                                      3647689787U, 3241528582U, 1669328060U, 2604311949U,
+                                      734810122U, 1516407546U, 560948863U, 1767346780U,
+                                      561034892U, 4156330026U, 3716417003U, 3475297030U,
+                                      1518272172U, 227211583U, 3938128828U, 126112909U,
+                                      3043416448U, 3131561933U, 1328739897U, 2455664041U,
+                                      2272238452U };
+
+static uint32_t fnv1_32_values[]= { 67176023U, 1190179409U, 2043204404U, 3221866419U,
+                                    2567703427U, 3787535528U, 4147287986U, 3500475733U,
+                                    344481048U, 3865235296U, 2181839183U, 119581266U,
+                                    510234242U, 4248244304U, 1362796839U, 103389328U,
+                                    1449620010U, 182962511U, 3554262370U, 3206747549U,
+                                    1551306158U, 4127558461U, 1889140833U, 2774173721U,
+                                    1180552018U };
+
+static uint32_t fnv1a_32_values[]= {  280767167U, 2421315013U, 3072375666U, 855001899U,
+                                      459261019U, 3521085446U, 18738364U, 1625305005U,
+                                      2162232970U, 777243802U, 3323728671U, 132336572U,
+                                      3654473228U, 260679466U, 1169454059U, 2698319462U,
+                                      1062177260U, 235516991U, 2218399068U, 405302637U,
+                                      1128467232U, 3579622413U, 2138539289U, 96429129U,
+                                      2877453236U };
+
+#ifdef HAVE_HSIEH_HASH
+static uint32_t hsieh_values[]= { 3738850110U, 3636226060U, 3821074029U, 3489929160U, 3485772682U, 80540287U,
+                                  1805464076U, 1895033657U, 409795758U, 979934958U, 3634096985U, 1284445480U,
+                                  2265380744U, 707972988U, 353823508U, 1549198350U, 1327930172U, 9304163U,
+                                  4220749037U, 2493964934U, 2777873870U, 2057831732U, 1510213931U, 2027828987U,
+                                  3395453351U };
+#else
+static uint32_t hsieh_values[]= {  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+#endif
+
+static uint32_t murmur_values[]= {  4142305122U, 734504955U, 3802834688U, 4076891445U,
+                                    387802650U, 560515427U, 3274673488U, 3150339524U,
+                                    1527441970U, 2728642900U, 3613992239U, 2938419259U,
+                                    2321988328U, 1145154116U, 4038540960U, 2224541613U,
+                                    264013145U, 3995512858U, 2400956718U, 2346666219U,
+                                    926327338U, 442757446U, 1770805201U, 560483147U,
+                                    3902279934U };
+
+static uint32_t jenkins_values[]= { 1442444624U, 4253821186U, 1885058256U, 2120131735U,
+                                    3261968576U, 3515188778U, 4232909173U, 4288625128U,
+                                    1812047395U, 3689182164U, 2502979932U, 1214050606U,
+                                    2415988847U, 1494268927U, 1025545760U, 3920481083U,
+                                    4153263658U, 3824871822U, 3072759809U, 798622255U,
+                                    3065432577U, 1453328165U, 2691550971U, 3408888387U,
+                                    2629893356U };
+
diff --git a/tests/hashkit_functions.c b/tests/hashkit_functions.c
new file mode 100644 (file)
index 0000000..2990b23
--- /dev/null
@@ -0,0 +1,387 @@
+/* libHashKit Functions Test
+ * 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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libhashkit/hashkit.h>
+
+#include "test.h"
+
+#include "hash_results.h"
+
+static hashkit_st global_hashk;
+
+/**
+  @brief hash_test_st is a structure we use in testing. It is currently empty.
+*/
+typedef struct hash_test_st hash_test_st;
+
+struct hash_test_st
+{
+  bool _unused;
+};
+
+static test_return_t init_test(void *not_used __attribute__((unused)))
+{
+  hashkit_st hashk;
+  hashkit_st *hashk_ptr;
+
+  hashk_ptr= hashkit_create(&hashk);
+  test_truth(hashk_ptr);
+  test_truth(hashk_ptr == &hashk);
+  test_truth(hashkit_is_initialized(&hashk) == true);
+  test_truth(hashkit_is_allocated(hashk_ptr) == false);
+
+  hashkit_free(hashk_ptr);
+
+  test_truth(hashkit_is_initialized(&hashk) == false);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t allocation_test(void *not_used __attribute__((unused)))
+{
+  hashkit_st *hashk_ptr;
+
+  hashk_ptr= hashkit_create(NULL);
+  test_truth(hashk_ptr);
+  test_truth(hashkit_is_allocated(hashk_ptr) == true);
+  test_truth(hashkit_is_initialized(hashk_ptr) == true);
+  hashkit_free(hashk_ptr);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t clone_test(hashkit_st *hashk)
+{
+  // First we make sure that the testing system is giving us what we expect.
+  assert(&global_hashk == hashk);
+
+  // Second we test if hashk is even valid
+  test_truth(hashkit_is_initialized(hashk) == true);
+
+  /* All null? */
+  {
+    hashkit_st *hashk_ptr;
+    hashk_ptr= hashkit_clone(NULL, NULL);
+    test_truth(hashk_ptr);
+    test_truth(hashkit_is_allocated(hashk_ptr) == true);
+    test_truth(hashkit_is_initialized(hashk_ptr) == true);
+    hashkit_free(hashk_ptr);
+  }
+
+  /* Can we init from null? */
+  {
+    hashkit_st *hashk_ptr;
+
+    hashk_ptr= hashkit_clone(NULL, hashk);
+
+    test_truth(hashk_ptr);
+    test_truth(hashkit_is_allocated(hashk_ptr) == true);
+    test_truth(hashkit_is_initialized(hashk_ptr) == true);
+
+    test_truth(hashk_ptr->distribution == hashk->distribution);
+    test_truth(hashk_ptr->continuum_count == hashk->continuum_count);
+    test_truth(hashk_ptr->continuum_points_count == hashk->continuum_points_count);
+    test_truth(hashk_ptr->list_size == hashk->list_size);
+    test_truth(hashk_ptr->context_size == hashk->context_size);
+    test_truth(hashk_ptr->continuum == NULL);
+    test_truth(hashk_ptr->hash_fn == hashk->hash_fn);
+    test_truth(hashk_ptr->active_fn == hashk->active_fn);
+    test_truth(hashk_ptr->continuum_hash_fn == hashk->continuum_hash_fn);
+    test_truth(hashk_ptr->continuum_key_fn == hashk->continuum_key_fn);
+    test_truth(hashk_ptr->sort_fn == hashk->sort_fn);
+    test_truth(hashk_ptr->weight_fn == hashk->weight_fn);
+    test_truth(hashk_ptr->list == hashk->list);
+
+    hashkit_free(hashk_ptr);
+  }
+
+  /* Can we init from struct? */
+  {
+    hashkit_st declared_clone;
+    hashkit_st *hash_clone;
+
+    hash_clone= hashkit_clone(&declared_clone, NULL);
+    test_truth(hash_clone);
+
+    hashkit_free(hash_clone);
+  }
+
+  /* Can we init from struct? */
+  {
+    hashkit_st declared_clone;
+    hashkit_st *hash_clone;
+    memset(&declared_clone, 0 , sizeof(hashkit_st));
+    hash_clone= hashkit_clone(&declared_clone, hashk);
+    test_truth(hash_clone);
+    hashkit_free(hash_clone);
+  }
+
+  return TEST_SUCCESS;
+}
+
+
+static test_return_t md5_run (hashkit_st *hashk __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= hashkit_md5(*ptr, strlen(*ptr));
+    test_truth(md5_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t crc_run (hashkit_st *hashk __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= hashkit_crc32(*ptr, strlen(*ptr));
+    assert(crc_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t fnv1_64_run (hashkit_st *hashk __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= hashkit_fnv1_64(*ptr, strlen(*ptr));
+    assert(fnv1_64_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t fnv1a_64_run (hashkit_st *hashk __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= hashkit_fnv1a_64(*ptr, strlen(*ptr));
+    assert(fnv1a_64_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t fnv1_32_run (hashkit_st *hashk __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= hashkit_fnv1_32(*ptr, strlen(*ptr));
+    assert(fnv1_32_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t fnv1a_32_run (hashkit_st *hashk __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= hashkit_fnv1a_32(*ptr, strlen(*ptr));
+    assert(fnv1a_32_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t hsieh_run (hashkit_st *hashk __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+#ifdef HAVE_HSIEH_HASH
+    hash_val= hashkit_hsieh(*ptr, strlen(*ptr));
+#else
+    hash_val= 1;
+#endif
+    assert(hsieh_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t murmur_run (hashkit_st *hashk __attribute__((unused)))
+{
+#ifdef __sparc
+  return TEST_SKIPPED;
+#else
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= hashkit_murmur(*ptr, strlen(*ptr));
+    assert(murmur_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+#endif
+}
+
+static test_return_t jenkins_run (hashkit_st *hashk __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= hashkit_jenkins(*ptr, strlen(*ptr));
+    assert(jenkins_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+
+
+
+/**
+  @brief now we list out the tests.
+*/
+
+test_st allocation[]= {
+  {"init", 0, (test_callback_fn)init_test},
+  {"create and free", 0, (test_callback_fn)allocation_test},
+  {"clone", 0, (test_callback_fn)clone_test},
+  {0, 0, 0}
+};
+
+test_st hash_tests[] ={
+  {"md5", 0, (test_callback_fn)md5_run },
+  {"crc", 0, (test_callback_fn)crc_run },
+  {"fnv1_64", 0, (test_callback_fn)fnv1_64_run },
+  {"fnv1a_64", 0, (test_callback_fn)fnv1a_64_run },
+  {"fnv1_32", 0, (test_callback_fn)fnv1_32_run },
+  {"fnv1a_32", 0, (test_callback_fn)fnv1a_32_run },
+  {"hsieh", 0, (test_callback_fn)hsieh_run },
+  {"murmur", 0, (test_callback_fn)murmur_run },
+  {"jenkis", 0, (test_callback_fn)jenkins_run },
+  {0, 0, (test_callback_fn)0}
+};
+
+/*
+ * The following test suite is used to verify that we don't introduce
+ * regression bugs. If you want more information about the bug / test,
+ * you should look in the bug report at
+ *   http://bugs.launchpad.net/libmemcached
+ */
+test_st regression[]= {
+  {0, 0, 0}
+};
+
+collection_st collection[] ={
+  {"allocation", 0, 0, allocation},
+  {"regression", 0, 0, regression},
+  {"hashing", 0, 0, hash_tests},
+  {0, 0, 0, 0}
+};
+
+/* Prototypes for functions we will pass to test framework */
+void *world_create(test_return_t *error);
+test_return_t world_destroy(hashkit_st *hashk);
+
+void *world_create(test_return_t *error)
+{
+  hashkit_st *hashk_ptr;
+
+  hashk_ptr= hashkit_create(&global_hashk);
+
+  if (hashk_ptr != &global_hashk)
+  {
+    *error= TEST_FAILURE;
+    return NULL;
+  }
+
+  // First we test if hashk is even valid
+  if (hashkit_is_initialized(hashk_ptr) == false)
+  {
+    *error= TEST_FAILURE;
+    return NULL;
+  }
+
+  if (hashkit_is_allocated(hashk_ptr) == true)
+  {
+    *error= TEST_FAILURE;
+    return NULL;
+  }
+
+  if (hashk_ptr->continuum != NULL)
+  {
+    *error= TEST_FAILURE;
+    return NULL;
+  }
+
+  *error= TEST_SUCCESS;
+
+  return hashk_ptr;
+}
+
+
+test_return_t world_destroy(hashkit_st *hashk)
+{
+  // Did we get back what we expected?
+  assert(hashkit_is_initialized(hashk) == true);
+  assert(hashkit_is_allocated(hashk) == false);
+  hashkit_free(&global_hashk);
+
+  return TEST_SUCCESS;
+}
+
+void get_world(world_st *world)
+{
+  world->collections= collection;
+  world->create= (test_callback_create_fn)world_create;
+  world->destroy= (test_callback_fn)world_destroy;
+}
diff --git a/tests/include.am b/tests/include.am
new file mode 100644 (file)
index 0000000..db6f23f
--- /dev/null
@@ -0,0 +1,275 @@
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+
+TESTS_LDADDS = libmemcached/libmemcached.la
+
+VALGRIND_COMMAND= $(LIBTOOL) --mode=execute valgrind --leak-check=yes --show-reachable=yes
+
+DEBUG_COMMAND= $(LIBTOOL) --mode=execute gdb
+
+if BUILD_LIBMEMCACHEDUTIL
+TESTS_LDADDS+= libmemcached/libmemcachedutil.la
+endif
+
+EXTRA_DIST+= \
+            tests/r/memcat.res \
+            tests/r/memcp.res \
+            tests/r/memrm.res \
+            tests/r/memslap.res \
+            tests/r/memstat.res \
+            tests/t/memcat.test \
+            tests/t/memcp.test \
+            tests/t/memrm.test \
+            tests/t/memslap.test \
+            tests/t/memstat.test
+
+noinst_HEADERS+= \
+                tests/hash_results.h \
+                tests/ketama_test_cases.h \
+                tests/ketama_test_cases_spy.h \
+                tests/libmemcached_world.h \
+                tests/server.h \
+                tests/test.h
+
+noinst_PROGRAMS+= \
+                 tests/atomsmasher \
+                 tests/startservers \
+                 tests/testapp \
+                 tests/testhashkit \
+                 tests/testplus
+
+noinst_LTLIBRARIES+= tests/libserver.la
+tests_libserver_la_SOURCES= tests/server.c
+
+noinst_LTLIBRARIES+= tests/libtest.la
+tests_libtest_la_SOURCES= tests/test.c
+
+tests_testapp_CFLAGS= $(AM_CFLAGS) $(NO_CONVERSION) $(NO_STRICT_ALIASING)
+tests_testapp_SOURCES= tests/mem_functions.c
+tests_testapp_LDADD= \
+       clients/libgenexec.la \
+       tests/libserver.la \
+       tests/libtest.la \
+       libmemcached/libmemcachedinternal.la \
+       $(TESTS_LDADDS)
+tests_testapp_DEPENDENCIES= $(tests_testapp_LDADD)
+
+tests_testplus_SOURCES= tests/plus.cpp
+tests_testplus_LDADD= tests/libtest.la tests/libserver.la $(TESTS_LDADDS)
+tests_testplus_DEPENDENCIES= $(tests_testplus_LDADD)
+
+tests_atomsmasher_SOURCES= tests/atomsmasher.c
+tests_atomsmasher_LDADD= \
+       clients/libgenexec.la \
+       tests/libserver.la \
+       tests/libtest.la \
+       $(TESTS_LDADDS)
+tests_atomsmasher_DEPENDENCIES= $(tests_atomsmasher_LDADD)
+
+tests_startservers_SOURCES= tests/start.c
+tests_startservers_LDADD= tests/libserver.la $(TESTS_LDADDS)
+tests_startservers_DEPENDENCIES= $(tests_startservers_LDADD)
+
+tests_testhashkit_SOURCES = tests/hashkit_functions.c
+tests_testhashkit_LDADD = tests/libtest.la libhashkit/libhashkit.la
+tests_testhashkit_DEPENDENCIES = $(tests_testhashkit_LDADD)
+
+test: test-docs test-plus test-mem test-hash memcapable test-memcat test-memcp test-memrm test-memerror test-memdump test-memflush test-memstat
+       echo "Tests completed"
+
+memcapable: clients/memcapable
+       @@MEMC_BINARY@ -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @clients/memcapable -p 12555 || echo "Your memcached server does not support all commands"
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+
+test-memcat: clients/memcat clients/memcp
+       @echo "Testing memcat"
+       @@MEMC_BINARY@ -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @clients/memcp --servers="localhost:12555" clients/memcp
+       @clients/memcat --servers="localhost:12555" memcp > tests/scratch
+#      @diff clients/memcp tests/scratch
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+       @rm tests/scratch
+
+valgrind-memcat: clients/memcat clients/memcp
+       @echo "Testing memcat"
+       @@MEMC_BINARY@ -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @clients/memcp --servers="localhost:12555" clients/memcp
+       @$(VALGRIND_COMMAND) clients/memcat --servers="localhost:12555" memcp > tests/scratch
+#      @diff clients/memcp tests/scratch
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+       @rm tests/scratch
+
+test-memcp: clients/memcp
+       @echo "Testing memcp"
+       @@MEMC_BINARY@ -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @clients/memcp --servers="localhost:12555" clients/memcp clients/memcat clients/memstat
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+
+valgrind-memcp: clients/memcat clients/memcp
+       @echo "Testing memcp"
+       @@MEMC_BINARY@ -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @$(VALGRIND_COMMAND) clients/memcp --servers="localhost:12555" clients/memcp clients/memcat clients/memstat
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+
+test-memrm: clients/memrm clients/memcp
+       @echo "Testing memrm"
+       @@MEMC_BINARY@ -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @clients/memcp --servers="localhost:12555" clients/memcat
+       @clients/memrm --servers="localhost:12555" memcat
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+
+valgrind-memrm: clients/memcat clients/memcp
+       @echo "Testing memrm"
+       @@MEMC_BINARY@ -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @clients/memcp --servers="localhost:12555" clients/memcat
+       @$(VALGRIND_COMMAND) clients/memrm --servers="localhost:12555" memcat
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+
+test-memflush: clients/memflush
+       @echo "Testing memflush"
+       @/usr/local/bin/memcached -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @clients/memflush --servers="localhost:12555"
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+
+valgrind-memflush: clients/memflush
+       @echo "Testing memflush"
+       @/usr/local/bin/memcached -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @$(VALGRIND_COMMAND) clients/memflush --servers="localhost:12555"
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+
+test-memdump: clients/memdump clients/memcp
+       @echo "Testing memdump"
+       @/usr/local/bin/memcached -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @clients/memcp --servers="localhost:12555" clients/memcat
+       @clients/memdump --servers="localhost:12555" > /dev/null
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+
+valgrind-memdump: clients/memcat clients/memcp
+       @echo "Testing memdump"
+       @/usr/local/bin/memcached -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @clients/memcp --servers="localhost:12555" clients/memcat
+       @$(VALGRIND_COMMAND) clients/memdump --servers="localhost:12555" > /dev/null
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+
+test-memstat: clients/memstat
+       @echo "Testing memstat"
+       @/usr/local/bin/memcached -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @clients/memstat --servers="localhost:12555" > /dev/null
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+
+valgrind-memstat: clients/memstat
+       @echo "Testing memstat"
+       @/usr/local/bin/memcached -d -P `pwd`/tests/Xumemc.pid -p 12555
+       @$(VALGRIND_COMMAND) clients/memstat --servers="localhost:12555" > /dev/null
+       @cat tests/Xumemc.pid | xargs kill || echo "Failed to kill memcached server"
+       @rm tests/Xumemc.pid
+
+test-memerror: clients/memerror
+       @echo "Testing memerror"
+       @clients/memerror 0 > /dev/null
+
+valgrind-memerror: clients/memerror
+       @echo "Testing memerror"
+       @$(VALGRIND_COMMAND) clients/memerror 0 > /dev/null
+
+
+
+
+
+MEMSLAP_COMMAND= clients/memslap $(COLLECTION) $(SUITE)
+
+MEM_COMMAND= tests/testapp $(COLLECTION) $(SUITE)
+
+PLUS_COMMAND= tests/testplus $(COLLECTION) $(SUITE)
+
+ATOM_COMMAND= tests/atomsmasher $(COLLECTION) $(SUITE)
+
+HASH_COMMAND= tests/testhashkit $(COLLECTION) $(SUITE)
+
+test-mem: tests/testapp
+       $(MEM_COMMAND)
+
+test-atom: tests/atomsmasher
+       $(ATOM_COMMAND)
+
+test-plus: tests/testplus
+       $(PLUS_COMMAND)
+
+test-hash: tests/testhashkit
+       $(HASH_COMMAND)
+
+gdb-mem: tests/testapp
+       $(DEBUG_COMMAND)  $(MEM_COMMAND)
+
+gdb-atom: tests/atomsmasher
+       $(DEBUG_COMMAND)  $(ATOM_COMMAND)
+
+gdb-plus: tests/testplus
+       $(DEBUG_COMMAND)  $(PLUS_COMMAND)
+
+gdb-hash: tests/testhashkit
+       $(DEBUG_COMMAND) $(HASH_COMMAND)
+
+gdb-memslap: clients/memslap
+       $(DEBUG_COMMAND)  $(MEMSLAP_COMMAND)
+
+valgrind-mem: tests/testapp
+       $(VALGRIND_COMMAND)  $(MEM_COMMAND)
+
+valgrind-atom: tests/atomsmasher
+       $(VALGRIND_COMMAND)  $(ATOM_COMMAND)
+
+valgrind-plus: tests/testplus
+       $(VALGRIND_COMMAND)  $(PLUS_COMMAND)
+
+valgrind-hash: tests/testhashkit
+       $(VALGRIND_COMMAND) $(HASH_COMMAND)
+
+valgrind-memslap: clients/memslap
+       $(VALGRIND_COMMAND) $(MEMSLAP_COMMAND)
+
+PHONY += valgrind
+valgrind: tests/testapp tests/testhashkit valgrind-mem valgrind-hash valgrind-memcat valgrind-memcp valgrind-memrm valgrind-memerror valgrind-memdump valgrind-memflush valgrind-memstat
+
+PHONY += cachegrind
+CLEANFILES += tests/cachegrind.out
+cachegrind:
+       rm -f tests/cachegrind.out.*
+       $(LIBTOOL) --mode=execute valgrind --tool=cachegrind --cachegrind-out-file=tests/cachegrind.out.%p --branch-sim=yes tests/testapp
+       cg_annotate tests/cachegrind.out.* --auto=yes > tests/cachegrind.out
+
+PHONY += callgrind
+CLEANFILES += tests/callgrind.out
+callgrind:
+       rm -f tests/callgrind.out.*
+       $(LIBTOOL) --mode=execute valgrind --tool=callgrind --callgrind-out-file=tests/callgrind.out.%p  tests/testapp
+       callgrind_annotate tests/callgrind.out.* --auto=yes > tests/callgrind.out
+
+PHONY += helgrind
+CLEANFILES+= helgrind.out.*
+helgrind:
+       rm -f helgrind.out.*
+       $(LIBTOOL) --mode=execute valgrind --tool=helgrind  tests/testapp
+
+PHONY += helgrind-slap
+helgrind-slap:
+       $(LIBTOOL) --mode=execute valgrind --tool=helgrind  clients/memslap --server=localhost --concurrency=30
+
+test-no-outputdiff: test
+
+hudson-valgrind: tests/testapp
+       $(VALGRIND_COMMAND) --log-file=tests/valgrind.out $(MEM_COMMAND)
index 3d770f169773f4f977ff27c9484c6f63da946e8c..b01d1ab23cf43d5fcc935fea1a029063d16c9b36 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * 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.
+ */
+
 #ifndef TESTS_KETAMA_TEST_CASES_H
 #define TESTS_KETAMA_TEST_CASES_H
 
index 5e6a9378b918cb2f7ef524d91abf1df8424f2589..b9c0a96eeba7dfaf0a7b459c850a210c94f00ca8 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * 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.
+ */
+
 #ifndef TESTS_KETAMA_TEST_CASES_SPY_H
 #define TESTS_KETAMA_TEST_CASES_SPY_H
 
diff --git a/tests/libmemcached_world.h b/tests/libmemcached_world.h
new file mode 100644 (file)
index 0000000..aab09ea
--- /dev/null
@@ -0,0 +1,172 @@
+/* libMemcached Functions Test
+ * 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.
+ *
+ * Description: This is the startup bits for any libmemcached test.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The structure we use for the test system */
+typedef struct
+{
+  server_startup_st construct;
+  memcached_st *parent;
+  memcached_st *memc;
+} libmemcached_test_container_st;
+
+/* Prototypes for functions we will pass to test framework */
+libmemcached_test_container_st *world_create(test_return_t *error);
+test_return_t world_test_startup(libmemcached_test_container_st *);
+test_return_t world_flush(libmemcached_test_container_st *container);
+test_return_t world_pre_run(libmemcached_test_container_st *);
+
+test_return_t world_post_run(libmemcached_test_container_st *);
+test_return_t world_on_error(test_return_t, libmemcached_test_container_st *);
+test_return_t world_destroy(libmemcached_test_container_st *);
+
+static libmemcached_test_container_st global_container;
+
+/**
+  @note generic shutdown/startup for libmemcached tests.
+*/
+test_return_t world_container_startup(libmemcached_test_container_st *container);
+test_return_t world_container_shutdown(libmemcached_test_container_st *container);
+
+libmemcached_test_container_st *world_create(test_return_t *error)
+{
+  memset(&global_container, 0, sizeof(global_container));
+  global_container.construct.count= SERVERS_TO_CREATE;
+  global_container.construct.udp= 0;
+  server_startup(&global_container.construct);
+
+  if (! global_container.construct.servers)
+  {
+    *error= TEST_FAILURE;
+    server_shutdown(&global_container.construct);
+    return NULL;
+  }
+
+  *error= TEST_SUCCESS;
+
+  return &global_container;
+}
+
+test_return_t world_container_startup(libmemcached_test_container_st *container)
+{
+  memcached_return_t rc;
+  container->parent= memcached_create(NULL);
+  test_truth((container->parent != NULL));
+
+  rc= memcached_server_push(container->parent, container->construct.servers);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  return TEST_SUCCESS;
+}
+
+test_return_t world_container_shutdown(libmemcached_test_container_st *container)
+{
+  memcached_free(container->parent);
+  container->parent= NULL;
+
+  return TEST_SUCCESS;
+}
+
+test_return_t world_test_startup(libmemcached_test_container_st *container)
+{
+  container->memc= memcached_clone(NULL, container->parent);
+  test_truth((container->memc != NULL));
+
+  return TEST_SUCCESS;
+}
+
+test_return_t world_flush(libmemcached_test_container_st *container)
+{
+  memcached_flush(container->memc, 0);
+  memcached_quit(container->memc);
+
+  return TEST_SUCCESS;
+}
+
+test_return_t world_pre_run(libmemcached_test_container_st *container)
+{
+  for (uint32_t loop= 0; loop < memcached_server_list_count(container->construct.servers); loop++)
+  {
+    memcached_server_st *instance=
+      memcached_server_instance_fetch(container->memc, loop);
+
+    test_truth(instance->fd == -1);
+    test_truth(instance->cursor_active == 0);
+  }
+
+  return TEST_SUCCESS;
+}
+
+
+test_return_t world_post_run(libmemcached_test_container_st *container)
+{
+  test_truth(container->memc);
+
+  return TEST_SUCCESS;
+}
+
+test_return_t world_on_error(test_return_t test_state, libmemcached_test_container_st *container)
+{
+  (void)test_state;
+  memcached_free(container->memc);
+  container->memc= NULL;
+
+  return TEST_SUCCESS;
+}
+
+test_return_t world_destroy(libmemcached_test_container_st *container)
+{
+  server_startup_st *construct= &container->construct;
+  memcached_server_st *servers= container->construct.servers;
+  memcached_server_list_free(servers);
+
+  server_shutdown(construct);
+
+  return TEST_SUCCESS;
+}
+
+typedef test_return_t (*libmemcached_test_callback_fn)(memcached_st *);
+static test_return_t _runner_default(libmemcached_test_callback_fn func, libmemcached_test_container_st *container)
+{
+  if (func)
+  {
+    return func(container->memc);
+  }
+  else
+  {
+    return TEST_SUCCESS;
+  }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+
+static world_runner_st defualt_libmemcached_runner= {
+  reinterpret_cast<test_callback_runner_fn>(_runner_default),
+  reinterpret_cast<test_callback_runner_fn>(_runner_default),
+  reinterpret_cast<test_callback_runner_fn>(_runner_default)
+};
+
+#else
+
+static world_runner_st defualt_libmemcached_runner= {
+  (test_callback_runner_fn)_runner_default,
+  (test_callback_runner_fn)_runner_default,
+  (test_callback_runner_fn)_runner_default
+};
+
+#endif
diff --git a/tests/mem_functions.c b/tests/mem_functions.c
new file mode 100644 (file)
index 0000000..3b545c8
--- /dev/null
@@ -0,0 +1,6063 @@
+/* libMemcached Functions Test
+ * 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.
+ */
+
+/*
+  Sample test application.
+*/
+
+#include "libmemcached/common.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <unistd.h>
+#include <time.h>
+#include "server.h"
+#include "clients/generator.h"
+#include "clients/execute.h"
+
+#ifndef INT64_MAX
+#define INT64_MAX LONG_MAX
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX INT_MAX
+#endif
+
+
+#include "test.h"
+
+#ifdef HAVE_LIBMEMCACHEDUTIL
+#include <pthread.h>
+#include "libmemcached/memcached_util.h"
+#endif
+
+#include "hash_results.h"
+
+#define GLOBAL_COUNT 10000
+#define GLOBAL2_COUNT 100
+#define SERVERS_TO_CREATE 5
+static uint32_t global_count;
+
+static pairs_st *global_pairs;
+static const char *global_keys[GLOBAL_COUNT];
+static size_t global_keys_length[GLOBAL_COUNT];
+
+static test_return_t  init_test(memcached_st *not_used __attribute__((unused)))
+{
+  memcached_st memc;
+
+  (void)memcached_create(&memc);
+  memcached_free(&memc);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  server_list_null_test(memcached_st *ptr __attribute__((unused)))
+{
+  memcached_server_st *server_list;
+  memcached_return_t rc;
+
+  server_list= memcached_server_list_append_with_weight(NULL, NULL, 0, 0, NULL);
+  test_truth(server_list == NULL);
+
+  server_list= memcached_server_list_append_with_weight(NULL, "localhost", 0, 0, NULL);
+  test_truth(server_list == NULL);
+
+  server_list= memcached_server_list_append_with_weight(NULL, NULL, 0, 0, &rc);
+  test_truth(server_list == NULL);
+
+  return TEST_SUCCESS;
+}
+
+#define TEST_PORT_COUNT 7
+in_port_t test_ports[TEST_PORT_COUNT];
+
+static memcached_return_t  server_display_function(memcached_st *ptr __attribute__((unused)), memcached_server_st *server, void *context)
+{
+  /* Do Nothing */
+  size_t bigger= *((size_t *)(context));
+  assert(bigger <= server->port);
+  *((size_t *)(context))= server->port;
+
+  return MEMCACHED_SUCCESS;
+}
+
+static test_return_t  server_sort_test(memcached_st *ptr __attribute__((unused)))
+{
+  size_t bigger= 0; /* Prime the value for the test_truth in server_display_function */
+
+  memcached_return_t rc;
+  memcached_server_fn callbacks[1];
+  memcached_st *local_memc;
+
+  local_memc= memcached_create(NULL);
+  test_truth(local_memc);
+  memcached_behavior_set(local_memc, MEMCACHED_BEHAVIOR_SORT_HOSTS, 1);
+
+  for (size_t x= 0; x < TEST_PORT_COUNT; x++)
+  {
+    test_ports[x]= (in_port_t)random() % 64000;
+    rc= memcached_server_add_with_weight(local_memc, "localhost", test_ports[x], 0);
+    test_truth(memcached_server_count(local_memc) == x + 1);
+    test_truth(memcached_servers_count(memcached_server_list(local_memc)) == x+1);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  callbacks[0]= server_display_function;
+  memcached_server_cursor(local_memc, callbacks, (void *)&bigger,  1);
+
+
+  memcached_free(local_memc);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  server_sort2_test(memcached_st *ptr __attribute__((unused)))
+{
+  size_t bigger= 0; /* Prime the value for the test_truth in server_display_function */
+  memcached_return_t rc;
+  memcached_server_fn callbacks[1];
+  memcached_st *local_memc;
+  memcached_server_instance_st *instance;
+
+  local_memc= memcached_create(NULL);
+  test_truth(local_memc);
+  rc= memcached_behavior_set(local_memc, MEMCACHED_BEHAVIOR_SORT_HOSTS, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_server_add_with_weight(local_memc, "MEMCACHED_BEHAVIOR_SORT_HOSTS", 43043, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  instance= memcached_server_instance_fetch(local_memc, 0);
+  test_truth(instance->port == 43043);
+
+  rc= memcached_server_add_with_weight(local_memc, "MEMCACHED_BEHAVIOR_SORT_HOSTS", 43042, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  instance= memcached_server_instance_fetch(local_memc, 0);
+  test_truth(instance->port == 43042);
+
+  instance= memcached_server_instance_fetch(local_memc, 1);
+  test_truth(instance->port == 43043);
+
+  callbacks[0]= server_display_function;
+  memcached_server_cursor(local_memc, callbacks, (void *)&bigger,  1);
+
+
+  memcached_free(local_memc);
+
+  return TEST_SUCCESS;
+}
+
+static memcached_return_t server_display_unsort_function(memcached_st *ptr __attribute__((unused)), memcached_server_st *server, void *context)
+{
+  /* Do Nothing */
+  uint32_t x= *((uint32_t *)(context));
+
+  assert(test_ports[x] == server->port);
+  *((uint32_t *)(context))= ++x;
+
+  return MEMCACHED_SUCCESS;
+}
+
+static test_return_t  server_unsort_test(memcached_st *ptr __attribute__((unused)))
+{
+  size_t counter= 0; /* Prime the value for the test_truth in server_display_function */
+  size_t bigger= 0; /* Prime the value for the test_truth in server_display_function */
+  memcached_return_t rc;
+  memcached_server_fn callbacks[1];
+  memcached_st *local_memc;
+
+  local_memc= memcached_create(NULL);
+  test_truth(local_memc);
+
+  for (size_t x= 0; x < TEST_PORT_COUNT; x++)
+  {
+    test_ports[x]= (in_port_t)(random() % 64000);
+    rc= memcached_server_add_with_weight(local_memc, "localhost", test_ports[x], 0);
+    test_truth(memcached_server_count(local_memc) == x+1);
+    test_truth(memcached_servers_count(memcached_server_list(local_memc)) == x+1);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  callbacks[0]= server_display_unsort_function;
+  memcached_server_cursor(local_memc, callbacks, (void *)&counter,  1);
+
+  /* Now we sort old data! */
+  memcached_behavior_set(local_memc, MEMCACHED_BEHAVIOR_SORT_HOSTS, 1);
+  callbacks[0]= server_display_function;
+  memcached_server_cursor(local_memc, callbacks, (void *)&bigger,  1);
+
+
+  memcached_free(local_memc);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  allocation_test(memcached_st *not_used __attribute__((unused)))
+{
+  memcached_st *memc;
+  memc= memcached_create(NULL);
+  test_truth(memc);
+  memcached_free(memc);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  clone_test(memcached_st *memc)
+{
+  /* All null? */
+  {
+    memcached_st *memc_clone;
+    memc_clone= memcached_clone(NULL, NULL);
+    test_truth(memc_clone);
+    memcached_free(memc_clone);
+  }
+
+  /* Can we init from null? */
+  {
+    memcached_st *memc_clone;
+    memc_clone= memcached_clone(NULL, memc);
+    test_truth(memc_clone);
+
+    test_truth(memc_clone->call_free == memc->call_free);
+    test_truth(memc_clone->call_malloc == memc->call_malloc);
+    test_truth(memc_clone->call_realloc == memc->call_realloc);
+    test_truth(memc_clone->call_calloc == memc->call_calloc);
+    test_truth(memc_clone->connect_timeout == memc->connect_timeout);
+    test_truth(memc_clone->delete_trigger == memc->delete_trigger);
+    test_truth(memc_clone->distribution == memc->distribution);
+    { // Test all of the flags
+      test_truth(memc_clone->flags.no_block == memc->flags.no_block);
+      test_truth(memc_clone->flags.tcp_nodelay == memc->flags.tcp_nodelay);
+      test_truth(memc_clone->flags.reuse_memory == memc->flags.reuse_memory);
+      test_truth(memc_clone->flags.use_cache_lookups == memc->flags.use_cache_lookups);
+      test_truth(memc_clone->flags.support_cas == memc->flags.support_cas);
+      test_truth(memc_clone->flags.buffer_requests == memc->flags.buffer_requests);
+      test_truth(memc_clone->flags.use_sort_hosts == memc->flags.use_sort_hosts);
+      test_truth(memc_clone->flags.verify_key == memc->flags.verify_key);
+      test_truth(memc_clone->flags.ketama_weighted == memc->flags.ketama_weighted);
+      test_truth(memc_clone->flags.binary_protocol == memc->flags.binary_protocol);
+      test_truth(memc_clone->flags.hash_with_prefix_key == memc->flags.hash_with_prefix_key);
+      test_truth(memc_clone->flags.no_reply == memc->flags.no_reply);
+      test_truth(memc_clone->flags.use_udp == memc->flags.use_udp);
+      test_truth(memc_clone->flags.auto_eject_hosts == memc->flags.auto_eject_hosts);
+      test_truth(memc_clone->flags.randomize_replica_read == memc->flags.randomize_replica_read);
+    }
+    test_truth(memc_clone->get_key_failure == memc->get_key_failure);
+    test_truth(memc_clone->hash == memc->hash);
+    test_truth(memc_clone->distribution_hash == memc->distribution_hash);
+    test_truth(memc_clone->io_bytes_watermark == memc->io_bytes_watermark);
+    test_truth(memc_clone->io_msg_watermark == memc->io_msg_watermark);
+    test_truth(memc_clone->io_key_prefetch == memc->io_key_prefetch);
+    test_truth(memc_clone->on_cleanup == memc->on_cleanup);
+    test_truth(memc_clone->on_clone == memc->on_clone);
+    test_truth(memc_clone->poll_timeout == memc->poll_timeout);
+    test_truth(memc_clone->rcv_timeout == memc->rcv_timeout);
+    test_truth(memc_clone->recv_size == memc->recv_size);
+    test_truth(memc_clone->retry_timeout == memc->retry_timeout);
+    test_truth(memc_clone->send_size == memc->send_size);
+    test_truth(memc_clone->server_failure_limit == memc->server_failure_limit);
+    test_truth(memc_clone->snd_timeout == memc->snd_timeout);
+    test_truth(memc_clone->user_data == memc->user_data);
+
+    memcached_free(memc_clone);
+  }
+
+  /* Can we init from struct? */
+  {
+    memcached_st declared_clone;
+    memcached_st *memc_clone;
+    memset(&declared_clone, 0 , sizeof(memcached_st));
+    memc_clone= memcached_clone(&declared_clone, NULL);
+    test_truth(memc_clone);
+    memcached_free(memc_clone);
+  }
+
+  /* Can we init from struct? */
+  {
+    memcached_st declared_clone;
+    memcached_st *memc_clone;
+    memset(&declared_clone, 0 , sizeof(memcached_st));
+    memc_clone= memcached_clone(&declared_clone, memc);
+    test_truth(memc_clone);
+    memcached_free(memc_clone);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t userdata_test(memcached_st *memc)
+{
+  void* foo= NULL;
+  test_truth(memcached_set_user_data(memc, foo) == NULL);
+  test_truth(memcached_get_user_data(memc) == foo);
+  test_truth(memcached_set_user_data(memc, NULL) == foo);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  connection_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+
+  rc= memcached_server_add_with_weight(memc, "localhost", 0, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  error_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  uint32_t values[] = { 851992627U, 2337886783U, 3196981036U, 4001849190U,
+                        982370485U, 1263635348U, 4242906218U, 3829656100U,
+                        1891735253U, 334139633U, 2257084983U, 3088286104U,
+                        13199785U, 2542027183U, 1097051614U, 199566778U,
+                        2748246961U, 2465192557U, 1664094137U, 2405439045U,
+                        1842224848U, 692413798U, 3479807801U, 919913813U,
+                        4269430871U, 610793021U, 527273862U, 1437122909U,
+                        2300930706U, 2943759320U, 674306647U, 2400528935U,
+                        54481931U, 4186304426U, 1741088401U, 2979625118U,
+                        4159057246U, 3425930182U, 2593724503U};
+
+  // You have updated the memcache_error messages but not updated docs/tests.
+  test_truth(MEMCACHED_MAXIMUM_RETURN == 39);
+  for (rc= MEMCACHED_SUCCESS; rc < MEMCACHED_MAXIMUM_RETURN; rc++)
+  {
+    uint32_t hash_val;
+    const char *msg=  memcached_strerror(memc, rc);
+    hash_val= memcached_generate_hash_value(msg, strlen(msg),
+                                            MEMCACHED_HASH_JENKINS);
+    test_truth(values[rc] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  set_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo";
+  const char *value= "when we sanitize";
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  append_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "fig";
+  const char *in_value= "we";
+  char *out_value= NULL;
+  size_t value_length;
+  uint32_t flags;
+
+  rc= memcached_flush(memc, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_set(memc, key, strlen(key),
+                    in_value, strlen(in_value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_append(memc, key, strlen(key),
+                       " the", strlen(" the"),
+                       (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_append(memc, key, strlen(key),
+                       " people", strlen(" people"),
+                       (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  out_value= memcached_get(memc, key, strlen(key),
+                       &value_length, &flags, &rc);
+  test_truth(!memcmp(out_value, "we the people", strlen("we the people")));
+  test_truth(strlen("we the people") == value_length);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  free(out_value);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  append_binary_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "numbers";
+  uint32_t store_list[] = { 23, 56, 499, 98, 32847, 0 };
+  uint32_t *value;
+  size_t value_length;
+  uint32_t flags;
+  uint32_t x;
+
+  rc= memcached_flush(memc, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_set(memc,
+                    key, strlen(key),
+                    NULL, 0,
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  for (x= 0; store_list[x] ; x++)
+  {
+    rc= memcached_append(memc,
+                         key, strlen(key),
+                         (char *)&store_list[x], sizeof(uint32_t),
+                         (time_t)0, (uint32_t)0);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  value= (uint32_t *)memcached_get(memc, key, strlen(key),
+                       &value_length, &flags, &rc);
+  test_truth((value_length == (sizeof(uint32_t) * x)));
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  for (uint32_t counter= x, *ptr= value; counter; counter--)
+  {
+    test_truth(*ptr == store_list[x - counter]);
+    ptr++;
+  }
+  free(value);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  cas2_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *keys[]= {"fudge", "son", "food"};
+  size_t key_length[]= {5, 3, 4};
+  const char *value= "we the people";
+  size_t value_length= strlen("we the people");
+  unsigned int x;
+  memcached_result_st results_obj;
+  memcached_result_st *results;
+  unsigned int set= 1;
+
+  rc= memcached_flush(memc, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, set);
+
+  for (x= 0; x < 3; x++)
+  {
+    rc= memcached_set(memc, keys[x], key_length[x],
+                      keys[x], key_length[x],
+                      (time_t)50, (uint32_t)9);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  rc= memcached_mget(memc, keys, key_length, 3);
+
+  results= memcached_result_create(memc, &results_obj);
+
+  results= memcached_fetch_result(memc, &results_obj, &rc);
+  test_truth(results);
+  test_truth(results->cas);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(memcached_result_cas(results));
+
+  test_truth(!memcmp(value, "we the people", strlen("we the people")));
+  test_truth(strlen("we the people") == value_length);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  memcached_result_free(&results_obj);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  cas_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "fun";
+  size_t key_length= strlen(key);
+  const char *value= "we the people";
+  const char* keys[2] = { key, NULL };
+  size_t keylengths[2] = { strlen(key), 0 };
+  size_t value_length= strlen(value);
+  const char *value2= "change the value";
+  size_t value2_length= strlen(value2);
+
+  memcached_result_st results_obj;
+  memcached_result_st *results;
+  unsigned int set= 1;
+
+  rc= memcached_flush(memc, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, set);
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_mget(memc, keys, keylengths, 1);
+
+  results= memcached_result_create(memc, &results_obj);
+
+  results= memcached_fetch_result(memc, &results_obj, &rc);
+  test_truth(results);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(memcached_result_cas(results));
+  test_truth(!memcmp(value, memcached_result_value(results), value_length));
+  test_truth(strlen(memcached_result_value(results)) == value_length);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  uint64_t cas = memcached_result_cas(results);
+
+  #if 0
+  results= memcached_fetch_result(memc, &results_obj, &rc);
+  test_truth(rc == MEMCACHED_END);
+  test_truth(results == NULL);
+#endif
+
+  rc= memcached_cas(memc, key, key_length, value2, value2_length, 0, 0, cas);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  /*
+   * The item will have a new cas value, so try to set it again with the old
+   * value. This should fail!
+   */
+  rc= memcached_cas(memc, key, key_length, value2, value2_length, 0, 0, cas);
+  test_truth(rc == MEMCACHED_DATA_EXISTS);
+
+  memcached_result_free(&results_obj);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  prepend_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "fig";
+  const char *value= "people";
+  char *out_value= NULL;
+  size_t value_length;
+  uint32_t flags;
+
+  rc= memcached_flush(memc, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_prepend(memc, key, strlen(key),
+                       "the ", strlen("the "),
+                       (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_prepend(memc, key, strlen(key),
+                       "we ", strlen("we "),
+                       (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  out_value= memcached_get(memc, key, strlen(key),
+                       &value_length, &flags, &rc);
+  test_truth(!memcmp(out_value, "we the people", strlen("we the people")));
+  test_truth(strlen("we the people") == value_length);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  free(out_value);
+
+  return TEST_SUCCESS;
+}
+
+/*
+  Set the value, then quit to make sure it is flushed.
+  Come back in and test that add fails.
+*/
+static test_return_t  add_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo";
+  const char *value= "when we sanitize";
+  unsigned long long setting_value;
+
+  setting_value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK);
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  memcached_quit(memc);
+  rc= memcached_add(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+
+  /* Too many broken OS'es have broken loopback in async, so we can't be sure of the result */
+  if (setting_value)
+  {
+    test_truth(rc == MEMCACHED_NOTSTORED || rc == MEMCACHED_STORED);
+  }
+  else
+  {
+    test_truth(rc == MEMCACHED_NOTSTORED || rc == MEMCACHED_DATA_EXISTS);
+  }
+
+  return TEST_SUCCESS;
+}
+
+/*
+** There was a problem of leaking filedescriptors in the initial release
+** of MacOSX 10.5. This test case triggers the problem. On some Solaris
+** systems it seems that the kernel is slow on reclaiming the resources
+** because the connects starts to time out (the test doesn't do much
+** anyway, so just loop 10 iterations)
+*/
+static test_return_t  add_wrapper(memcached_st *memc)
+{
+  unsigned int x;
+  unsigned int max= 10000;
+#ifdef __sun
+  max= 10;
+#endif
+#ifdef __APPLE__
+  max= 10;
+#endif
+
+  for (x= 0; x < max; x++)
+    add_test(memc);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  replace_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo";
+  const char *value= "when we sanitize";
+  const char *original= "first we insert some data";
+
+  rc= memcached_set(memc, key, strlen(key),
+                    original, strlen(original),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  rc= memcached_replace(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  delete_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo";
+  const char *value= "when we sanitize";
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  rc= memcached_delete(memc, key, strlen(key), (time_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  flush_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+
+  rc= memcached_flush(memc, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  return TEST_SUCCESS;
+}
+
+static memcached_return_t  server_function(memcached_st *ptr __attribute__((unused)),
+                                           memcached_server_st *server __attribute__((unused)),
+                                           void *context __attribute__((unused)))
+{
+  /* Do Nothing */
+
+  return MEMCACHED_SUCCESS;
+}
+
+static test_return_t  memcached_server_cursor_test(memcached_st *memc)
+{
+  char context[8];
+  strcpy(context, "foo bad");
+  memcached_server_fn callbacks[1];
+
+  callbacks[0]= server_function;
+  memcached_server_cursor(memc, callbacks, context,  1);
+  return TEST_SUCCESS;
+}
+
+static test_return_t  bad_key_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo bad";
+  char *string;
+  size_t string_length;
+  uint32_t flags;
+  memcached_st *memc_clone;
+  unsigned int set= 1;
+  size_t max_keylen= 0xffff;
+
+  // Just skip if we are in binary mode.
+  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL))
+    return TEST_SKIPPED;
+
+  memc_clone= memcached_clone(NULL, memc);
+  test_truth(memc_clone);
+
+  rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  /* All keys are valid in the binary protocol (except for length) */
+  if (memcached_behavior_get(memc_clone, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 0)
+  {
+    string= memcached_get(memc_clone, key, strlen(key),
+                          &string_length, &flags, &rc);
+    test_truth(rc == MEMCACHED_BAD_KEY_PROVIDED);
+    test_truth(string_length ==  0);
+    test_truth(!string);
+
+    set= 0;
+    rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    string= memcached_get(memc_clone, key, strlen(key),
+                          &string_length, &flags, &rc);
+    test_truth(rc == MEMCACHED_NOTFOUND);
+    test_truth(string_length ==  0);
+    test_truth(!string);
+
+    /* Test multi key for bad keys */
+    const char *keys[] = { "GoodKey", "Bad Key", "NotMine" };
+    size_t key_lengths[] = { 7, 7, 7 };
+    set= 1;
+    rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set);
+    test_truth(rc == MEMCACHED_SUCCESS);
+
+    rc= memcached_mget(memc_clone, keys, key_lengths, 3);
+    test_truth(rc == MEMCACHED_BAD_KEY_PROVIDED);
+
+    rc= memcached_mget_by_key(memc_clone, "foo daddy", 9, keys, key_lengths, 1);
+    test_truth(rc == MEMCACHED_BAD_KEY_PROVIDED);
+
+    max_keylen= 250;
+
+    /* The following test should be moved to the end of this function when the
+       memcached server is updated to allow max size length of the keys in the
+       binary protocol
+    */
+    rc= memcached_callback_set(memc_clone, MEMCACHED_CALLBACK_PREFIX_KEY, NULL);
+    test_truth(rc == MEMCACHED_SUCCESS);
+
+    char *longkey= malloc(max_keylen + 1);
+    if (longkey != NULL)
+    {
+      memset(longkey, 'a', max_keylen + 1);
+      string= memcached_get(memc_clone, longkey, max_keylen,
+                            &string_length, &flags, &rc);
+      test_truth(rc == MEMCACHED_NOTFOUND);
+      test_truth(string_length ==  0);
+      test_truth(!string);
+
+      string= memcached_get(memc_clone, longkey, max_keylen + 1,
+                            &string_length, &flags, &rc);
+      test_truth(rc == MEMCACHED_BAD_KEY_PROVIDED);
+      test_truth(string_length ==  0);
+      test_truth(!string);
+
+      free(longkey);
+    }
+  }
+
+  /* Make sure zero length keys are marked as bad */
+  set= 1;
+  rc= memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_VERIFY_KEY, set);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  string= memcached_get(memc_clone, key, 0,
+                        &string_length, &flags, &rc);
+  test_truth(rc == MEMCACHED_BAD_KEY_PROVIDED);
+  test_truth(string_length ==  0);
+  test_truth(!string);
+
+  memcached_free(memc_clone);
+
+  return TEST_SUCCESS;
+}
+
+#define READ_THROUGH_VALUE "set for me"
+static memcached_return_t read_through_trigger(memcached_st *memc __attribute__((unused)),
+                                               char *key __attribute__((unused)),
+                                               size_t key_length __attribute__((unused)),
+                                               memcached_result_st *result)
+{
+
+  return memcached_result_set_value(result, READ_THROUGH_VALUE, strlen(READ_THROUGH_VALUE));
+}
+
+static test_return_t read_through(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo";
+  char *string;
+  size_t string_length;
+  uint32_t flags;
+  memcached_trigger_key_fn cb= (memcached_trigger_key_fn)read_through_trigger;
+
+  string= memcached_get(memc, key, strlen(key),
+                        &string_length, &flags, &rc);
+
+  test_truth(rc == MEMCACHED_NOTFOUND);
+  test_false(string_length);
+  test_false(string);
+
+  rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_GET_FAILURE,
+                             *(void **)&cb);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  string= memcached_get(memc, key, strlen(key),
+                        &string_length, &flags, &rc);
+
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(string_length ==  strlen(READ_THROUGH_VALUE));
+  test_strcmp(READ_THROUGH_VALUE, string);
+  free(string);
+
+  string= memcached_get(memc, key, strlen(key),
+                        &string_length, &flags, &rc);
+
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(string_length ==  strlen(READ_THROUGH_VALUE));
+  test_truth(!strcmp(READ_THROUGH_VALUE, string));
+  free(string);
+
+  return TEST_SUCCESS;
+}
+
+static memcached_return_t  delete_trigger(memcached_st *ptr __attribute__((unused)),
+                                          const char *key,
+                                          size_t key_length __attribute__((unused)))
+{
+  assert(key);
+
+  return MEMCACHED_SUCCESS;
+}
+
+static test_return_t  delete_through(memcached_st *memc)
+{
+  memcached_trigger_delete_key_fn callback;
+  memcached_return_t rc;
+
+  callback= (memcached_trigger_delete_key_fn)delete_trigger;
+
+  rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_DELETE_TRIGGER, *(void**)&callback);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  get_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo";
+  char *string;
+  size_t string_length;
+  uint32_t flags;
+
+  rc= memcached_delete(memc, key, strlen(key), (time_t)0);
+  test_truth(rc == MEMCACHED_BUFFERED || rc == MEMCACHED_NOTFOUND);
+
+  string= memcached_get(memc, key, strlen(key),
+                        &string_length, &flags, &rc);
+
+  test_truth(rc == MEMCACHED_NOTFOUND);
+  test_false(string_length);
+  test_false(string);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  get_test2(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo";
+  const char *value= "when we sanitize";
+  char *string;
+  size_t string_length;
+  uint32_t flags;
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  string= memcached_get(memc, key, strlen(key),
+                        &string_length, &flags, &rc);
+
+  test_truth(string);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(string_length == strlen(value));
+  test_truth(!memcmp(string, value, string_length));
+
+  free(string);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  set_test2(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo";
+  const char *value= "train in the brain";
+  size_t value_length= strlen(value);
+  unsigned int x;
+
+  for (x= 0; x < 10; x++)
+  {
+    rc= memcached_set(memc, key, strlen(key),
+                      value, value_length,
+                      (time_t)0, (uint32_t)0);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  }
+
+  return TEST_SUCCESS;
+}
+
+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_truth(value);
+
+  for (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++)
+  {
+    char key[16];
+
+    sprintf(key, "foo%u", x);
+
+    rc= memcached_set(memc, key, strlen(key),
+                      value, value_length,
+                      (time_t)0, (uint32_t)0);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  }
+
+  free(value);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  get_test3(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo";
+  char *value;
+  size_t value_length= 8191;
+  char *string;
+  size_t string_length;
+  uint32_t flags;
+  uint32_t x;
+
+  value = (char*)malloc(value_length);
+  test_truth(value);
+
+  for (x= 0; x < value_length; x++)
+    value[x] = (char) (x % 127);
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, value_length,
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  string= memcached_get(memc, key, strlen(key),
+                        &string_length, &flags, &rc);
+
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(string);
+  test_truth(string_length == value_length);
+  test_truth(!memcmp(string, value, string_length));
+
+  free(string);
+  free(value);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  get_test4(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo";
+  char *value;
+  size_t value_length= 8191;
+  char *string;
+  size_t string_length;
+  uint32_t flags;
+  uint32_t x;
+
+  value = (char*)malloc(value_length);
+  test_truth(value);
+
+  for (x= 0; x < value_length; x++)
+    value[x] = (char) (x % 127);
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, value_length,
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  for (x= 0; x < 10; x++)
+  {
+    string= memcached_get(memc, key, strlen(key),
+                          &string_length, &flags, &rc);
+
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(string);
+    test_truth(string_length == value_length);
+    test_truth(!memcmp(string, value, string_length));
+    free(string);
+  }
+
+  free(value);
+
+  return TEST_SUCCESS;
+}
+
+/*
+ * This test verifies that memcached_read_one_response doesn't try to
+ * dereference a NIL-pointer if you issue a multi-get and don't read out all
+ * responses before you execute a storage command.
+ */
+static test_return_t get_test5(memcached_st *memc)
+{
+  /*
+  ** Request the same key twice, to ensure that we hash to the same server
+  ** (so that we have multiple response values queued up) ;-)
+  */
+  const char *keys[]= { "key", "key" };
+  size_t lengths[]= { 3, 3 };
+  uint32_t flags;
+  size_t rlen;
+
+  memcached_return_t rc= memcached_set(memc, keys[0], lengths[0],
+                                     keys[0], lengths[0], 0, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  rc= memcached_mget(memc, keys, lengths, 2);
+
+  memcached_result_st results_obj;
+  memcached_result_st *results;
+  results=memcached_result_create(memc, &results_obj);
+  test_truth(results);
+  results=memcached_fetch_result(memc, &results_obj, &rc);
+  test_truth(results);
+  memcached_result_free(&results_obj);
+
+  /* Don't read out the second result, but issue a set instead.. */
+  rc= memcached_set(memc, keys[0], lengths[0], keys[0], lengths[0], 0, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  char *val= memcached_get_by_key(memc, keys[0], lengths[0], "yek", 3,
+                                  &rlen, &flags, &rc);
+  test_truth(val == NULL);
+  test_truth(rc == MEMCACHED_NOTFOUND);
+  val= memcached_get(memc, keys[0], lengths[0], &rlen, &flags, &rc);
+  test_truth(val != NULL);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  free(val);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  mget_end(memcached_st *memc)
+{
+  const char *keys[]= { "foo", "foo2" };
+  size_t lengths[]= { 3, 4 };
+  const char *values[]= { "fjord", "41" };
+
+  memcached_return_t rc;
+
+  // Set foo and foo2
+  for (int i= 0; i < 2; i++)
+  {
+    rc= memcached_set(memc, keys[i], lengths[i], values[i], strlen(values[i]),
+                     (time_t)0, (uint32_t)0);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  char *string;
+  size_t string_length;
+  uint32_t flags;
+
+  // retrieve both via mget
+  rc= memcached_mget(memc, keys, lengths, 2);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  char key[MEMCACHED_MAX_KEY];
+  size_t key_length;
+
+  // this should get both
+  for (int i = 0; i < 2; i++)
+  {
+    string= memcached_fetch(memc, key, &key_length, &string_length,
+                            &flags, &rc);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    int val = 0;
+    if (key_length == 4)
+      val= 1;
+    test_truth(string_length == strlen(values[val]));
+    test_truth(strncmp(values[val], string, string_length) == 0);
+    free(string);
+  }
+
+  // this should indicate end
+  string= memcached_fetch(memc, key, &key_length, &string_length, &flags, &rc);
+  test_truth(rc == MEMCACHED_END);
+
+  // now get just one
+  rc= memcached_mget(memc, keys, lengths, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  string= memcached_fetch(memc, key, &key_length, &string_length, &flags, &rc);
+  test_truth(key_length == lengths[0]);
+  test_truth(strncmp(keys[0], key, key_length) == 0);
+  test_truth(string_length == strlen(values[0]));
+  test_truth(strncmp(values[0], string, string_length) == 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  free(string);
+
+  // this should indicate end
+  string= memcached_fetch(memc, key, &key_length, &string_length, &flags, &rc);
+  test_truth(rc == MEMCACHED_END);
+
+  return TEST_SUCCESS;
+}
+
+/* Do not copy the style of this code, I just access hosts to testthis function */
+static test_return_t  stats_servername_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  memcached_stat_st memc_stat;
+  memcached_server_instance_st *instance=
+    memcached_server_instance_fetch(memc, 0);
+
+  rc= memcached_stat_servername(&memc_stat, NULL,
+                                instance->hostname,
+                                instance->port);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  increment_test(memcached_st *memc)
+{
+  uint64_t new_number;
+  memcached_return_t rc;
+  const char *key= "number";
+  const char *value= "0";
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  rc= memcached_increment(memc, key, strlen(key),
+                          1, &new_number);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(new_number == 1);
+
+  rc= memcached_increment(memc, key, strlen(key),
+                          1, &new_number);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(new_number == 2);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  increment_with_initial_test(memcached_st *memc)
+{
+  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0)
+  {
+    uint64_t new_number;
+    memcached_return_t rc;
+    const char *key= "number";
+    uint64_t initial= 0;
+
+    rc= memcached_increment_with_initial(memc, key, strlen(key),
+                                         1, initial, 0, &new_number);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(new_number == initial);
+
+    rc= memcached_increment_with_initial(memc, key, strlen(key),
+                                         1, initial, 0, &new_number);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(new_number == (initial + 1));
+  }
+  return TEST_SUCCESS;
+}
+
+static test_return_t  decrement_test(memcached_st *memc)
+{
+  uint64_t new_number;
+  memcached_return_t rc;
+  const char *key= "number";
+  const char *value= "3";
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  rc= memcached_decrement(memc, key, strlen(key),
+                          1, &new_number);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(new_number == 2);
+
+  rc= memcached_decrement(memc, key, strlen(key),
+                          1, &new_number);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(new_number == 1);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  decrement_with_initial_test(memcached_st *memc)
+{
+  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0)
+  {
+    uint64_t new_number;
+    memcached_return_t rc;
+    const char *key= "number";
+    uint64_t initial= 3;
+
+    rc= memcached_decrement_with_initial(memc, key, strlen(key),
+                                         1, initial, 0, &new_number);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(new_number == initial);
+
+    rc= memcached_decrement_with_initial(memc, key, strlen(key),
+                                         1, initial, 0, &new_number);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(new_number == (initial - 1));
+  }
+  return TEST_SUCCESS;
+}
+
+static test_return_t  increment_by_key_test(memcached_st *memc)
+{
+  uint64_t new_number;
+  memcached_return_t rc;
+  const char *master_key= "foo";
+  const char *key= "number";
+  const char *value= "0";
+
+  rc= memcached_set_by_key(memc, master_key, strlen(master_key),
+                           key, strlen(key),
+                           value, strlen(value),
+                           (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  rc= memcached_increment_by_key(memc, master_key, strlen(master_key), key, strlen(key),
+                                 1, &new_number);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(new_number == 1);
+
+  rc= memcached_increment_by_key(memc, master_key, strlen(master_key), key, strlen(key),
+                                 1, &new_number);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(new_number == 2);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  increment_with_initial_by_key_test(memcached_st *memc)
+{
+  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0)
+  {
+    uint64_t new_number;
+    memcached_return_t rc;
+    const char *master_key= "foo";
+    const char *key= "number";
+    uint64_t initial= 0;
+
+    rc= memcached_increment_with_initial_by_key(memc, master_key, strlen(master_key),
+                                                key, strlen(key),
+                                                1, initial, 0, &new_number);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(new_number == initial);
+
+    rc= memcached_increment_with_initial_by_key(memc, master_key, strlen(master_key),
+                                                key, strlen(key),
+                                                1, initial, 0, &new_number);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(new_number == (initial + 1));
+  }
+  return TEST_SUCCESS;
+}
+
+static test_return_t  decrement_by_key_test(memcached_st *memc)
+{
+  uint64_t new_number;
+  memcached_return_t rc;
+  const char *master_key= "foo";
+  const char *key= "number";
+  const char *value= "3";
+
+  rc= memcached_set_by_key(memc, master_key, strlen(master_key),
+                           key, strlen(key),
+                           value, strlen(value),
+                           (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  rc= memcached_decrement_by_key(memc, master_key, strlen(master_key),
+                                 key, strlen(key),
+                                 1, &new_number);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(new_number == 2);
+
+  rc= memcached_decrement_by_key(memc, master_key, strlen(master_key),
+                                 key, strlen(key),
+                                 1, &new_number);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(new_number == 1);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  decrement_with_initial_by_key_test(memcached_st *memc)
+{
+  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0)
+  {
+    uint64_t new_number;
+    memcached_return_t rc;
+    const char *master_key= "foo";
+    const char *key= "number";
+    uint64_t initial= 3;
+
+    rc= memcached_decrement_with_initial_by_key(memc, master_key, strlen(master_key),
+                                                key, strlen(key),
+                                                1, initial, 0, &new_number);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(new_number == initial);
+
+    rc= memcached_decrement_with_initial_by_key(memc, master_key, strlen(master_key),
+                                                key, strlen(key),
+                                                1, initial, 0, &new_number);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(new_number == (initial - 1));
+  }
+  return TEST_SUCCESS;
+}
+
+static test_return_t  quit_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "fudge";
+  const char *value= "sanford and sun";
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)10, (uint32_t)3);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  memcached_quit(memc);
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)50, (uint32_t)9);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  mget_result_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *keys[]= {"fudge", "son", "food"};
+  size_t key_length[]= {5, 3, 4};
+  unsigned int x;
+
+  memcached_result_st results_obj;
+  memcached_result_st *results;
+
+  results= memcached_result_create(memc, &results_obj);
+  test_truth(results);
+  test_truth(&results_obj == results);
+
+  /* We need to empty the server before continueing test */
+  rc= memcached_flush(memc, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_mget(memc, keys, key_length, 3);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL)
+  {
+    test_truth(results);
+  }
+
+  while ((results= memcached_fetch_result(memc, &results_obj, &rc)) != NULL)
+  test_truth(!results);
+  test_truth(rc == MEMCACHED_END);
+
+  for (x= 0; x < 3; x++)
+  {
+    rc= memcached_set(memc, keys[x], key_length[x],
+                      keys[x], key_length[x],
+                      (time_t)50, (uint32_t)9);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  }
+
+  rc= memcached_mget(memc, keys, key_length, 3);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  while ((results= memcached_fetch_result(memc, &results_obj, &rc)))
+  {
+    test_truth(results);
+    test_truth(&results_obj == results);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(memcached_result_key_length(results) == memcached_result_length(results));
+    test_truth(!memcmp(memcached_result_key_value(results),
+                   memcached_result_value(results),
+                   memcached_result_length(results)));
+  }
+
+  memcached_result_free(&results_obj);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  mget_result_alloc_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *keys[]= {"fudge", "son", "food"};
+  size_t key_length[]= {5, 3, 4};
+  unsigned int x;
+
+  memcached_result_st *results;
+
+  /* We need to empty the server before continueing test */
+  rc= memcached_flush(memc, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_mget(memc, keys, key_length, 3);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  while ((results= memcached_fetch_result(memc, NULL, &rc)) != NULL)
+  {
+    test_truth(results);
+  }
+  test_truth(!results);
+  test_truth(rc == MEMCACHED_END);
+
+  for (x= 0; x < 3; x++)
+  {
+    rc= memcached_set(memc, keys[x], key_length[x],
+                      keys[x], key_length[x],
+                      (time_t)50, (uint32_t)9);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  }
+
+  rc= memcached_mget(memc, keys, key_length, 3);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  x= 0;
+  while ((results= memcached_fetch_result(memc, NULL, &rc)))
+  {
+    test_truth(results);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(memcached_result_key_length(results) == memcached_result_length(results));
+    test_truth(!memcmp(memcached_result_key_value(results),
+                   memcached_result_value(results),
+                   memcached_result_length(results)));
+    memcached_result_free(results);
+    x++;
+  }
+
+  return TEST_SUCCESS;
+}
+
+/* Count the results */
+static memcached_return_t callback_counter(memcached_st *ptr __attribute__((unused)),
+                                           memcached_result_st *result __attribute__((unused)),
+                                           void *context)
+{
+  size_t *counter= (size_t *)context;
+
+  *counter= *counter + 1;
+
+  return MEMCACHED_SUCCESS;
+}
+
+static test_return_t  mget_result_function(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *keys[]= {"fudge", "son", "food"};
+  size_t key_length[]= {5, 3, 4};
+  unsigned int x;
+  size_t counter;
+  memcached_execute_fn callbacks[1];
+
+  /* We need to empty the server before continueing test */
+  rc= memcached_flush(memc, 0);
+  for (x= 0; x < 3; x++)
+  {
+    rc= memcached_set(memc, keys[x], key_length[x],
+                      keys[x], key_length[x],
+                      (time_t)50, (uint32_t)9);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  }
+
+  rc= memcached_mget(memc, keys, key_length, 3);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  callbacks[0]= &callback_counter;
+  counter= 0;
+  rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
+
+  test_truth(counter == 3);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  mget_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *keys[]= {"fudge", "son", "food"};
+  size_t key_length[]= {5, 3, 4};
+  unsigned int x;
+  uint32_t flags;
+
+  char return_key[MEMCACHED_MAX_KEY];
+  size_t return_key_length;
+  char *return_value;
+  size_t return_value_length;
+
+  /* We need to empty the server before continueing test */
+  rc= memcached_flush(memc, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  rc= memcached_mget(memc, keys, key_length, 3);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
+                      &return_value_length, &flags, &rc)) != NULL)
+  {
+    test_truth(return_value);
+  }
+  test_truth(!return_value);
+  test_truth(return_value_length == 0);
+  test_truth(rc == MEMCACHED_END);
+
+  for (x= 0; x < 3; x++)
+  {
+    rc= memcached_set(memc, keys[x], key_length[x],
+                      keys[x], key_length[x],
+                      (time_t)50, (uint32_t)9);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  }
+
+  rc= memcached_mget(memc, keys, key_length, 3);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  x= 0;
+  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
+                                        &return_value_length, &flags, &rc)))
+  {
+    test_truth(return_value);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(return_key_length == return_value_length);
+    test_truth(!memcmp(return_value, return_key, return_value_length));
+    free(return_value);
+    x++;
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t mget_execute(memcached_st *memc)
+{
+  bool binary= false;
+
+  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) != 0)
+    binary= true;
+
+  /*
+   * I only want to hit _one_ server so I know the number of requests I'm
+   * sending in the pipeline.
+   */
+  uint32_t number_of_hosts= memc->number_of_hosts;
+  memc->number_of_hosts= 1;
+
+  size_t max_keys= binary ? 20480 : 1;
+
+
+  char **keys= calloc(max_keys, sizeof(char*));
+  size_t *key_length=calloc(max_keys, sizeof(size_t));
+
+  /* First add all of the items.. */
+  char blob[1024] = {0};
+  memcached_return_t rc;
+  for (size_t x= 0; x < max_keys; ++x)
+  {
+    char k[251];
+
+    key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%zu", x);
+    keys[x]= strdup(k);
+    test_truth(keys[x] != NULL);
+    rc= memcached_add(memc, keys[x], key_length[x], blob, sizeof(blob), 0, 0);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  }
+
+  /* Try to get all of them with a large multiget */
+  size_t counter= 0;
+  memcached_execute_fn callbacks[1]= { [0]= &callback_counter };
+  rc= memcached_mget_execute(memc, (const char**)keys, key_length,
+                             max_keys, callbacks, &counter, 1);
+
+  if (binary)
+  {
+    test_truth(rc == MEMCACHED_SUCCESS);
+
+    rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
+    test_truth(rc == MEMCACHED_END);
+
+    /* Verify that we got all of the items */
+    test_truth(counter == max_keys);
+  }
+  else
+  {
+    test_truth(rc == MEMCACHED_NOT_SUPPORTED);
+    test_truth(counter == 0);
+  }
+
+  /* Release all allocated resources */
+  for (size_t x= 0; x < max_keys; ++x)
+  {
+    free(keys[x]);
+  }
+  free(keys);
+  free(key_length);
+
+  memc->number_of_hosts= number_of_hosts;
+  return TEST_SUCCESS;
+}
+
+static test_return_t  get_stats_keys(memcached_st *memc)
+{
+ char **stat_list;
+ char **ptr;
+ memcached_stat_st memc_stat;
+ memcached_return_t rc;
+
+ stat_list= memcached_stat_get_keys(memc, &memc_stat, &rc);
+ test_truth(rc == MEMCACHED_SUCCESS);
+ for (ptr= stat_list; *ptr; ptr++)
+   test_truth(*ptr);
+
+ free(stat_list);
+
+ return TEST_SUCCESS;
+}
+
+static test_return_t  version_string_test(memcached_st *memc __attribute__((unused)))
+{
+  const char *version_string;
+
+  version_string= memcached_lib_version();
+
+  test_truth(!strcmp(version_string, LIBMEMCACHED_VERSION_STRING));
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  get_stats(memcached_st *memc)
+{
+ unsigned int x;
+ char **stat_list;
+ char **ptr;
+ memcached_return_t rc;
+ memcached_stat_st *memc_stat;
+
+ memc_stat= memcached_stat(memc, NULL, &rc);
+ test_truth(rc == MEMCACHED_SUCCESS);
+
+ test_truth(rc == MEMCACHED_SUCCESS);
+ test_truth(memc_stat);
+
+ for (x= 0; x < memcached_server_count(memc); x++)
+ {
+   stat_list= memcached_stat_get_keys(memc, memc_stat+x, &rc);
+   test_truth(rc == MEMCACHED_SUCCESS);
+   for (ptr= stat_list; *ptr; ptr++);
+
+   free(stat_list);
+ }
+
+ memcached_stat_free(NULL, memc_stat);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  add_host_test(memcached_st *memc)
+{
+  unsigned int x;
+  memcached_server_st *servers;
+  memcached_return_t rc;
+  char servername[]= "0.example.com";
+
+  servers= memcached_server_list_append_with_weight(NULL, servername, 400, 0, &rc);
+  test_truth(servers);
+  test_truth(1 == memcached_server_list_count(servers));
+
+  for (x= 2; x < 20; x++)
+  {
+    char buffer[SMALL_STRING_LEN];
+
+    snprintf(buffer, SMALL_STRING_LEN, "%u.example.com", 400+x);
+    servers= memcached_server_list_append_with_weight(servers, buffer, 401, 0,
+                                     &rc);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(x == memcached_server_list_count(servers));
+  }
+
+  rc= memcached_server_push(memc, servers);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  rc= memcached_server_push(memc, servers);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  memcached_server_list_free(servers);
+
+  return TEST_SUCCESS;
+}
+
+static memcached_return_t  clone_test_callback(memcached_st *parent __attribute__((unused)), memcached_st *memc_clone __attribute__((unused)))
+{
+  return MEMCACHED_SUCCESS;
+}
+
+static memcached_return_t  cleanup_test_callback(memcached_st *ptr __attribute__((unused)))
+{
+  return MEMCACHED_SUCCESS;
+}
+
+static test_return_t  callback_test(memcached_st *memc)
+{
+  /* Test User Data */
+  {
+    int x= 5;
+    int *test_ptr;
+    memcached_return_t rc;
+
+    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_USER_DATA, &x);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_ptr= (int *)memcached_callback_get(memc, MEMCACHED_CALLBACK_USER_DATA, &rc);
+    test_truth(*test_ptr == x);
+  }
+
+  /* Test Clone Callback */
+  {
+    memcached_clone_fn clone_cb= (memcached_clone_fn)clone_test_callback;
+    void *clone_cb_ptr= *(void **)&clone_cb;
+    void *temp_function= NULL;
+    memcached_return_t rc;
+
+    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_CLONE_FUNCTION,
+                               clone_cb_ptr);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    temp_function= memcached_callback_get(memc, MEMCACHED_CALLBACK_CLONE_FUNCTION, &rc);
+    test_truth(temp_function == clone_cb_ptr);
+  }
+
+  /* Test Cleanup Callback */
+  {
+    memcached_cleanup_fn cleanup_cb=
+      (memcached_cleanup_fn)cleanup_test_callback;
+    void *cleanup_cb_ptr= *(void **)&cleanup_cb;
+    void *temp_function= NULL;
+    memcached_return_t rc;
+
+    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_CLONE_FUNCTION,
+                               cleanup_cb_ptr);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    temp_function= memcached_callback_get(memc, MEMCACHED_CALLBACK_CLONE_FUNCTION, &rc);
+    test_truth(temp_function == cleanup_cb_ptr);
+  }
+
+  return TEST_SUCCESS;
+}
+
+/* We don't test the behavior itself, we test the switches */
+static test_return_t  behavior_test(memcached_st *memc)
+{
+  uint64_t value;
+  uint32_t set= 1;
+
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, set);
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK);
+  test_truth(value == 1);
+
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, set);
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY);
+  test_truth(value == 1);
+
+  set= MEMCACHED_HASH_MD5;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_HASH);
+  test_truth(value == MEMCACHED_HASH_MD5);
+
+  set= 0;
+
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, set);
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NO_BLOCK);
+  test_truth(value == 0);
+
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, set);
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY);
+  test_truth(value == 0);
+
+  set= MEMCACHED_HASH_DEFAULT;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_HASH);
+  test_truth(value == MEMCACHED_HASH_DEFAULT);
+
+  set= MEMCACHED_HASH_CRC;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_HASH);
+  test_truth(value == MEMCACHED_HASH_CRC);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE);
+  test_truth(value > 0);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
+  test_truth(value > 0);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, value + 1);
+  test_truth((value + 1) == memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS));
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t MEMCACHED_BEHAVIOR_CORK_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  bool set= true;
+  bool value;
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_CORK, set);
+#ifdef TCP_CORK
+  test_truth(rc == MEMCACHED_SUCCESS);
+#else
+  test_truth(rc == MEMCACHED_NOT_SUPPORTED);
+#endif
+
+  value= (bool)memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_CORK);
+#ifdef TCP_CORK
+  test_truth((bool)value == set);
+#else
+  test_false((bool)value == set);
+#endif
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t fetch_all_results(memcached_st *memc)
+{
+  memcached_return_t rc= MEMCACHED_SUCCESS;
+  char return_key[MEMCACHED_MAX_KEY];
+  size_t return_key_length;
+  char *return_value;
+  size_t return_value_length;
+  uint32_t flags;
+
+  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
+                                        &return_value_length, &flags, &rc)))
+  {
+    test_truth(return_value);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    free(return_value);
+  }
+
+  return ((rc == MEMCACHED_END) || (rc == MEMCACHED_SUCCESS)) ? TEST_SUCCESS : TEST_FAILURE;
+}
+
+/* Test case provided by Cal Haldenbrand */
+static test_return_t  user_supplied_bug1(memcached_st *memc)
+{
+  unsigned int setter= 1;
+
+  unsigned long long total= 0;
+  uint32_t size= 0;
+  char key[10];
+  char randomstuff[6 * 1024];
+  memcached_return_t rc;
+
+  memset(randomstuff, 0, 6 * 1024);
+
+  /* We just keep looking at the same values over and over */
+  srandom(10);
+
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, setter);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, setter);
+
+
+  /* add key */
+  for (uint32_t x= 0 ; total < 20 * 1024576 ; x++ )
+  {
+    unsigned int j= 0;
+
+    size= (uint32_t)(rand() % ( 5 * 1024 ) ) + 400;
+    memset(randomstuff, 0, 6 * 1024);
+    test_truth(size < 6 * 1024); /* Being safe here */
+
+    for (j= 0 ; j < size ;j++)
+      randomstuff[j] = (signed char) ((rand() % 26) + 97);
+
+    total += size;
+    snprintf(key, sizeof(key), "%u", x);
+    rc = memcached_set(memc, key, strlen(key),
+                       randomstuff, strlen(randomstuff), 10, 0);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+    /* If we fail, lets try again */
+    if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED)
+      rc = memcached_set(memc, key, strlen(key),
+                         randomstuff, strlen(randomstuff), 10, 0);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  }
+
+  return TEST_SUCCESS;
+}
+
+/* Test case provided by Cal Haldenbrand */
+static test_return_t  user_supplied_bug2(memcached_st *memc)
+{
+  unsigned int setter;
+  size_t total= 0;
+
+  setter= 1;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, setter);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, setter);
+#ifdef NOT_YET
+  setter = 20 * 1024576;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE, setter);
+  setter = 20 * 1024576;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE, setter);
+  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE);
+  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
+
+  for (x= 0, errors= 0; total < 20 * 1024576 ; x++)
+#endif
+
+  for (uint32_t x= 0, errors= 0; total < 24576 ; x++)
+  {
+    memcached_return_t rc= MEMCACHED_SUCCESS;
+    char buffer[SMALL_STRING_LEN];
+    uint32_t flags= 0;
+    size_t val_len= 0;
+    char *getval;
+
+    memset(buffer, 0, SMALL_STRING_LEN);
+
+    snprintf(buffer, sizeof(buffer), "%u", x);
+    getval= memcached_get(memc, buffer, strlen(buffer),
+                           &val_len, &flags, &rc);
+    if (rc != MEMCACHED_SUCCESS)
+    {
+      if (rc == MEMCACHED_NOTFOUND)
+        errors++;
+      else
+      {
+        test_truth(rc);
+      }
+
+      continue;
+    }
+    total+= val_len;
+    errors= 0;
+    free(getval);
+  }
+
+  return TEST_SUCCESS;
+}
+
+/* Do a large mget() over all the keys we think exist */
+#define KEY_COUNT 3000 // * 1024576
+static test_return_t  user_supplied_bug3(memcached_st *memc)
+{
+  memcached_return_t rc;
+  unsigned int setter;
+  unsigned int x;
+  char **keys;
+  size_t key_lengths[KEY_COUNT];
+
+  setter= 1;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, setter);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, setter);
+#ifdef NOT_YET
+  setter = 20 * 1024576;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE, setter);
+  setter = 20 * 1024576;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE, setter);
+  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE);
+  getter = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
+#endif
+
+  keys= calloc(KEY_COUNT, sizeof(char *));
+  test_truth(keys);
+  for (x= 0; x < KEY_COUNT; x++)
+  {
+    char buffer[30];
+
+    snprintf(buffer, 30, "%u", x);
+    keys[x]= strdup(buffer);
+    key_lengths[x]= strlen(keys[x]);
+  }
+
+  rc= memcached_mget(memc, (const char **)keys, key_lengths, KEY_COUNT);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  test_truth(fetch_all_results(memc) == TEST_SUCCESS);
+
+  for (x= 0; x < KEY_COUNT; x++)
+    free(keys[x]);
+  free(keys);
+
+  return TEST_SUCCESS;
+}
+
+/* Make sure we behave properly if server list has no values */
+static test_return_t  user_supplied_bug4(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *keys[]= {"fudge", "son", "food"};
+  size_t key_length[]= {5, 3, 4};
+  unsigned int x;
+  uint32_t flags;
+  char return_key[MEMCACHED_MAX_KEY];
+  size_t return_key_length;
+  char *return_value;
+  size_t return_value_length;
+
+  /* Here we free everything before running a bunch of mget tests */
+  memcached_servers_reset(memc);
+
+
+  /* We need to empty the server before continueing test */
+  rc= memcached_flush(memc, 0);
+  test_truth(rc == MEMCACHED_NO_SERVERS);
+
+  rc= memcached_mget(memc, keys, key_length, 3);
+  test_truth(rc == MEMCACHED_NO_SERVERS);
+
+  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
+                      &return_value_length, &flags, &rc)) != NULL)
+  {
+    test_truth(return_value);
+  }
+  test_truth(!return_value);
+  test_truth(return_value_length == 0);
+  test_truth(rc == MEMCACHED_NO_SERVERS);
+
+  for (x= 0; x < 3; x++)
+  {
+    rc= memcached_set(memc, keys[x], key_length[x],
+                      keys[x], key_length[x],
+                      (time_t)50, (uint32_t)9);
+    test_truth(rc == MEMCACHED_NO_SERVERS);
+  }
+
+  rc= memcached_mget(memc, keys, key_length, 3);
+  test_truth(rc == MEMCACHED_NO_SERVERS);
+
+  x= 0;
+  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
+                                        &return_value_length, &flags, &rc)))
+  {
+    test_truth(return_value);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(return_key_length == return_value_length);
+    test_truth(!memcmp(return_value, return_key, return_value_length));
+    free(return_value);
+    x++;
+  }
+
+  return TEST_SUCCESS;
+}
+
+#define VALUE_SIZE_BUG5 1048064
+static test_return_t  user_supplied_bug5(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *keys[]= {"036790384900", "036790384902", "036790384904", "036790384906"};
+  size_t key_length[]=  {strlen("036790384900"), strlen("036790384902"), strlen("036790384904"), strlen("036790384906")};
+  char return_key[MEMCACHED_MAX_KEY];
+  size_t return_key_length;
+  char *value;
+  size_t value_length;
+  uint32_t flags;
+  unsigned int count;
+  unsigned int x;
+  char insert_data[VALUE_SIZE_BUG5];
+
+  for (x= 0; x < VALUE_SIZE_BUG5; x++)
+    insert_data[x]= (signed char)rand();
+
+  memcached_flush(memc, 0);
+  value= memcached_get(memc, keys[0], key_length[0],
+                        &value_length, &flags, &rc);
+  test_truth(value == NULL);
+  rc= memcached_mget(memc, keys, key_length, 4);
+
+  count= 0;
+  while ((value= memcached_fetch(memc, return_key, &return_key_length,
+                                        &value_length, &flags, &rc)))
+    count++;
+  test_truth(count == 0);
+
+  for (x= 0; x < 4; x++)
+  {
+    rc= memcached_set(memc, keys[x], key_length[x],
+                      insert_data, VALUE_SIZE_BUG5,
+                      (time_t)0, (uint32_t)0);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  for (x= 0; x < 10; x++)
+  {
+    value= memcached_get(memc, keys[0], key_length[0],
+                         &value_length, &flags, &rc);
+    test_truth(value);
+    free(value);
+
+    rc= memcached_mget(memc, keys, key_length, 4);
+    count= 0;
+    while ((value= memcached_fetch(memc, return_key, &return_key_length,
+                                          &value_length, &flags, &rc)))
+    {
+      count++;
+      free(value);
+    }
+    test_truth(count == 4);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  user_supplied_bug6(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *keys[]= {"036790384900", "036790384902", "036790384904", "036790384906"};
+  size_t key_length[]=  {strlen("036790384900"), strlen("036790384902"), strlen("036790384904"), strlen("036790384906")};
+  char return_key[MEMCACHED_MAX_KEY];
+  size_t return_key_length;
+  char *value;
+  size_t value_length;
+  uint32_t flags;
+  unsigned int count;
+  unsigned int x;
+  char insert_data[VALUE_SIZE_BUG5];
+
+  for (x= 0; x < VALUE_SIZE_BUG5; x++)
+    insert_data[x]= (signed char)rand();
+
+  memcached_flush(memc, 0);
+  value= memcached_get(memc, keys[0], key_length[0],
+                        &value_length, &flags, &rc);
+  test_truth(value == NULL);
+  test_truth(rc == MEMCACHED_NOTFOUND);
+  rc= memcached_mget(memc, keys, key_length, 4);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  count= 0;
+  while ((value= memcached_fetch(memc, return_key, &return_key_length,
+                                        &value_length, &flags, &rc)))
+    count++;
+  test_truth(count == 0);
+  test_truth(rc == MEMCACHED_END);
+
+  for (x= 0; x < 4; x++)
+  {
+    rc= memcached_set(memc, keys[x], key_length[x],
+                      insert_data, VALUE_SIZE_BUG5,
+                      (time_t)0, (uint32_t)0);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  for (x= 0; x < 2; x++)
+  {
+    value= memcached_get(memc, keys[0], key_length[0],
+                         &value_length, &flags, &rc);
+    test_truth(value);
+    free(value);
+
+    rc= memcached_mget(memc, keys, key_length, 4);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    count= 3;
+    /* We test for purge of partial complete fetches */
+    for (count= 3; count; count--)
+    {
+      value= memcached_fetch(memc, return_key, &return_key_length,
+                             &value_length, &flags, &rc);
+      test_truth(rc == MEMCACHED_SUCCESS);
+      test_truth(!(memcmp(value, insert_data, value_length)));
+      test_truth(value_length);
+      free(value);
+    }
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  user_supplied_bug8(memcached_st *memc __attribute__((unused)))
+{
+  memcached_return_t rc;
+  memcached_st *mine;
+  memcached_st *memc_clone;
+
+  memcached_server_st *servers;
+  const char *server_list= "memcache1.memcache.bk.sapo.pt:11211, memcache1.memcache.bk.sapo.pt:11212, memcache1.memcache.bk.sapo.pt:11213, memcache1.memcache.bk.sapo.pt:11214, memcache2.memcache.bk.sapo.pt:11211, memcache2.memcache.bk.sapo.pt:11212, memcache2.memcache.bk.sapo.pt:11213, memcache2.memcache.bk.sapo.pt:11214";
+
+  servers= memcached_servers_parse(server_list);
+  test_truth(servers);
+
+  mine= memcached_create(NULL);
+  rc= memcached_server_push(mine, servers);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  memcached_server_list_free(servers);
+
+  test_truth(mine);
+  memc_clone= memcached_clone(NULL, mine);
+
+  memcached_quit(mine);
+  memcached_quit(memc_clone);
+
+
+  memcached_free(mine);
+  memcached_free(memc_clone);
+
+  return TEST_SUCCESS;
+}
+
+/* Test flag store/retrieve */
+static test_return_t  user_supplied_bug7(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *keys= "036790384900";
+  size_t key_length=  strlen(keys);
+  char return_key[MEMCACHED_MAX_KEY];
+  size_t return_key_length;
+  char *value;
+  size_t value_length;
+  uint32_t flags;
+  unsigned int x;
+  char insert_data[VALUE_SIZE_BUG5];
+
+  for (x= 0; x < VALUE_SIZE_BUG5; x++)
+    insert_data[x]= (signed char)rand();
+
+  memcached_flush(memc, 0);
+
+  flags= 245;
+  rc= memcached_set(memc, keys, key_length,
+                    insert_data, VALUE_SIZE_BUG5,
+                    (time_t)0, flags);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  flags= 0;
+  value= memcached_get(memc, keys, key_length,
+                        &value_length, &flags, &rc);
+  test_truth(flags == 245);
+  test_truth(value);
+  free(value);
+
+  rc= memcached_mget(memc, &keys, &key_length, 1);
+
+  flags= 0;
+  value= memcached_fetch(memc, return_key, &return_key_length,
+                         &value_length, &flags, &rc);
+  test_truth(flags == 245);
+  test_truth(value);
+  free(value);
+
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  user_supplied_bug9(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *keys[]= {"UDATA:edevil@sapo.pt", "fudge&*@#", "for^#@&$not"};
+  size_t key_length[3];
+  unsigned int x;
+  uint32_t flags;
+  unsigned count= 0;
+
+  char return_key[MEMCACHED_MAX_KEY];
+  size_t return_key_length;
+  char *return_value;
+  size_t return_value_length;
+
+
+  key_length[0]= strlen("UDATA:edevil@sapo.pt");
+  key_length[1]= strlen("fudge&*@#");
+  key_length[2]= strlen("for^#@&$not");
+
+
+  for (x= 0; x < 3; x++)
+  {
+    rc= memcached_set(memc, keys[x], key_length[x],
+                      keys[x], key_length[x],
+                      (time_t)50, (uint32_t)9);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  rc= memcached_mget(memc, keys, key_length, 3);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  /* We need to empty the server before continueing test */
+  while ((return_value= memcached_fetch(memc, return_key, &return_key_length,
+                      &return_value_length, &flags, &rc)) != NULL)
+  {
+    test_truth(return_value);
+    free(return_value);
+    count++;
+  }
+  test_truth(count == 3);
+
+  return TEST_SUCCESS;
+}
+
+/* We are testing with aggressive timeout to get failures */
+static test_return_t  user_supplied_bug10(memcached_st *memc)
+{
+  const char *key= "foo";
+  char *value;
+  size_t value_length= 512;
+  unsigned int x;
+  size_t key_len= 3;
+  memcached_return_t rc;
+  unsigned int set= 1;
+  memcached_st *mclone= memcached_clone(NULL, memc);
+  int32_t timeout;
+
+  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_NO_BLOCK, set);
+  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_TCP_NODELAY, set);
+  timeout= 2;
+  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_POLL_TIMEOUT,
+                         (uint64_t)timeout);
+
+  value = (char*)malloc(value_length * sizeof(char));
+
+  for (x= 0; x < value_length; x++)
+    value[x]= (char) (x % 127);
+
+  for (x= 1; x <= 100000; ++x)
+  {
+    rc= memcached_set(mclone, key, key_len,value, value_length, 0, 0);
+
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_WRITE_FAILURE ||
+           rc == MEMCACHED_BUFFERED || rc == MEMCACHED_TIMEOUT);
+
+    if (rc == MEMCACHED_WRITE_FAILURE || rc == MEMCACHED_TIMEOUT)
+      x--;
+  }
+
+  free(value);
+  memcached_free(mclone);
+
+  return TEST_SUCCESS;
+}
+
+/*
+  We are looking failures in the async protocol
+*/
+static test_return_t  user_supplied_bug11(memcached_st *memc)
+{
+  const char *key= "foo";
+  char *value;
+  size_t value_length= 512;
+  unsigned int x;
+  size_t key_len= 3;
+  memcached_return_t rc;
+  unsigned int set= 1;
+  int32_t timeout;
+  memcached_st *mclone= memcached_clone(NULL, memc);
+
+  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_NO_BLOCK, set);
+  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_TCP_NODELAY, set);
+  timeout= -1;
+  memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_POLL_TIMEOUT,
+                         (size_t)timeout);
+
+  timeout= (int32_t)memcached_behavior_get(mclone, MEMCACHED_BEHAVIOR_POLL_TIMEOUT);
+
+  test_truth(timeout == -1);
+
+  value = (char*)malloc(value_length * sizeof(char));
+
+  for (x= 0; x < value_length; x++)
+    value[x]= (char) (x % 127);
+
+  for (x= 1; x <= 100000; ++x)
+  {
+    rc= memcached_set(mclone, key, key_len,value, value_length, 0, 0);
+  }
+
+  free(value);
+  memcached_free(mclone);
+
+  return TEST_SUCCESS;
+}
+
+/*
+  Bug found where incr was not returning MEMCACHED_NOTFOUND when object did not exist.
+*/
+static test_return_t  user_supplied_bug12(memcached_st *memc)
+{
+  memcached_return_t rc;
+  uint32_t flags;
+  size_t value_length;
+  char *value;
+  uint64_t number_value;
+
+  value= memcached_get(memc, "autoincrement", strlen("autoincrement"),
+                        &value_length, &flags, &rc);
+  test_truth(value == NULL);
+  test_truth(rc == MEMCACHED_NOTFOUND);
+
+  rc= memcached_increment(memc, "autoincrement", strlen("autoincrement"),
+                          1, &number_value);
+
+  test_truth(value == NULL);
+  /* The binary protocol will set the key if it doesn't exist */
+  if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1)
+  {
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+  else
+  {
+    test_truth(rc == MEMCACHED_NOTFOUND);
+  }
+
+  rc= memcached_set(memc, "autoincrement", strlen("autoincrement"), "1", 1, 0, 0);
+
+  value= memcached_get(memc, "autoincrement", strlen("autoincrement"),
+                        &value_length, &flags, &rc);
+  test_truth(value);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  free(value);
+
+  rc= memcached_increment(memc, "autoincrement", strlen("autoincrement"),
+                          1, &number_value);
+  test_truth(number_value == 2);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  return TEST_SUCCESS;
+}
+
+/*
+  Bug found where command total one more than MEMCACHED_MAX_BUFFER
+  set key34567890 0 0 8169 \r\n is sent followed by buffer of size 8169, followed by 8169
+ */
+static test_return_t  user_supplied_bug13(memcached_st *memc)
+{
+  char key[] = "key34567890";
+  char *overflow;
+  memcached_return_t rc;
+  size_t overflowSize;
+
+  char commandFirst[]= "set key34567890 0 0 ";
+  char commandLast[] = " \r\n"; /* first line of command sent to server */
+  size_t commandLength;
+  size_t testSize;
+
+  commandLength = strlen(commandFirst) + strlen(commandLast) + 4; /* 4 is number of characters in size, probably 8196 */
+
+  overflowSize = MEMCACHED_MAX_BUFFER - commandLength;
+
+  for (testSize= overflowSize - 1; testSize < overflowSize + 1; testSize++)
+  {
+    overflow= malloc(testSize);
+    test_truth(overflow != NULL);
+
+    memset(overflow, 'x', testSize);
+    rc= memcached_set(memc, key, strlen(key),
+                      overflow, testSize, 0, 0);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    free(overflow);
+  }
+
+  return TEST_SUCCESS;
+}
+
+
+/*
+  Test values of many different sizes
+  Bug found where command total one more than MEMCACHED_MAX_BUFFER
+  set key34567890 0 0 8169 \r\n
+  is sent followed by buffer of size 8169, followed by 8169
+ */
+static test_return_t  user_supplied_bug14(memcached_st *memc)
+{
+  size_t setter= 1;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, setter);
+  memcached_return_t rc;
+  const char *key= "foo";
+  char *value;
+  size_t value_length= 18000;
+  char *string;
+  size_t string_length;
+  uint32_t flags;
+  unsigned int x;
+  size_t current_length;
+
+  value = (char*)malloc(value_length);
+  test_truth(value);
+
+  for (x= 0; x < value_length; x++)
+    value[x] = (char) (x % 127);
+
+  for (current_length= 0; current_length < value_length; current_length++)
+  {
+    rc= memcached_set(memc, key, strlen(key),
+                      value, current_length,
+                      (time_t)0, (uint32_t)0);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+    string= memcached_get(memc, key, strlen(key),
+                          &string_length, &flags, &rc);
+
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(string_length == current_length);
+    test_truth(!memcmp(string, value, string_length));
+
+    free(string);
+  }
+
+  free(value);
+
+  return TEST_SUCCESS;
+}
+
+/*
+  Look for zero length value problems
+  */
+static test_return_t  user_supplied_bug15(memcached_st *memc)
+{
+  uint32_t x;
+  memcached_return_t rc;
+  const char *key= "mykey";
+  char *value;
+  size_t length;
+  uint32_t flags;
+
+  for (x= 0; x < 2; x++)
+  {
+    rc= memcached_set(memc, key, strlen(key),
+                      NULL, 0,
+                      (time_t)0, (uint32_t)0);
+
+    test_truth(rc == MEMCACHED_SUCCESS);
+
+    value= memcached_get(memc, key, strlen(key),
+                         &length, &flags, &rc);
+
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(value == NULL);
+    test_truth(length == 0);
+    test_truth(flags == 0);
+
+    value= memcached_get(memc, key, strlen(key),
+                         &length, &flags, &rc);
+
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(value == NULL);
+    test_truth(length == 0);
+    test_truth(flags == 0);
+  }
+
+  return TEST_SUCCESS;
+}
+
+/* Check the return sizes on FLAGS to make sure it stores 32bit unsigned values correctly */
+static test_return_t  user_supplied_bug16(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "mykey";
+  char *value;
+  size_t length;
+  uint32_t flags;
+
+  rc= memcached_set(memc, key, strlen(key),
+                    NULL, 0,
+                    (time_t)0, UINT32_MAX);
+
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_get(memc, key, strlen(key),
+                       &length, &flags, &rc);
+
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(value == NULL);
+  test_truth(length == 0);
+  test_truth(flags == UINT32_MAX);
+
+  return TEST_SUCCESS;
+}
+
+#ifndef __sun
+/* Check the validity of chinese key*/
+static test_return_t  user_supplied_bug17(memcached_st *memc)
+{
+    memcached_return_t rc;
+    const char *key= "豆瓣";
+    const char *value="我们在炎热抑郁的夏天无法停止豆瓣";
+    char *value2;
+    size_t length;
+    uint32_t flags;
+
+    rc= memcached_set(memc, key, strlen(key),
+            value, strlen(value),
+            (time_t)0, 0);
+
+    test_truth(rc == MEMCACHED_SUCCESS);
+
+    value2= memcached_get(memc, key, strlen(key),
+            &length, &flags, &rc);
+
+    test_truth(length==strlen(value));
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(memcmp(value, value2, length)==0);
+    free(value2);
+
+    return TEST_SUCCESS;
+}
+#endif
+
+/*
+  From Andrei on IRC
+*/
+
+static test_return_t user_supplied_bug19(memcached_st *memc)
+{
+  memcached_st *m;
+  memcached_server_st *s;
+  memcached_return_t res;
+
+  (void)memc;
+
+  m= memcached_create(NULL);
+  memcached_server_add_with_weight(m, "localhost", 11311, 100);
+  memcached_server_add_with_weight(m, "localhost", 11312, 100);
+
+  s= memcached_server_by_key(m, "a", 1, &res);
+  memcached_server_free(s);
+
+  memcached_free(m);
+
+  return TEST_SUCCESS;
+}
+
+/* CAS test from Andei */
+static test_return_t user_supplied_bug20(memcached_st *memc)
+{
+  memcached_return_t status;
+  memcached_result_st *result, result_obj;
+  const char *key = "abc";
+  size_t key_len = strlen("abc");
+  const char *value = "foobar";
+  size_t value_len = strlen(value);
+
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1);
+
+  status = memcached_set(memc, key, key_len, value, value_len, (time_t)0, (uint32_t)0);
+  test_truth(status == MEMCACHED_SUCCESS);
+
+  status = memcached_mget(memc, &key, &key_len, 1);
+  test_truth(status == MEMCACHED_SUCCESS);
+
+  result= memcached_result_create(memc, &result_obj);
+  test_truth(result);
+
+  memcached_result_create(memc, &result_obj);
+  result= memcached_fetch_result(memc, &result_obj, &status);
+
+  test_truth(result);
+  test_truth(status == MEMCACHED_SUCCESS);
+
+  memcached_result_free(result);
+
+  return TEST_SUCCESS;
+}
+
+#include "ketama_test_cases.h"
+static test_return_t user_supplied_bug18(memcached_st *trash)
+{
+  memcached_return_t rc;
+  uint64_t value;
+  int x;
+  memcached_server_st *server_pool;
+  memcached_st *memc;
+
+  (void)trash;
+
+  memc= memcached_create(NULL);
+  test_truth(memc);
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
+  test_truth(value == 1);
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
+  test_truth(value == MEMCACHED_HASH_MD5);
+
+  server_pool = memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
+  memcached_server_push(memc, server_pool);
+
+  /* verify that the server list was parsed okay. */
+  test_truth(memcached_server_count(memc) == 8);
+  test_truth(strcmp(server_pool[0].hostname, "10.0.1.1") == 0);
+  test_truth(server_pool[0].port == 11211);
+  test_truth(server_pool[0].weight == 600);
+  test_truth(strcmp(server_pool[2].hostname, "10.0.1.3") == 0);
+  test_truth(server_pool[2].port == 11211);
+  test_truth(server_pool[2].weight == 200);
+  test_truth(strcmp(server_pool[7].hostname, "10.0.1.8") == 0);
+  test_truth(server_pool[7].port == 11211);
+  test_truth(server_pool[7].weight == 100);
+
+  /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
+   * us test the boundary wraparound.
+   */
+  test_truth(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->continuum[0].index);
+
+  /* verify the standard ketama set. */
+  for (x= 0; x < 99; x++)
+  {
+    uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(memc, server_idx);
+    char *hostname = instance->hostname;
+    test_strcmp(hostname, ketama_test_cases[x].server);
+  }
+
+  memcached_server_list_free(server_pool);
+  memcached_free(memc);
+
+  return TEST_SUCCESS;
+}
+
+/* Large mget() of missing keys with binary proto
+ *
+ * If many binary quiet commands (such as getq's in an mget) fill the output
+ * buffer and the server chooses not to respond, memcached_flush hangs. See
+ * http://lists.tangent.org/pipermail/libmemcached/2009-August/000918.html
+ */
+
+/* sighandler_t function that always asserts false */
+static void fail(int unused __attribute__((unused)))
+{
+  assert(0);
+}
+
+
+static test_return_t  _user_supplied_bug21(memcached_st* memc, size_t key_count)
+{
+  memcached_return_t rc;
+  unsigned int x;
+  char **keys;
+  size_t* key_lengths;
+  void (*oldalarm)(int);
+  memcached_st *memc_clone;
+
+  memc_clone= memcached_clone(NULL, memc);
+  test_truth(memc_clone);
+
+  /* only binproto uses getq for mget */
+  memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
+
+  /* empty the cache to ensure misses (hence non-responses) */
+  rc= memcached_flush(memc_clone, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  key_lengths= calloc(key_count, sizeof(size_t));
+  keys= calloc(key_count, sizeof(char *));
+  test_truth(keys);
+  for (x= 0; x < key_count; x++)
+  {
+    char buffer[30];
+
+    snprintf(buffer, 30, "%u", x);
+    keys[x]= strdup(buffer);
+    key_lengths[x]= strlen(keys[x]);
+  }
+
+  oldalarm= signal(SIGALRM, fail);
+  alarm(5);
+
+  rc= memcached_mget(memc_clone, (const char **)keys, key_lengths, key_count);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  alarm(0);
+  signal(SIGALRM, oldalarm);
+
+  test_truth(fetch_all_results(memc) == TEST_SUCCESS);
+
+  for (x= 0; x < key_count; x++)
+    free(keys[x]);
+  free(keys);
+  free(key_lengths);
+
+  memcached_free(memc_clone);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t pre_binary(memcached_st *memc);
+
+static test_return_t user_supplied_bug21(memcached_st *memc)
+{
+  test_return_t test_rc;
+  test_rc= pre_binary(memc);
+
+  if (test_rc != TEST_SUCCESS)
+    return test_rc;
+
+  test_return_t rc;
+
+  /* should work as of r580 */
+  rc= _user_supplied_bug21(memc, 10);
+  test_truth(rc == TEST_SUCCESS);
+
+  /* should fail as of r580 */
+  rc= _user_supplied_bug21(memc, 1000);
+  test_truth(rc == TEST_SUCCESS);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t auto_eject_hosts(memcached_st *trash)
+{
+  (void) trash;
+  memcached_server_instance_st *instance;
+
+  memcached_return_t rc;
+  memcached_st *memc= memcached_create(NULL);
+  test_truth(memc);
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  uint64_t value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
+  test_truth(value == 1);
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
+  test_truth(value == MEMCACHED_HASH_MD5);
+
+    /* server should be removed when in delay */
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS);
+  test_truth(value == 1);
+
+  memcached_server_st *server_pool;
+  server_pool = memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
+  memcached_server_push(memc, server_pool);
+
+  /* verify that the server list was parsed okay. */
+  test_truth(memcached_server_count(memc) == 8);
+  test_truth(strcmp(server_pool[0].hostname, "10.0.1.1") == 0);
+  test_truth(server_pool[0].port == 11211);
+  test_truth(server_pool[0].weight == 600);
+  test_truth(strcmp(server_pool[2].hostname, "10.0.1.3") == 0);
+  test_truth(server_pool[2].port == 11211);
+  test_truth(server_pool[2].weight == 200);
+  test_truth(strcmp(server_pool[7].hostname, "10.0.1.8") == 0);
+  test_truth(server_pool[7].port == 11211);
+  test_truth(server_pool[7].weight == 100);
+
+  instance= memcached_server_instance_fetch(memc, 2);
+  instance->next_retry = time(NULL) + 15;
+  memc->next_distribution_rebuild= time(NULL) - 1;
+
+  for (size_t x= 0; x < 99; x++)
+  {
+    uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
+    test_truth(server_idx != 2);
+  }
+
+  /* and re-added when it's back. */
+  instance->next_retry = time(NULL) - 1;
+  memc->next_distribution_rebuild= time(NULL) - 1;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION,
+                         memc->distribution);
+  for (size_t x= 0; x < 99; x++)
+  {
+    uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
+    // We re-use instance from above.
+    instance=
+      memcached_server_instance_fetch(memc, server_idx);
+    char *hostname = instance->hostname;
+    test_truth(strcmp(hostname, ketama_test_cases[x].server) == 0);
+  }
+
+  memcached_server_list_free(server_pool);
+  memcached_free(memc);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t output_ketama_weighted_keys(memcached_st *trash)
+{
+  (void) trash;
+
+  memcached_return_t rc;
+  memcached_st *memc= memcached_create(NULL);
+  test_truth(memc);
+
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  uint64_t value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
+  test_truth(value == 1);
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
+  test_truth(value == MEMCACHED_HASH_MD5);
+
+
+  test_truth(memcached_behavior_set_distribution(memc, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY) == MEMCACHED_SUCCESS);
+
+  memcached_server_st *server_pool;
+  server_pool = memcached_servers_parse("10.0.1.1:11211,10.0.1.2:11211,10.0.1.3:11211,10.0.1.4:11211,10.0.1.5:11211,10.0.1.6:11211,10.0.1.7:11211,10.0.1.8:11211,192.168.1.1:11211,192.168.100.1:11211");
+  memcached_server_push(memc, server_pool);
+
+  // @todo this needs to be refactored to actually test something.
+#if 0
+  FILE *fp;
+  if ((fp = fopen("ketama_keys.txt", "w")))
+  {
+    // noop
+  } else {
+    printf("cannot write to file ketama_keys.txt");
+    return TEST_FAILURE;
+  }
+
+  for (int x= 0; x < 10000; x++)
+  {
+    char key[10];
+    sprintf(key, "%d", x);
+
+    uint32_t server_idx = memcached_generate_hash(memc, key, strlen(key));
+    char *hostname = memc->hosts[server_idx].hostname;
+    in_port_t port = memc->hosts[server_idx].port;
+    fprintf(fp, "key %s is on host /%s:%u\n", key, hostname, port);
+  }
+  fclose(fp);
+#endif
+  memcached_server_list_free(server_pool);
+  memcached_free(memc);
+
+  return TEST_SUCCESS;
+}
+
+
+static test_return_t  result_static(memcached_st *memc)
+{
+  memcached_result_st result;
+  memcached_result_st *result_ptr;
+
+  result_ptr= memcached_result_create(memc, &result);
+  test_truth(result.options.is_allocated == false);
+  test_truth(memcached_is_initialized(&result) == true);
+  test_truth(result_ptr);
+  test_truth(result_ptr == &result);
+
+  memcached_result_free(&result);
+
+  test_truth(result.options.is_allocated == false);
+  test_truth(memcached_is_initialized(&result) == false);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  result_alloc(memcached_st *memc)
+{
+  memcached_result_st *result_ptr;
+
+  result_ptr= memcached_result_create(memc, NULL);
+  test_truth(result_ptr);
+  test_truth(result_ptr->options.is_allocated == true);
+  test_truth(memcached_is_initialized(result_ptr) == true);
+  memcached_result_free(result_ptr);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  string_static_null(memcached_st *memc)
+{
+  memcached_string_st string;
+  memcached_string_st *string_ptr;
+
+  string_ptr= memcached_string_create(memc, &string, 0);
+  test_truth(string.options.is_initialized == true);
+  test_truth(string_ptr);
+
+  /* The following two better be the same! */
+  test_truth(memcached_is_allocated(string_ptr) == false);
+  test_truth(memcached_is_allocated(&string) == false);
+  test_truth(&string == string_ptr);
+
+  test_truth(string.options.is_initialized == true);
+  test_truth(memcached_is_initialized(&string) == true);
+  memcached_string_free(&string);
+  test_truth(memcached_is_initialized(&string) == false);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  string_alloc_null(memcached_st *memc)
+{
+  memcached_string_st *string;
+
+  string= memcached_string_create(memc, NULL, 0);
+  test_truth(string);
+  test_truth(memcached_is_allocated(string) == true);
+  test_truth(memcached_is_initialized(string) == true);
+  memcached_string_free(string);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  string_alloc_with_size(memcached_st *memc)
+{
+  memcached_string_st *string;
+
+  string= memcached_string_create(memc, NULL, 1024);
+  test_truth(string);
+  test_truth(memcached_is_allocated(string) == true);
+  test_truth(memcached_is_initialized(string) == true);
+  memcached_string_free(string);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  string_alloc_with_size_toobig(memcached_st *memc)
+{
+  memcached_string_st *string;
+
+  string= memcached_string_create(memc, NULL, SIZE_MAX);
+  test_truth(string == NULL);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  string_alloc_append(memcached_st *memc)
+{
+  unsigned int x;
+  char buffer[SMALL_STRING_LEN];
+  memcached_string_st *string;
+
+  /* Ring the bell! */
+  memset(buffer, 6, SMALL_STRING_LEN);
+
+  string= memcached_string_create(memc, NULL, 100);
+  test_truth(string);
+  test_truth(memcached_is_allocated(string) == true);
+  test_truth(memcached_is_initialized(string) == true);
+
+  for (x= 0; x < 1024; x++)
+  {
+    memcached_return_t rc;
+    rc= memcached_string_append(string, buffer, SMALL_STRING_LEN);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+  test_truth(memcached_is_allocated(string) == true);
+  memcached_string_free(string);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  string_alloc_append_toobig(memcached_st *memc)
+{
+  memcached_return_t rc;
+  unsigned int x;
+  char buffer[SMALL_STRING_LEN];
+  memcached_string_st *string;
+
+  /* Ring the bell! */
+  memset(buffer, 6, SMALL_STRING_LEN);
+
+  string= memcached_string_create(memc, NULL, 100);
+  test_truth(string);
+  test_truth(memcached_is_allocated(string) == true);
+  test_truth(memcached_is_initialized(string) == true);
+
+  for (x= 0; x < 1024; x++)
+  {
+    rc= memcached_string_append(string, buffer, SMALL_STRING_LEN);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+  rc= memcached_string_append(string, buffer, SIZE_MAX);
+  test_truth(rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE);
+  test_truth(memcached_is_allocated(string) == true);
+  memcached_string_free(string);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  cleanup_pairs(memcached_st *memc __attribute__((unused)))
+{
+  pairs_free(global_pairs);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  generate_pairs(memcached_st *memc __attribute__((unused)))
+{
+  global_pairs= pairs_generate(GLOBAL_COUNT, 400);
+  global_count= GLOBAL_COUNT;
+
+  for (size_t x= 0; x < global_count; x++)
+  {
+    global_keys[x]= global_pairs[x].key;
+    global_keys_length[x]=  global_pairs[x].key_length;
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  generate_large_pairs(memcached_st *memc __attribute__((unused)))
+{
+  global_pairs= pairs_generate(GLOBAL2_COUNT, MEMCACHED_MAX_BUFFER+10);
+  global_count= GLOBAL2_COUNT;
+
+  for (size_t x= 0; x < global_count; x++)
+  {
+    global_keys[x]= global_pairs[x].key;
+    global_keys_length[x]=  global_pairs[x].key_length;
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  generate_data(memcached_st *memc)
+{
+  execute_set(memc, global_pairs, global_count);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  generate_data_with_stats(memcached_st *memc)
+{
+  memcached_stat_st *stat_p;
+  memcached_return_t rc;
+  uint32_t host_index= 0;
+  execute_set(memc, global_pairs, global_count);
+
+  //TODO: hosts used size stats
+  stat_p= memcached_stat(memc, NULL, &rc);
+  test_truth(stat_p);
+
+  for (host_index= 0; host_index < SERVERS_TO_CREATE; host_index++)
+  {
+    /* This test was changes so that "make test" would work properlly */
+#ifdef DEBUG
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(memc, host_index);
+
+    printf("\nserver %u|%s|%u bytes: %llu\n", host_index, instance->hostname, instance->port, (unsigned long long)(stat_p + host_index)->bytes);
+#endif
+    test_truth((unsigned long long)(stat_p + host_index)->bytes);
+  }
+
+  memcached_stat_free(NULL, stat_p);
+
+  return TEST_SUCCESS;
+}
+static test_return_t  generate_buffer_data(memcached_st *memc)
+{
+  size_t latch= 0;
+
+  latch= 1;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, latch);
+  generate_data(memc);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  get_read_count(memcached_st *memc)
+{
+  memcached_return_t rc;
+  memcached_st *memc_clone;
+
+  memc_clone= memcached_clone(NULL, memc);
+  test_truth(memc_clone);
+
+  memcached_server_add_with_weight(memc_clone, "localhost", 6666, 0);
+
+  {
+    char *return_value;
+    size_t return_value_length;
+    uint32_t flags;
+    uint32_t count;
+
+    for (size_t x= count= 0; x < global_count; x++)
+    {
+      return_value= memcached_get(memc_clone, global_keys[x], global_keys_length[x],
+                                  &return_value_length, &flags, &rc);
+      if (rc == MEMCACHED_SUCCESS)
+      {
+        count++;
+        if (return_value)
+          free(return_value);
+      }
+    }
+  }
+
+  memcached_free(memc_clone);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  get_read(memcached_st *memc)
+{
+  memcached_return_t rc;
+
+  {
+    char *return_value;
+    size_t return_value_length;
+    uint32_t flags;
+
+    for (size_t x= 0; x < global_count; x++)
+    {
+      return_value= memcached_get(memc, global_keys[x], global_keys_length[x],
+                                  &return_value_length, &flags, &rc);
+      /*
+      test_truth(return_value);
+      test_truth(rc == MEMCACHED_SUCCESS);
+    */
+      if (rc == MEMCACHED_SUCCESS && return_value)
+        free(return_value);
+    }
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  mget_read(memcached_st *memc)
+{
+  memcached_return_t rc;
+
+  rc= memcached_mget(memc, global_keys, global_keys_length, global_count);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(fetch_all_results(memc) == TEST_SUCCESS);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  mget_read_result(memcached_st *memc)
+{
+  memcached_return_t rc;
+
+  rc= memcached_mget(memc, global_keys, global_keys_length, global_count);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  /* Turn this into a help function */
+  {
+    memcached_result_st results_obj;
+    memcached_result_st *results;
+
+    results= memcached_result_create(memc, &results_obj);
+
+    while ((results= memcached_fetch_result(memc, &results_obj, &rc)))
+    {
+      test_truth(results);
+      test_truth(rc == MEMCACHED_SUCCESS);
+    }
+
+    memcached_result_free(&results_obj);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  mget_read_function(memcached_st *memc)
+{
+  memcached_return_t rc;
+  size_t counter;
+  memcached_execute_fn callbacks[1];
+
+  rc= memcached_mget(memc, global_keys, global_keys_length, global_count);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  callbacks[0]= &callback_counter;
+  counter= 0;
+  rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  delete_generate(memcached_st *memc)
+{
+  for (size_t x= 0; x < global_count; x++)
+  {
+    (void)memcached_delete(memc, global_keys[x], global_keys_length[x], (time_t)0);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  delete_buffer_generate(memcached_st *memc)
+{
+  uint64_t latch= 0;
+
+  latch= 1;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, latch);
+
+  for (size_t x= 0; x < global_count; x++)
+  {
+    (void)memcached_delete(memc, global_keys[x], global_keys_length[x], (time_t)0);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  add_host_test1(memcached_st *memc)
+{
+  memcached_return_t rc;
+  char servername[]= "0.example.com";
+  memcached_server_st *servers;
+
+  servers= memcached_server_list_append_with_weight(NULL, servername, 400, 0, &rc);
+  test_truth(servers);
+  test_truth(1 == memcached_server_list_count(servers));
+
+  for (size_t x= 2; x < 20; x++)
+  {
+    char buffer[SMALL_STRING_LEN];
+
+    snprintf(buffer, SMALL_STRING_LEN, "%zu.example.com", 400+x);
+    servers= memcached_server_list_append_with_weight(servers, buffer, 401, 0,
+                                     &rc);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(x == memcached_server_list_count(servers));
+  }
+
+  rc= memcached_server_push(memc, servers);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  rc= memcached_server_push(memc, servers);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  memcached_server_list_free(servers);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t pre_nonblock(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t pre_cork(memcached_st *memc)
+{
+  memcached_return_t rc;
+  bool set= true;
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_CORK, set);
+
+  if (rc == MEMCACHED_SUCCESS)
+    return TEST_SUCCESS;
+
+  return TEST_SKIPPED;
+}
+
+static test_return_t pre_cork_and_nonblock(memcached_st *memc)
+{
+  test_return_t rc;
+  
+  rc= pre_cork(memc);
+
+  if (rc != TEST_SUCCESS)
+    return rc;
+
+  return pre_nonblock(memc);
+}
+
+static test_return_t pre_nonblock_binary(memcached_st *memc)
+{
+  memcached_return_t rc= MEMCACHED_FAILURE;
+  memcached_st *memc_clone;
+  memcached_server_instance_st *instance;
+
+  memc_clone= memcached_clone(NULL, memc);
+  test_truth(memc_clone);
+  // The memcached_version needs to be done on a clone, because the server
+  // will not toggle protocol on an connection.
+  memcached_version(memc_clone);
+
+  instance= memcached_server_instance_fetch(memc_clone, 0);
+
+  if (instance->major_version >= 1 && instance->minor_version > 2)
+  {
+    memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
+    rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1);
+  }
+  else
+  {
+    return TEST_SKIPPED;
+  }
+
+  memcached_free(memc_clone);
+
+  return rc == MEMCACHED_SUCCESS ? TEST_SUCCESS : TEST_SKIPPED;
+}
+
+static test_return_t pre_murmur(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_MURMUR);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t pre_jenkins(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_JENKINS);
+
+  return TEST_SUCCESS;
+}
+
+
+static test_return_t pre_md5(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_MD5);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t pre_crc(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_CRC);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t pre_hsieh(memcached_st *memc)
+{
+#ifdef HAVE_HSIEH_HASH
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_HSIEH);
+  return TEST_SUCCESS;
+#else
+  (void) memc;
+  return TEST_SKIPPED;
+#endif
+}
+
+static test_return_t pre_hash_fnv1_64(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_MURMUR);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t pre_hash_fnv1a_64(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_FNV1A_64);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t pre_hash_fnv1_32(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_FNV1_32);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t pre_hash_fnv1a_32(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, (uint64_t)MEMCACHED_HASH_FNV1A_32);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t pre_behavior_ketama(memcached_st *memc)
+{
+  memcached_return_t rc;
+  uint64_t value;
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA);
+  test_truth(value == 1);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t pre_behavior_ketama_weighted(memcached_st *memc)
+{
+  memcached_return_t rc;
+  uint64_t value;
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
+  test_truth(value == 1);
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
+  test_truth(value == MEMCACHED_HASH_MD5);
+
+  return TEST_SUCCESS;
+}
+
+/**
+  @note This should be testing to see if the server really supports the binary protocol.
+*/
+static test_return_t pre_binary(memcached_st *memc)
+{
+  memcached_return_t rc= MEMCACHED_FAILURE;
+  memcached_st *memc_clone;
+  memcached_server_instance_st *instance;
+
+  memc_clone= memcached_clone(NULL, memc);
+  test_truth(memc_clone);
+  // The memcached_version needs to be done on a clone, because the server
+  // will not toggle protocol on an connection.
+  memcached_version(memc_clone);
+
+  instance= memcached_server_instance_fetch(memc_clone, 0);
+
+  if (instance->major_version >= 1 && instance->minor_version > 2)
+  {
+    rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) == 1);
+  }
+
+  memcached_free(memc_clone);
+
+  return rc == MEMCACHED_SUCCESS ? TEST_SUCCESS : TEST_SKIPPED;
+}
+
+
+static test_return_t pre_replication(memcached_st *memc)
+{
+  test_return_t test_rc;
+  test_rc= pre_binary(memc);
+
+  if (test_rc != TEST_SUCCESS)
+    return test_rc;
+
+  /*
+   * Make sure that we store the item on all servers
+   * (master + replicas == number of servers)
+   */
+  memcached_return_t rc;
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS,
+                             memcached_server_count(memc) - 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS) == memcached_server_count(memc) - 1);
+
+  return rc == MEMCACHED_SUCCESS ? TEST_SUCCESS : TEST_SKIPPED;
+}
+
+
+static test_return_t pre_replication_noblock(memcached_st *memc)
+{
+  test_return_t rc;
+
+  rc= pre_replication(memc);
+  if (rc != TEST_SUCCESS)
+    return rc;
+
+  rc= pre_nonblock(memc);
+
+  return rc;
+}
+
+
+static void my_free(memcached_st *ptr __attribute__((unused)), void *mem)
+{
+#ifdef HARD_MALLOC_TESTS
+  void *real_ptr= (mem == NULL) ? mem : (void*)((caddr_t)mem - 8);
+  free(real_ptr);
+#else
+  free(mem);
+#endif
+}
+
+
+static void *my_malloc(memcached_st *ptr __attribute__((unused)), const size_t size)
+{
+#ifdef HARD_MALLOC_TESTS
+  void *ret= malloc(size + 8);
+  if (ret != NULL)
+  {
+    ret= (void*)((caddr_t)ret + 8);
+  }
+#else
+  void *ret= malloc(size);
+#endif
+
+  if (ret != NULL)
+  {
+    memset(ret, 0xff, size);
+  }
+
+  return ret;
+}
+
+
+static void *my_realloc(memcached_st *ptr __attribute__((unused)), void *mem, const size_t size)
+{
+#ifdef HARD_MALLOC_TESTS
+  void *real_ptr= (mem == NULL) ? NULL : (void*)((caddr_t)mem - 8);
+  void *nmem= realloc(real_ptr, size + 8);
+
+  void *ret= NULL;
+  if (nmem != NULL)
+  {
+    ret= (void*)((caddr_t)nmem + 8);
+  }
+
+  return ret;
+#else
+  return realloc(mem, size);
+#endif
+}
+
+
+static void *my_calloc(memcached_st *ptr __attribute__((unused)), size_t nelem, const size_t size)
+{
+#ifdef HARD_MALLOC_TESTS
+  void *mem= my_malloc(ptr, nelem * size);
+  if (mem)
+  {
+    memset(mem, 0, nelem * size);
+  }
+
+  return mem;
+#else
+  return calloc(nelem, size);
+#endif
+}
+
+
+static test_return_t set_prefix(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "mine";
+  char *value;
+
+  /* Make sure be default none exists */
+  value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+  test_truth(rc == MEMCACHED_FAILURE);
+
+  /* Test a clean set */
+  rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, (void *)key);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+  test_truth(memcmp(value, key, 4) == 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  /* Test that we can turn it off */
+  rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, NULL);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+  test_truth(rc == MEMCACHED_FAILURE);
+
+  /* Now setup for main test */
+  rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, (void *)key);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(memcmp(value, key, 4) == 0);
+
+  /* Set to Zero, and then Set to something too large */
+  {
+    char long_key[255];
+    memset(long_key, 0, 255);
+
+    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, NULL);
+    test_truth(rc == MEMCACHED_SUCCESS);
+
+    value= memcached_callback_get(memc, MEMCACHED_CALLBACK_PREFIX_KEY, &rc);
+    test_truth(rc == MEMCACHED_FAILURE);
+    test_truth(value == NULL);
+
+    /* Test a long key for failure */
+    /* TODO, extend test to determine based on setting, what result should be */
+    strcpy(long_key, "Thisismorethentheallottednumberofcharacters");
+    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, long_key);
+    //test_truth(rc == MEMCACHED_BAD_KEY_PROVIDED);
+    test_truth(rc == MEMCACHED_SUCCESS);
+
+    /* Now test a key with spaces (which will fail from long key, since bad key is not set) */
+    strcpy(long_key, "This is more then the allotted number of characters");
+    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, long_key);
+    test_truth(rc == MEMCACHED_BAD_KEY_PROVIDED);
+
+    /* Test for a bad prefix, but with a short key */
+    rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_VERIFY_KEY, 1);
+    test_truth(rc == MEMCACHED_SUCCESS);
+
+    strcpy(long_key, "dog cat");
+    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_PREFIX_KEY, long_key);
+    test_truth(rc == MEMCACHED_BAD_KEY_PROVIDED);
+  }
+
+  return TEST_SUCCESS;
+}
+
+
+#ifdef MEMCACHED_ENABLE_DEPRECATED
+static test_return_t deprecated_set_memory_alloc(memcached_st *memc)
+{
+  void *test_ptr= NULL;
+  void *cb_ptr= NULL;
+  {
+    memcached_malloc_fn malloc_cb=
+      (memcached_malloc_fn)my_malloc;
+    cb_ptr= *(void **)&malloc_cb;
+    memcached_return_t rc;
+
+    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_MALLOC_FUNCTION, cb_ptr);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_ptr= memcached_callback_get(memc, MEMCACHED_CALLBACK_MALLOC_FUNCTION, &rc);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(test_ptr == cb_ptr);
+  }
+
+  {
+    memcached_realloc_fn realloc_cb=
+      (memcached_realloc_fn)my_realloc;
+    cb_ptr= *(void **)&realloc_cb;
+    memcached_return_t rc;
+
+    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_REALLOC_FUNCTION, cb_ptr);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_ptr= memcached_callback_get(memc, MEMCACHED_CALLBACK_REALLOC_FUNCTION, &rc);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(test_ptr == cb_ptr);
+  }
+
+  {
+    memcached_free_fn free_cb=
+      (memcached_free_fn)my_free;
+    cb_ptr= *(void **)&free_cb;
+    memcached_return_t rc;
+
+    rc= memcached_callback_set(memc, MEMCACHED_CALLBACK_FREE_FUNCTION, cb_ptr);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_ptr= memcached_callback_get(memc, MEMCACHED_CALLBACK_FREE_FUNCTION, &rc);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(test_ptr == cb_ptr);
+  }
+
+  return TEST_SUCCESS;
+}
+#endif
+
+
+static test_return_t set_memory_alloc(memcached_st *memc)
+{
+  memcached_return_t rc;
+  rc= memcached_set_memory_allocators(memc, NULL, my_free,
+                                      my_realloc, my_calloc);
+  test_truth(rc == MEMCACHED_FAILURE);
+
+  rc= memcached_set_memory_allocators(memc, my_malloc, my_free,
+                                      my_realloc, my_calloc);
+
+  memcached_malloc_fn mem_malloc;
+  memcached_free_fn mem_free;
+  memcached_realloc_fn mem_realloc;
+  memcached_calloc_fn mem_calloc;
+  memcached_get_memory_allocators(memc, &mem_malloc, &mem_free,
+                                  &mem_realloc, &mem_calloc);
+
+  test_truth(mem_malloc == my_malloc);
+  test_truth(mem_realloc == my_realloc);
+  test_truth(mem_calloc == my_calloc);
+  test_truth(mem_free == my_free);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t enable_consistent_crc(memcached_st *memc)
+{
+  test_return_t rc;
+  memcached_server_distribution_t value= MEMCACHED_DISTRIBUTION_CONSISTENT;
+  memcached_hash_t hash;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, value);
+  if ((rc= pre_crc(memc)) != TEST_SUCCESS)
+    return rc;
+
+  value= (memcached_server_distribution_t)memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION);
+  test_truth(value == MEMCACHED_DISTRIBUTION_CONSISTENT);
+
+  hash= (memcached_hash_t)memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_HASH);
+
+  if (hash != MEMCACHED_HASH_CRC)
+    return TEST_SKIPPED;
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t enable_consistent_hsieh(memcached_st *memc)
+{
+  test_return_t rc;
+  memcached_server_distribution_t value= MEMCACHED_DISTRIBUTION_CONSISTENT;
+  memcached_hash_t hash;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, value);
+  if ((rc= pre_hsieh(memc)) != TEST_SUCCESS)
+    return rc;
+
+  value= (memcached_server_distribution_t)memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION);
+  test_truth(value == MEMCACHED_DISTRIBUTION_CONSISTENT);
+
+  hash= (memcached_hash_t)memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_HASH);
+
+  if (hash != MEMCACHED_HASH_HSIEH)
+    return TEST_SKIPPED;
+
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t enable_cas(memcached_st *memc)
+{
+  unsigned int set= 1;
+
+  memcached_server_instance_st *instance=
+    memcached_server_instance_fetch(memc, 0);
+
+  memcached_version(memc);
+
+  if ((instance->major_version >= 1 && (instance->minor_version == 2 && instance->micro_version >= 4))
+      || instance->minor_version > 2)
+  {
+    memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, set);
+
+    return TEST_SUCCESS;
+  }
+
+  return TEST_SKIPPED;
+}
+
+static test_return_t  check_for_1_2_3(memcached_st *memc)
+{
+  memcached_version(memc);
+  memcached_server_instance_st *instance=
+    memcached_server_instance_fetch(memc, 0);
+
+  if ((instance->major_version >= 1 && (instance->minor_version == 2 && instance->micro_version >= 4))
+      || instance->minor_version > 2)
+    return TEST_SUCCESS;
+
+  return TEST_SKIPPED;
+}
+
+static test_return_t  pre_unix_socket(memcached_st *memc)
+{
+  memcached_return_t rc;
+  struct stat buf;
+
+  memcached_servers_reset(memc);
+
+  if (stat("/tmp/memcached.socket", &buf))
+    return TEST_SKIPPED;
+
+  rc= memcached_server_add_unix_socket_with_weight(memc, "/tmp/memcached.socket", 0);
+
+  return ( rc == MEMCACHED_SUCCESS ? TEST_SUCCESS : TEST_FAILURE );
+}
+
+static test_return_t  pre_nodelay(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 0);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  pre_settimer(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SND_TIMEOUT, 1000);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RCV_TIMEOUT, 1000);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t  poll_timeout(memcached_st *memc)
+{
+  size_t timeout;
+
+  timeout= 100;
+
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, timeout);
+
+  timeout= (size_t)memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT);
+
+  test_truth(timeout == 100);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t noreply_test(memcached_st *memc)
+{
+  memcached_return_t ret;
+  ret= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 1);
+  test_truth(ret == MEMCACHED_SUCCESS);
+  ret= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
+  test_truth(ret == MEMCACHED_SUCCESS);
+  ret= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1);
+  test_truth(ret == MEMCACHED_SUCCESS);
+  test_truth(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NOREPLY) == 1);
+  test_truth(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS) == 1);
+  test_truth(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS) == 1);
+
+  for (int count=0; count < 5; ++count)
+  {
+    for (size_t x= 0; x < 100; ++x)
+    {
+      char key[10];
+      size_t len= (size_t)sprintf(key, "%zu", x);
+      switch (count)
+      {
+      case 0:
+        ret= memcached_add(memc, key, len, key, len, 0, 0);
+        break;
+      case 1:
+        ret= memcached_replace(memc, key, len, key, len, 0, 0);
+        break;
+      case 2:
+        ret= memcached_set(memc, key, len, key, len, 0, 0);
+        break;
+      case 3:
+        ret= memcached_append(memc, key, len, key, len, 0, 0);
+        break;
+      case 4:
+        ret= memcached_prepend(memc, key, len, key, len, 0, 0);
+        break;
+      default:
+        test_truth(count);
+        break;
+      }
+      test_truth(ret == MEMCACHED_SUCCESS || ret == MEMCACHED_BUFFERED);
+    }
+
+    /*
+    ** NOTE: Don't ever do this in your code! this is not a supported use of the
+    ** API and is _ONLY_ done this way to verify that the library works the
+    ** way it is supposed to do!!!!
+    */
+    int no_msg=0;
+    for (uint32_t x= 0; x < memcached_server_count(memc); ++x)
+    {
+      memcached_server_instance_st *instance=
+        memcached_server_instance_fetch(memc, x);
+      no_msg+=(int)(instance->cursor_active);
+    }
+
+    test_truth(no_msg == 0);
+    test_truth(memcached_flush_buffers(memc) == MEMCACHED_SUCCESS);
+
+    /*
+     ** Now validate that all items was set properly!
+     */
+    for (size_t x= 0; x < 100; ++x)
+    {
+      char key[10];
+
+      size_t len= (size_t)sprintf(key, "%zu", x);
+      size_t length;
+      uint32_t flags;
+      char* value=memcached_get(memc, key, strlen(key),
+                                &length, &flags, &ret);
+      test_truth(ret == MEMCACHED_SUCCESS && value != NULL);
+      switch (count)
+      {
+      case 0: /* FALLTHROUGH */
+      case 1: /* FALLTHROUGH */
+      case 2:
+        test_truth(strncmp(value, key, len) == 0);
+        test_truth(len == length);
+        break;
+      case 3:
+        test_truth(length == len * 2);
+        break;
+      case 4:
+        test_truth(length == len * 3);
+        break;
+      default:
+        test_truth(count);
+        break;
+      }
+      free(value);
+    }
+  }
+
+  /* Try setting an illegal cas value (should not return an error to
+   * the caller (because we don't expect a return message from the server)
+   */
+  const char* keys[]= {"0"};
+  size_t lengths[]= {1};
+  size_t length;
+  uint32_t flags;
+  memcached_result_st results_obj;
+  memcached_result_st *results;
+  ret= memcached_mget(memc, keys, lengths, 1);
+  test_truth(ret == MEMCACHED_SUCCESS);
+
+  results= memcached_result_create(memc, &results_obj);
+  test_truth(results);
+  results= memcached_fetch_result(memc, &results_obj, &ret);
+  test_truth(results);
+  test_truth(ret == MEMCACHED_SUCCESS);
+  uint64_t cas= memcached_result_cas(results);
+  memcached_result_free(&results_obj);
+
+  ret= memcached_cas(memc, keys[0], lengths[0], keys[0], lengths[0], 0, 0, cas);
+  test_truth(ret == MEMCACHED_SUCCESS);
+
+  /*
+   * The item will have a new cas value, so try to set it again with the old
+   * value. This should fail!
+   */
+  ret= memcached_cas(memc, keys[0], lengths[0], keys[0], lengths[0], 0, 0, cas);
+  test_truth(ret == MEMCACHED_SUCCESS);
+  test_truth(memcached_flush_buffers(memc) == MEMCACHED_SUCCESS);
+  char* value=memcached_get(memc, keys[0], lengths[0], &length, &flags, &ret);
+  test_truth(ret == MEMCACHED_SUCCESS && value != NULL);
+  free(value);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t analyzer_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  memcached_stat_st *memc_stat;
+  memcached_analysis_st *report;
+
+  memc_stat= memcached_stat(memc, NULL, &rc);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(memc_stat);
+
+  report= memcached_analyze(memc, memc_stat, &rc);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(report);
+
+  free(report);
+  memcached_stat_free(NULL, memc_stat);
+
+  return TEST_SUCCESS;
+}
+
+/* Count the objects */
+static memcached_return_t callback_dump_counter(memcached_st *ptr __attribute__((unused)),
+                                              const char *key __attribute__((unused)),
+                                              size_t key_length __attribute__((unused)),
+                                              void *context)
+{
+  size_t *counter= (size_t *)context;
+
+  *counter= *counter + 1;
+
+  return MEMCACHED_SUCCESS;
+}
+
+static test_return_t dump_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  size_t counter= 0;
+  memcached_dump_fn callbacks[1];
+  test_return_t main_rc;
+
+  callbacks[0]= &callback_dump_counter;
+
+  /* No support for Binary protocol yet */
+  if (memc->flags.binary_protocol)
+    return TEST_SUCCESS;
+
+  main_rc= set_test3(memc);
+
+  test_truth (main_rc == TEST_SUCCESS);
+
+  rc= memcached_dump(memc, callbacks, (void *)&counter, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  /* We may have more then 32 if our previous flush has not completed */
+  test_truth(counter >= 32);
+
+  return TEST_SUCCESS;
+}
+
+#ifdef HAVE_LIBMEMCACHEDUTIL
+static void* connection_release(void *arg)
+{
+  struct {
+    memcached_pool_st* pool;
+    memcached_st* mmc;
+  } *resource= arg;
+
+  usleep(250);
+  assert(memcached_pool_push(resource->pool, resource->mmc) == MEMCACHED_SUCCESS);
+  return arg;
+}
+
+static test_return_t connection_pool_test(memcached_st *memc)
+{
+  memcached_pool_st* pool= memcached_pool_create(memc, 5, 10);
+  test_truth(pool != NULL);
+  memcached_st* mmc[10];
+  memcached_return_t rc;
+
+  for (size_t x= 0; x < 10; ++x)
+  {
+    mmc[x]= memcached_pool_pop(pool, false, &rc);
+    test_truth(mmc[x] != NULL);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  test_truth(memcached_pool_pop(pool, false, &rc) == NULL);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  pthread_t tid;
+  struct {
+    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_truth(rc == MEMCACHED_SUCCESS);
+  pthread_join(tid, NULL);
+  test_truth(mmc[9] == item.mmc);
+  const char *key= "key";
+  size_t keylen= strlen(key);
+
+  // verify that I can do ops with all connections
+  rc= memcached_set(mmc[0], key, keylen, "0", 1, 0, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  for (size_t x= 0; x < 10; ++x) 
+  {
+    uint64_t number_value;
+    rc= memcached_increment(mmc[x], key, keylen, 1, &number_value);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(number_value == (x+1));
+  }
+
+  // Release them..
+  for (size_t x= 0; x < 10; ++x)
+  {
+    test_truth(memcached_pool_push(pool, mmc[x]) == MEMCACHED_SUCCESS);
+  }
+
+
+  /* verify that I can set behaviors on the pool when I don't have all
+   * of the connections in the pool. It should however be enabled
+   * when I push the item into the pool
+   */
+  mmc[0]= memcached_pool_pop(pool, false, &rc);
+  test_truth(mmc[0] != NULL);
+
+  rc= memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK, 9999);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  mmc[1]= memcached_pool_pop(pool, false, &rc);
+  test_truth(mmc[1] != NULL);
+
+  test_truth(memcached_behavior_get(mmc[1], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK) == 9999);
+  test_truth(memcached_pool_push(pool, mmc[1]) == MEMCACHED_SUCCESS);
+  test_truth(memcached_pool_push(pool, mmc[0]) == MEMCACHED_SUCCESS);
+
+  mmc[0]= memcached_pool_pop(pool, false, &rc);
+  test_truth(memcached_behavior_get(mmc[0], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK) == 9999);
+  test_truth(memcached_pool_push(pool, mmc[0]) == MEMCACHED_SUCCESS);
+
+
+  test_truth(memcached_pool_destroy(pool) == memc);
+  return TEST_SUCCESS;
+}
+#endif
+
+static test_return_t replication_set_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  memcached_st *memc_clone= memcached_clone(NULL, memc);
+  memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 0);
+
+  rc= memcached_set(memc, "bubba", 5, "0", 1, 0, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  /*
+  ** We are using the quiet commands to store the replicas, so we need
+  ** to ensure that all of them are processed before we can continue.
+  ** In the test we go directly from storing the object to trying to
+  ** receive the object from all of the different servers, so we
+  ** could end up in a race condition (the memcached server hasn't yet
+  ** processed the quiet command from the replication set when it process
+  ** the request from the other client (created by the clone)). As a
+  ** workaround for that we call memcached_quit to send the quit command
+  ** to the server and wait for the response ;-) If you use the test code
+  ** as an example for your own code, please note that you shouldn't need
+  ** to do this ;-)
+  */
+  memcached_quit(memc);
+
+  /*
+  ** "bubba" should now be stored on all of our servers. We don't have an
+  ** easy to use API to address each individual server, so I'll just iterate
+  ** through a bunch of "master keys" and I should most likely hit all of the
+  ** servers...
+  */
+  for (int x= 'a'; x <= 'z'; ++x)
+  {
+    char key[2]= { [0]= (char)x };
+    size_t len;
+    uint32_t flags;
+    char *val= memcached_get_by_key(memc_clone, key, 1, "bubba", 5,
+                                    &len, &flags, &rc);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    test_truth(val != NULL);
+    free(val);
+  }
+
+  memcached_free(memc_clone);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t replication_get_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+
+  /*
+   * Don't do the following in your code. I am abusing the internal details
+   * within the library, and this is not a supported interface.
+   * This is to verify correct behavior in the library
+   */
+  for (uint32_t host= 0; host < memcached_server_count(memc); ++host)
+  {
+    memcached_st *memc_clone= memcached_clone(NULL, memc);
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(memc_clone, host);
+
+    instance->port= 0;
+
+    for (int x= 'a'; x <= 'z'; ++x)
+    {
+      char key[2]= { [0]= (char)x };
+      size_t len;
+      uint32_t flags;
+      char *val= memcached_get_by_key(memc_clone, key, 1, "bubba", 5,
+                                      &len, &flags, &rc);
+      test_truth(rc == MEMCACHED_SUCCESS);
+      test_truth(val != NULL);
+      free(val);
+    }
+
+    memcached_free(memc_clone);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t replication_mget_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  memcached_st *memc_clone= memcached_clone(NULL, memc);
+  memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 0);
+
+  const char *keys[]= { "bubba", "key1", "key2", "key3" };
+  size_t len[]= { 5, 4, 4, 4 };
+
+  for (size_t x= 0; x< 4; ++x)
+  {
+    rc= memcached_set(memc, keys[x], len[x], "0", 1, 0, 0);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  /*
+  ** We are using the quiet commands to store the replicas, so we need
+  ** to ensure that all of them are processed before we can continue.
+  ** In the test we go directly from storing the object to trying to
+  ** receive the object from all of the different servers, so we
+  ** could end up in a race condition (the memcached server hasn't yet
+  ** processed the quiet command from the replication set when it process
+  ** the request from the other client (created by the clone)). As a
+  ** workaround for that we call memcached_quit to send the quit command
+  ** to the server and wait for the response ;-) If you use the test code
+  ** as an example for your own code, please note that you shouldn't need
+  ** to do this ;-)
+  */
+  memcached_quit(memc);
+
+  /*
+   * Don't do the following in your code. I am abusing the internal details
+   * within the library, and this is not a supported interface.
+   * This is to verify correct behavior in the library
+   */
+  memcached_result_st result_obj;
+  for (uint32_t host= 0; host < memc_clone->number_of_hosts; host++)
+  {
+    memcached_st *new_clone= memcached_clone(NULL, memc);
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(new_clone, host);
+    instance->port= 0;
+
+    for (int x= 'a'; x <= 'z'; ++x)
+    {
+      char key[2]= { [0]= (char)x, [1]= 0 };
+
+      rc= memcached_mget_by_key(new_clone, key, 1, keys, len, 4);
+      test_truth(rc == MEMCACHED_SUCCESS);
+
+      memcached_result_st *results= memcached_result_create(new_clone, &result_obj);
+      test_truth(results);
+
+      int hits= 0;
+      while ((results= memcached_fetch_result(new_clone, &result_obj, &rc)) != NULL)
+      {
+        hits++;
+      }
+      test_truth(hits == 4);
+      memcached_result_free(&result_obj);
+    }
+
+    memcached_free(new_clone);
+  }
+
+  memcached_free(memc_clone);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t replication_randomize_mget_test(memcached_st *memc)
+{
+  memcached_result_st result_obj;
+  memcached_return_t rc;
+  memcached_st *memc_clone= memcached_clone(NULL, memc);
+  memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 3);
+  memcached_behavior_set(memc_clone, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ, 1);
+
+  const char *keys[]= { "key1", "key2", "key3", "key4", "key5", "key6", "key7" };
+  size_t len[]= { 4, 4, 4, 4, 4, 4, 4 };
+
+  for (int x=0; x< 7; ++x)
+  {
+    rc= memcached_set(memc, keys[x], len[x], "1", 1, 0, 0);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  memcached_quit(memc);
+
+  for (size_t x= 0; x< 7; ++x)
+  {
+    const char key[2]= { [0]= (const char)x };
+
+    rc= memcached_mget_by_key(memc_clone, key, 1, keys, len, 7);
+    test_truth(rc == MEMCACHED_SUCCESS);
+
+    memcached_result_st *results= memcached_result_create(memc_clone, &result_obj);
+    test_truth(results);
+
+    int hits= 0;
+    while ((results= memcached_fetch_result(memc_clone, &result_obj, &rc)) != NULL)
+    {
+      ++hits;
+    }
+    test_truth(hits == 7);
+    memcached_result_free(&result_obj);
+  }
+  memcached_free(memc_clone);
+  return TEST_SUCCESS;
+}
+
+static test_return_t replication_delete_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  memcached_st *memc_clone= memcached_clone(NULL, memc);
+  /* Delete the items from all of the servers except 1 */
+  uint64_t repl= memcached_behavior_get(memc,
+                                        MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, --repl);
+
+  const char *keys[]= { "bubba", "key1", "key2", "key3" };
+  size_t len[]= { 5, 4, 4, 4 };
+
+  for (size_t x= 0; x< 4; ++x)
+  {
+    rc= memcached_delete_by_key(memc, keys[0], len[0], keys[x], len[x], 0);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  /*
+   * Don't do the following in your code. I am abusing the internal details
+   * within the library, and this is not a supported interface.
+   * This is to verify correct behavior in the library
+   */
+  uint32_t hash= memcached_generate_hash(memc, keys[0], len[0]);
+  for (uint32_t x= 0; x < (repl + 1); ++x)
+  {
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(memc_clone, x);
+
+    instance->port= 0;
+    if (++hash == memc_clone->number_of_hosts)
+      hash= 0;
+  }
+
+  memcached_result_st result_obj;
+  for (uint32_t host= 0; host < memc_clone->number_of_hosts; ++host)
+  {
+    for (size_t x= 'a'; x <= 'z'; ++x)
+    {
+      const char key[2]= { [0]= (const char)x };
+
+      rc= memcached_mget_by_key(memc_clone, key, 1, keys, len, 4);
+      test_truth(rc == MEMCACHED_SUCCESS);
+
+      memcached_result_st *results= memcached_result_create(memc_clone, &result_obj);
+      test_truth(results);
+
+      int hits= 0;
+      while ((results= memcached_fetch_result(memc_clone, &result_obj, &rc)) != NULL)
+      {
+        ++hits;
+      }
+      test_truth(hits == 4);
+      memcached_result_free(&result_obj);
+    }
+  }
+  memcached_free(memc_clone);
+
+  return TEST_SUCCESS;
+}
+
+static void increment_request_id(uint16_t *id)
+{
+  (*id)++;
+  if ((*id & UDP_REQUEST_ID_THREAD_MASK) != 0)
+    *id= 0;
+}
+
+static uint16_t *get_udp_request_ids(memcached_st *memc)
+{
+  uint16_t *ids= malloc(sizeof(uint16_t) * memcached_server_count(memc));
+  assert(ids != NULL);
+
+  for (uint32_t x= 0; x < memcached_server_count(memc); x++)
+  {
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(memc, x);
+
+    ids[x]= get_udp_datagram_request_id((struct udp_datagram_header_st *) instance->write_buffer);
+  }
+
+  return ids;
+}
+
+static test_return_t post_udp_op_check(memcached_st *memc, uint16_t *expected_req_ids)
+{
+  memcached_server_st *cur_server = memcached_server_list(memc);
+  uint16_t *cur_req_ids = get_udp_request_ids(memc);
+
+  for (size_t x= 0; x < memcached_server_count(memc); x++)
+  {
+    test_truth(cur_server[x].cursor_active == 0);
+    test_truth(cur_req_ids[x] == expected_req_ids[x]);
+  }
+  free(expected_req_ids);
+  free(cur_req_ids);
+
+  return TEST_SUCCESS;
+}
+
+/*
+** There is a little bit of a hack here, instead of removing
+** the servers, I just set num host to 0 and them add then new udp servers
+**/
+static test_return_t init_udp(memcached_st *memc)
+{
+  memcached_version(memc);
+  memcached_server_instance_st *instance=
+    memcached_server_instance_fetch(memc, 0);
+
+  /* For the time being, only support udp test for >= 1.2.6 && < 1.3 */
+  if (instance->major_version != 1 || instance->minor_version != 2
+          || instance->micro_version < 6)
+    return TEST_SKIPPED;
+
+  uint32_t num_hosts= memcached_server_count(memc);
+  memcached_server_st servers[num_hosts];
+  memcpy(servers, memcached_server_list(memc), sizeof(memcached_server_st) * num_hosts);
+  for (uint32_t x= 0; x < num_hosts; x++)
+  {
+    memcached_server_instance_st *set_instance=
+      memcached_server_instance_fetch(memc, x);
+
+    memcached_server_free(set_instance);
+  }
+
+  memc->number_of_hosts= 0;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, 1);
+  for (uint32_t x= 0; x < num_hosts; x++)
+  {
+    memcached_server_instance_st *set_instance=
+      memcached_server_instance_fetch(memc, x);
+
+    test_truth(memcached_server_add_udp(memc, servers[x].hostname, servers[x].port) == MEMCACHED_SUCCESS);
+    test_truth(set_instance->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t binary_init_udp(memcached_st *memc)
+{
+  test_return_t test_rc;
+  test_rc= pre_binary(memc);
+
+  if (test_rc != TEST_SUCCESS)
+    return test_rc;
+
+  return init_udp(memc);
+}
+
+/* Make sure that I cant add a tcp server to a udp client */
+static test_return_t add_tcp_server_udp_client_test(memcached_st *memc)
+{
+  (void)memc;
+#if 0
+  memcached_server_st server;
+  memcached_server_instance_st *instance=
+    memcached_server_instance_fetch(memc, 0);
+  memcached_server_clone(&server, &memc->hosts[0]);
+  test_truth(memcached_server_remove(&(memc->hosts[0])) == MEMCACHED_SUCCESS);
+  test_truth(memcached_server_add(memc, server.hostname, server.port) == MEMCACHED_INVALID_HOST_PROTOCOL);
+#endif
+  return TEST_SUCCESS;
+}
+
+/* Make sure that I cant add a udp server to a tcp client */
+static test_return_t add_udp_server_tcp_client_test(memcached_st *memc)
+{
+  (void)memc;
+#if 0
+  memcached_server_st server;
+  memcached_server_instance_st *instance=
+    memcached_server_instance_fetch(memc, 0);
+  memcached_server_clone(&server, &memc->hosts[0]);
+  test_truth(memcached_server_remove(&(memc->hosts[0])) == MEMCACHED_SUCCESS);
+
+  memcached_st tcp_client;
+  memcached_create(&tcp_client);
+  test_truth(memcached_server_add_udp(&tcp_client, server.hostname, server.port) == MEMCACHED_INVALID_HOST_PROTOCOL);
+#endif
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t set_udp_behavior_test(memcached_st *memc)
+{
+
+  memcached_quit(memc);
+  memc->number_of_hosts= 0;
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, memc->distribution);
+  test_truth(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, 1) == MEMCACHED_SUCCESS);
+  test_truth(memc->flags.use_udp);
+  test_truth(memc->flags.no_reply);
+
+  test_truth(memcached_server_count(memc) == 0);
+
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP,0);
+  test_truth(! (memc->flags.use_udp));
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY,0);
+  test_truth(! (memc->flags.no_reply));
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t udp_set_test(memcached_st *memc)
+{
+  unsigned int num_iters= 1025; //request id rolls over at 1024
+
+  for (size_t x= 0; x < num_iters;x++)
+  {
+    memcached_return_t rc;
+    const char *key= "foo";
+    const char *value= "when we sanitize";
+    uint16_t *expected_ids= get_udp_request_ids(memc);
+    unsigned int server_key= memcached_generate_hash(memc, key, strlen(key));
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(memc, server_key);
+    size_t init_offset= instance->write_buffer_offset;
+
+    rc= memcached_set(memc, key, strlen(key),
+                      value, strlen(value),
+                      (time_t)0, (uint32_t)0);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+    /** NB, the check below assumes that if new write_ptr is less than
+     *  the original write_ptr that we have flushed. For large payloads, this
+     *  maybe an invalid assumption, but for the small payload we have it is OK
+     */
+    if (rc == MEMCACHED_SUCCESS ||
+            instance->write_buffer_offset < init_offset)
+      increment_request_id(&expected_ids[server_key]);
+
+    if (rc == MEMCACHED_SUCCESS)
+    {
+      test_truth(instance->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH);
+    }
+    else
+    {
+      test_truth(instance->write_buffer_offset != UDP_DATAGRAM_HEADER_LENGTH);
+      test_truth(instance->write_buffer_offset <= MAX_UDP_DATAGRAM_LENGTH);
+    }
+    test_truth(post_udp_op_check(memc, expected_ids) == TEST_SUCCESS);
+  }
+  return TEST_SUCCESS;
+}
+
+static test_return_t udp_buffered_set_test(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
+  return udp_set_test(memc);
+}
+
+static test_return_t udp_set_too_big_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "bar";
+  char value[MAX_UDP_DATAGRAM_LENGTH];
+  uint16_t *expected_ids= get_udp_request_ids(memc);
+  rc= memcached_set(memc, key, strlen(key),
+                    value, MAX_UDP_DATAGRAM_LENGTH,
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_WRITE_FAILURE);
+
+  return post_udp_op_check(memc,expected_ids);
+}
+
+static test_return_t udp_delete_test(memcached_st *memc)
+{
+  unsigned int num_iters= 1025; //request id rolls over at 1024
+
+  for (size_t x= 0; x < num_iters;x++)
+  {
+    memcached_return_t rc;
+    const char *key= "foo";
+    uint16_t *expected_ids=get_udp_request_ids(memc);
+    unsigned int server_key= memcached_generate_hash(memc, key, strlen(key));
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(memc, server_key);
+    size_t init_offset= instance->write_buffer_offset;
+
+    rc= memcached_delete(memc, key, strlen(key), 0);
+    test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+    if (rc == MEMCACHED_SUCCESS || instance->write_buffer_offset < init_offset)
+      increment_request_id(&expected_ids[server_key]);
+    if (rc == MEMCACHED_SUCCESS)
+    {
+      test_truth(instance->write_buffer_offset == UDP_DATAGRAM_HEADER_LENGTH);
+    }
+    else
+    {
+      test_truth(instance->write_buffer_offset != UDP_DATAGRAM_HEADER_LENGTH);
+      test_truth(instance->write_buffer_offset <= MAX_UDP_DATAGRAM_LENGTH);
+    }
+    test_truth(post_udp_op_check(memc,expected_ids) == TEST_SUCCESS);
+  }
+  return TEST_SUCCESS;
+}
+
+static test_return_t udp_buffered_delete_test(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
+  return udp_delete_test(memc);
+}
+
+static test_return_t udp_verbosity_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  uint16_t *expected_ids= get_udp_request_ids(memc);
+
+  for (size_t x= 0; x < memcached_server_count(memc); x++)
+  {
+    increment_request_id(&expected_ids[x]);
+  }
+
+  rc= memcached_verbosity(memc,3);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  return post_udp_op_check(memc,expected_ids);
+}
+
+static test_return_t udp_quit_test(memcached_st *memc)
+{
+  uint16_t *expected_ids= get_udp_request_ids(memc);
+  memcached_quit(memc);
+  return post_udp_op_check(memc, expected_ids);
+}
+
+static test_return_t udp_flush_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  uint16_t *expected_ids= get_udp_request_ids(memc);
+
+  for (size_t x= 0; x < memcached_server_count(memc); x++)
+  {
+    increment_request_id(&expected_ids[x]);
+  }
+
+  rc= memcached_flush(memc,0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  return post_udp_op_check(memc,expected_ids);
+}
+
+static test_return_t udp_incr_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "incr";
+  const char *value= "1";
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+
+  test_truth(rc == MEMCACHED_SUCCESS);
+  uint16_t *expected_ids= get_udp_request_ids(memc);
+  unsigned int server_key= memcached_generate_hash(memc, key, strlen(key));
+  increment_request_id(&expected_ids[server_key]);
+  uint64_t newvalue;
+  rc= memcached_increment(memc, key, strlen(key), 1, &newvalue);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  return post_udp_op_check(memc, expected_ids);
+}
+
+static test_return_t udp_decr_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "decr";
+  const char *value= "1";
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+
+  test_truth(rc == MEMCACHED_SUCCESS);
+  uint16_t *expected_ids= get_udp_request_ids(memc);
+  unsigned int server_key= memcached_generate_hash(memc, key, strlen(key));
+  increment_request_id(&expected_ids[server_key]);
+  uint64_t newvalue;
+  rc= memcached_decrement(memc, key, strlen(key), 1, &newvalue);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  return post_udp_op_check(memc, expected_ids);
+}
+
+
+static test_return_t udp_stat_test(memcached_st *memc)
+{
+  memcached_stat_st * rv= NULL;
+  memcached_return_t rc;
+  char args[]= "";
+  uint16_t *expected_ids = get_udp_request_ids(memc);
+  rv = memcached_stat(memc, args, &rc);
+  free(rv);
+  test_truth(rc == MEMCACHED_NOT_SUPPORTED);
+  return post_udp_op_check(memc, expected_ids);
+}
+
+static test_return_t udp_version_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  uint16_t *expected_ids = get_udp_request_ids(memc);
+  rc = memcached_version(memc);
+  test_truth(rc == MEMCACHED_NOT_SUPPORTED);
+  return post_udp_op_check(memc, expected_ids);
+}
+
+static test_return_t udp_get_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  const char *key= "foo";
+  size_t vlen;
+  uint16_t *expected_ids = get_udp_request_ids(memc);
+  char *val= memcached_get(memc, key, strlen(key), &vlen, (uint32_t)0, &rc);
+  test_truth(rc == MEMCACHED_NOT_SUPPORTED);
+  test_truth(val == NULL);
+  return post_udp_op_check(memc, expected_ids);
+}
+
+static test_return_t udp_mixed_io_test(memcached_st *memc)
+{
+  test_st current_op;
+  test_st mixed_io_ops [] ={
+    {"udp_set_test", 0,
+      (test_callback_fn)udp_set_test},
+    {"udp_set_too_big_test", 0,
+      (test_callback_fn)udp_set_too_big_test},
+    {"udp_delete_test", 0,
+      (test_callback_fn)udp_delete_test},
+    {"udp_verbosity_test", 0,
+      (test_callback_fn)udp_verbosity_test},
+    {"udp_quit_test", 0,
+      (test_callback_fn)udp_quit_test},
+    {"udp_flush_test", 0,
+      (test_callback_fn)udp_flush_test},
+    {"udp_incr_test", 0,
+      (test_callback_fn)udp_incr_test},
+    {"udp_decr_test", 0,
+      (test_callback_fn)udp_decr_test},
+    {"udp_version_test", 0,
+      (test_callback_fn)udp_version_test}
+  };
+  for (size_t x= 0; x < 500; x++)
+  {
+    current_op= mixed_io_ops[random() % 9];
+    test_truth(current_op.test_fn(memc) == TEST_SUCCESS);
+  }
+  return TEST_SUCCESS;
+}
+
+#if 0
+static test_return_t hash_sanity_test (memcached_st *memc)
+{
+  (void)memc;
+
+  assert(MEMCACHED_HASH_DEFAULT == MEMCACHED_HASH_DEFAULT);
+  assert(MEMCACHED_HASH_MD5 == MEMCACHED_HASH_MD5);
+  assert(MEMCACHED_HASH_CRC == MEMCACHED_HASH_CRC);
+  assert(MEMCACHED_HASH_FNV1_64 == MEMCACHED_HASH_FNV1_64);
+  assert(MEMCACHED_HASH_FNV1A_64 == MEMCACHED_HASH_FNV1A_64);
+  assert(MEMCACHED_HASH_FNV1_32 == MEMCACHED_HASH_FNV1_32);
+  assert(MEMCACHED_HASH_FNV1A_32 == MEMCACHED_HASH_FNV1A_32);
+#ifdef HAVE_HSIEH_HASH
+  assert(MEMCACHED_HASH_HSIEH == MEMCACHED_HASH_HSIEH);
+#endif
+  assert(MEMCACHED_HASH_MURMUR == MEMCACHED_HASH_MURMUR);
+  assert(MEMCACHED_HASH_JENKINS == MEMCACHED_HASH_JENKINS);
+  assert(MEMCACHED_HASH_MAX == MEMCACHED_HASH_MAX);
+
+  return TEST_SUCCESS;
+}
+#endif
+
+static test_return_t hsieh_avaibility_test (memcached_st *memc)
+{
+  memcached_return_t expected_rc= MEMCACHED_FAILURE;
+#ifdef HAVE_HSIEH_HASH
+  expected_rc= MEMCACHED_SUCCESS;
+#endif
+  memcached_return_t rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH,
+                                            (uint64_t)MEMCACHED_HASH_HSIEH);
+  test_truth(rc == expected_rc);
+  return TEST_SUCCESS;
+}
+
+static test_return_t md5_run (memcached_st *memc __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_MD5);
+    test_truth(md5_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t crc_run (memcached_st *memc __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_CRC);
+    test_truth(crc_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t fnv1_64_run (memcached_st *memc __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1_64);
+    test_truth(fnv1_64_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t fnv1a_64_run (memcached_st *memc __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1A_64);
+    test_truth(fnv1a_64_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t fnv1_32_run (memcached_st *memc __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1_32);
+    test_truth(fnv1_32_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t fnv1a_32_run (memcached_st *memc __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_FNV1A_32);
+    test_truth(fnv1a_32_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t hsieh_run (memcached_st *memc __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_HSIEH);
+    test_truth(hsieh_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t murmur_run (memcached_st *memc __attribute__((unused)))
+{
+#ifdef __sparc
+  return TEST_SKIPPED;
+#else
+  uint32_t x;
+  const char **ptr;
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_MURMUR);
+    test_truth(murmur_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+#endif
+}
+
+static test_return_t jenkins_run (memcached_st *memc __attribute__((unused)))
+{
+  uint32_t x;
+  const char **ptr;
+
+
+  for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
+  {
+    uint32_t hash_val;
+
+    hash_val= memcached_generate_hash_value(*ptr, strlen(*ptr), MEMCACHED_HASH_JENKINS);
+    test_truth(jenkins_values[x] == hash_val);
+  }
+
+  return TEST_SUCCESS;
+}
+
+
+static test_return_t ketama_compatibility_libmemcached(memcached_st *trash)
+{
+  memcached_return_t rc;
+  uint64_t value;
+  int x;
+  memcached_server_st *server_pool;
+  memcached_st *memc;
+
+  (void)trash;
+
+  memc= memcached_create(NULL);
+  test_truth(memc);
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
+  test_truth(value == 1);
+
+  test_truth(memcached_behavior_set_distribution(memc, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) == MEMCACHED_SUCCESS);
+  test_truth(memcached_behavior_get_distribution(memc) == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
+
+
+  server_pool = memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
+  memcached_server_push(memc, server_pool);
+
+  /* verify that the server list was parsed okay. */
+  test_truth(memcached_server_count(memc) == 8);
+  test_strcmp(server_pool[0].hostname, "10.0.1.1");
+  test_truth(server_pool[0].port == 11211);
+  test_truth(server_pool[0].weight == 600);
+  test_strcmp(server_pool[2].hostname, "10.0.1.3");
+  test_truth(server_pool[2].port == 11211);
+  test_truth(server_pool[2].weight == 200);
+  test_strcmp(server_pool[7].hostname, "10.0.1.8");
+  test_truth(server_pool[7].port == 11211);
+  test_truth(server_pool[7].weight == 100);
+
+  /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
+   * us test the boundary wraparound.
+   */
+  test_truth(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->continuum[0].index);
+
+  /* verify the standard ketama set. */
+  for (x= 0; x < 99; x++)
+  {
+    uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(memc, server_idx);
+    char *hostname = instance->hostname;
+
+    test_strcmp(hostname, ketama_test_cases[x].server);
+  }
+
+  memcached_server_list_free(server_pool);
+  memcached_free(memc);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t ketama_compatibility_spymemcached(memcached_st *trash)
+{
+  memcached_return_t rc;
+  uint64_t value;
+  int x;
+  memcached_server_st *server_pool;
+  memcached_st *memc;
+
+  (void)trash;
+
+  memc= memcached_create(NULL);
+  test_truth(memc);
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
+  test_truth(value == 1);
+
+  test_truth(memcached_behavior_set_distribution(memc, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY) == MEMCACHED_SUCCESS);
+  test_truth(memcached_behavior_get_distribution(memc) == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY);
+
+  server_pool = memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
+  memcached_server_push(memc, server_pool);
+
+  /* verify that the server list was parsed okay. */
+  test_truth(memcached_server_count(memc) == 8);
+  test_strcmp(server_pool[0].hostname, "10.0.1.1");
+  test_truth(server_pool[0].port == 11211);
+  test_truth(server_pool[0].weight == 600);
+  test_strcmp(server_pool[2].hostname, "10.0.1.3");
+  test_truth(server_pool[2].port == 11211);
+  test_truth(server_pool[2].weight == 200);
+  test_strcmp(server_pool[7].hostname, "10.0.1.8");
+  test_truth(server_pool[7].port == 11211);
+  test_truth(server_pool[7].weight == 100);
+
+  /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
+   * us test the boundary wraparound.
+   */
+  test_truth(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->continuum[0].index);
+
+  /* verify the standard ketama set. */
+  for (x= 0; x < 99; x++)
+  {
+    uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases_spy[x].key, strlen(ketama_test_cases_spy[x].key));
+    memcached_server_instance_st *instance=
+      memcached_server_instance_fetch(memc, server_idx);
+    char *hostname = instance->hostname;
+    test_strcmp(hostname, ketama_test_cases_spy[x].server);
+  }
+
+  memcached_server_list_free(server_pool);
+  memcached_free(memc);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t regression_bug_434484(memcached_st *memc)
+{
+  test_return_t test_rc;
+  test_rc= pre_binary(memc);
+
+  if (test_rc != TEST_SUCCESS)
+    return test_rc;
+
+  memcached_return_t ret;
+  const char *key= "regression_bug_434484";
+  size_t keylen= strlen(key);
+
+  ret= memcached_append(memc, key, keylen, key, keylen, 0, 0);
+  test_truth(ret == MEMCACHED_NOTSTORED);
+
+  size_t size= 2048 * 1024;
+  void *data= calloc(1, size);
+  test_truth(data != NULL);
+  ret= memcached_set(memc, key, keylen, data, size, 0, 0);
+  test_truth(ret == MEMCACHED_E2BIG);
+  free(data);
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t regression_bug_434843(memcached_st *memc)
+{
+  test_return_t test_rc;
+  test_rc= pre_binary(memc);
+
+  if (test_rc != TEST_SUCCESS)
+    return test_rc;
+
+  memcached_return_t rc;
+  size_t counter= 0;
+  memcached_execute_fn callbacks[1]= { [0]= &callback_counter };
+
+  /*
+   * I only want to hit only _one_ server so I know the number of requests I'm
+   * sending in the pipleine to the server. Let's try to do a multiget of
+   * 1024 (that should satisfy most users don't you think?). Future versions
+   * will include a mget_execute function call if you need a higher number.
+   */
+  uint32_t number_of_hosts= memcached_server_count(memc);
+  memc->number_of_hosts= 1;
+  const size_t max_keys= 1024;
+  char **keys= calloc(max_keys, sizeof(char*));
+  size_t *key_length=calloc(max_keys, sizeof(size_t));
+
+  for (size_t x= 0; x < max_keys; ++x)
+  {
+     char k[251];
+
+     key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%zu", x);
+     keys[x]= strdup(k);
+     test_truth(keys[x] != NULL);
+  }
+
+  /*
+   * Run two times.. the first time we should have 100% cache miss,
+   * and the second time we should have 100% cache hits
+   */
+  for (size_t y= 0; y < 2; y++)
+  {
+    rc= memcached_mget(memc, (const char**)keys, key_length, max_keys);
+    test_truth(rc == MEMCACHED_SUCCESS);
+    rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
+
+    if (y == 0)
+    {
+      /* The first iteration should give me a 100% cache miss. verify that*/
+      char blob[1024]= { 0 };
+
+      test_truth(counter == 0);
+
+      for (size_t x= 0; x < max_keys; ++x)
+      {
+        rc= memcached_add(memc, keys[x], key_length[x],
+                          blob, sizeof(blob), 0, 0);
+        test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+      }
+    }
+    else
+    {
+      /* Verify that we received all of the key/value pairs */
+       test_truth(counter == max_keys);
+    }
+  }
+
+  /* Release allocated resources */
+  for (size_t x= 0; x < max_keys; ++x)
+  {
+    free(keys[x]);
+  }
+  free(keys);
+  free(key_length);
+
+  memc->number_of_hosts= number_of_hosts;
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t regression_bug_434843_buffered(memcached_st *memc)
+{
+  memcached_return_t rc;
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  return regression_bug_434843(memc);
+}
+
+static test_return_t regression_bug_421108(memcached_st *memc)
+{
+  memcached_return_t rc;
+  memcached_stat_st *memc_stat= memcached_stat(memc, NULL, &rc);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  char *bytes= memcached_stat_get_value(memc, memc_stat, "bytes", &rc);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(bytes != NULL);
+  char *bytes_read= memcached_stat_get_value(memc, memc_stat,
+                                             "bytes_read", &rc);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(bytes_read != NULL);
+
+  char *bytes_written= memcached_stat_get_value(memc, memc_stat,
+                                                "bytes_written", &rc);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  test_truth(bytes_written != NULL);
+
+  test_truth(strcmp(bytes, bytes_read) != 0);
+  test_truth(strcmp(bytes, bytes_written) != 0);
+
+  /* Release allocated resources */
+  free(bytes);
+  free(bytes_read);
+  free(bytes_written);
+  memcached_stat_free(NULL, memc_stat);
+
+  return TEST_SUCCESS;
+}
+
+/*
+ * The test case isn't obvious so I should probably document why
+ * it works the way it does. Bug 442914 was caused by a bug
+ * in the logic in memcached_purge (it did not handle the case
+ * where the number of bytes sent was equal to the watermark).
+ * In this test case, create messages so that we hit that case
+ * and then disable noreply mode and issue a new command to
+ * verify that it isn't stuck. If we change the format for the
+ * delete command or the watermarks, we need to update this
+ * test....
+ */
+static test_return_t regression_bug_442914(memcached_st *memc)
+{
+  memcached_return_t rc;
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 1);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);
+
+  uint32_t number_of_hosts= memcached_server_count(memc);
+  memc->number_of_hosts= 1;
+
+  char k[250];
+  size_t len;
+
+  for (uint32_t x= 0; x < 250; ++x)
+  {
+     len= (size_t)snprintf(k, sizeof(k), "%0250u", x);
+     rc= memcached_delete(memc, k, len, 0);
+     test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  }
+
+  (void)snprintf(k, sizeof(k), "%037u", 251U);
+  len= strlen(k);
+
+  rc= memcached_delete(memc, k, len, 0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 0);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  rc= memcached_delete(memc, k, len, 0);
+  test_truth(rc == MEMCACHED_NOTFOUND);
+
+  memc->number_of_hosts= number_of_hosts;
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t regression_bug_447342(memcached_st *memc)
+{
+  memcached_server_instance_st *instance_one;
+  memcached_server_instance_st *instance_two;
+
+  if (memcached_server_count(memc) < 3 || pre_replication(memc) != MEMCACHED_SUCCESS)
+    return TEST_SKIPPED;
+
+  memcached_return_t rc;
+
+  rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, 2);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  const size_t max_keys= 100;
+  char **keys= calloc(max_keys, sizeof(char*));
+  size_t *key_length= calloc(max_keys, sizeof(size_t));
+
+  for (size_t x= 0; x < max_keys; ++x)
+  {
+    char k[251];
+
+    key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%zu", x);
+    keys[x]= strdup(k);
+    test_truth(keys[x] != NULL);
+    rc= memcached_set(memc, k, key_length[x], k, key_length[x], 0, 0);
+    test_truth(rc == MEMCACHED_SUCCESS);
+  }
+
+  /*
+  ** We are using the quiet commands to store the replicas, so we need
+  ** to ensure that all of them are processed before we can continue.
+  ** In the test we go directly from storing the object to trying to
+  ** receive the object from all of the different servers, so we
+  ** could end up in a race condition (the memcached server hasn't yet
+  ** processed the quiet command from the replication set when it process
+  ** the request from the other client (created by the clone)). As a
+  ** workaround for that we call memcached_quit to send the quit command
+  ** to the server and wait for the response ;-) If you use the test code
+  ** as an example for your own code, please note that you shouldn't need
+  ** to do this ;-)
+  */
+  memcached_quit(memc);
+
+  /* Verify that all messages are stored, and we didn't stuff too much
+   * into the servers
+   */
+  rc= memcached_mget(memc, (const char* const *)keys, key_length, max_keys);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  size_t counter= 0;
+  memcached_execute_fn callbacks[1]= { [0]= &callback_counter };
+  rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
+  /* Verify that we received all of the key/value pairs */
+  test_truth(counter == max_keys);
+
+  memcached_quit(memc);
+  /*
+   * Don't do the following in your code. I am abusing the internal details
+   * within the library, and this is not a supported interface.
+   * This is to verify correct behavior in the library. Fake that two servers
+   * are dead..
+   */
+  instance_one= memcached_server_instance_fetch(memc, 0);
+  instance_two= memcached_server_instance_fetch(memc, 2);
+  in_port_t port0= instance_one->port;
+  in_port_t port2= instance_two->port;
+
+  instance_one->port= 0;
+  instance_two->port= 0;
+
+  rc= memcached_mget(memc, (const char* const *)keys, key_length, max_keys);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  counter= 0;
+  rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
+  test_truth(counter == (unsigned int)max_keys);
+
+  /* restore the memc handle */
+  instance_one->port= port0;
+  instance_two->port= port2;
+
+  memcached_quit(memc);
+
+  /* Remove half of the objects */
+  for (size_t x= 0; x < max_keys; ++x)
+  {
+    if (x & 1)
+    {
+      rc= memcached_delete(memc, keys[x], key_length[x], 0);
+      test_truth(rc == MEMCACHED_SUCCESS);
+    }
+  }
+
+  memcached_quit(memc);
+  instance_one->port= 0;
+  instance_two->port= 0;
+
+  /* now retry the command, this time we should have cache misses */
+  rc= memcached_mget(memc, (const char* const *)keys, key_length, max_keys);
+  test_truth(rc == MEMCACHED_SUCCESS);
+
+  counter= 0;
+  rc= memcached_fetch_execute(memc, callbacks, (void *)&counter, 1);
+  test_truth(counter == (unsigned int)(max_keys >> 1));
+
+  /* Release allocated resources */
+  for (size_t x= 0; x < max_keys; ++x)
+  {
+    free(keys[x]);
+  }
+  free(keys);
+  free(key_length);
+
+  /* restore the memc handle */
+  instance_one->port= port0;
+  instance_two->port= port2;
+
+  return TEST_SUCCESS;
+}
+
+static test_return_t regression_bug_463297(memcached_st *memc)
+{
+  memcached_st *memc_clone= memcached_clone(NULL, memc);
+  test_truth(memc_clone != NULL);
+  test_truth(memcached_version(memc_clone) == MEMCACHED_SUCCESS);
+
+  memcached_server_instance_st *instance=
+    memcached_server_instance_fetch(memc_clone, 0);
+
+  if (instance->major_version > 1 ||
+      (instance->major_version == 1 &&
+       instance->minor_version > 2))
+  {
+     /* Binary protocol doesn't support deferred delete */
+     memcached_st *bin_clone= memcached_clone(NULL, memc);
+     test_truth(bin_clone != NULL);
+     test_truth(memcached_behavior_set(bin_clone, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1) == MEMCACHED_SUCCESS);
+     test_truth(memcached_delete(bin_clone, "foo", 3, 1) == MEMCACHED_INVALID_ARGUMENTS);
+     memcached_free(bin_clone);
+
+     memcached_quit(memc_clone);
+
+     /* If we know the server version, deferred delete should fail
+      * with invalid arguments */
+     test_truth(memcached_delete(memc_clone, "foo", 3, 1) == MEMCACHED_INVALID_ARGUMENTS);
+
+     /* If we don't know the server version, we should get a protocol error */
+     memcached_return_t rc= memcached_delete(memc, "foo", 3, 1);
+
+     /* but there is a bug in some of the memcached servers (1.4) that treats
+      * the counter as noreply so it doesn't send the proper error message
+      */
+     test_truth(rc == MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_NOTFOUND || rc == MEMCACHED_CLIENT_ERROR);
+
+     /* And buffered mode should be disabled and we should get protocol error */
+     test_truth(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1) == MEMCACHED_SUCCESS);
+     rc= memcached_delete(memc, "foo", 3, 1);
+     test_truth(rc == MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_NOTFOUND || rc == MEMCACHED_CLIENT_ERROR);
+
+     /* Same goes for noreply... */
+     test_truth(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 1) == MEMCACHED_SUCCESS);
+     rc= memcached_delete(memc, "foo", 3, 1);
+     test_truth(rc == MEMCACHED_PROTOCOL_ERROR || rc == MEMCACHED_NOTFOUND || rc == MEMCACHED_CLIENT_ERROR);
+
+     /* but a normal request should go through (and be buffered) */
+     test_truth((rc= memcached_delete(memc, "foo", 3, 0)) == MEMCACHED_BUFFERED);
+     test_truth(memcached_flush_buffers(memc) == MEMCACHED_SUCCESS);
+
+     test_truth(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0) == MEMCACHED_SUCCESS);
+     /* unbuffered noreply should be success */
+     test_truth(memcached_delete(memc, "foo", 3, 0) == MEMCACHED_SUCCESS);
+     /* unbuffered with reply should be not found... */
+     test_truth(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 0) == MEMCACHED_SUCCESS);
+     test_truth(memcached_delete(memc, "foo", 3, 0) == MEMCACHED_NOTFOUND);
+  }
+
+  memcached_free(memc_clone);
+  return TEST_SUCCESS;
+}
+
+
+/* Test memcached_server_get_last_disconnect
+ * For a working server set, shall be NULL
+ * For a set of non existing server, shall not be NULL
+ */
+static test_return_t  test_get_last_disconnect(memcached_st *memc)
+{
+  memcached_return_t rc;
+  memcached_server_st *disconnected_server;
+
+  /* With the working set of server */
+  const char *key= "marmotte";
+  const char *value= "milka";
+
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+  disconnected_server = memcached_server_get_last_disconnect(memc);
+  test_truth(disconnected_server == NULL);
+
+  /* With a non existing server */
+  memcached_st *mine;
+  memcached_server_st *servers;
+
+  const char *server_list= "localhost:9";
+
+  servers= memcached_servers_parse(server_list);
+  test_truth(servers);
+  mine= memcached_create(NULL);
+  rc= memcached_server_push(mine, servers);
+  test_truth(rc == MEMCACHED_SUCCESS);
+  memcached_server_list_free(servers);
+  test_truth(mine);
+
+  rc= memcached_set(mine, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc != MEMCACHED_SUCCESS);
+
+  disconnected_server = memcached_server_get_last_disconnect(mine);
+  test_truth(disconnected_server != NULL);
+  test_truth(disconnected_server->port == 9);
+  test_truth(strncmp(disconnected_server->hostname,"localhost",9) == 0);
+
+  memcached_quit(mine);
+  memcached_free(mine);
+
+  return TEST_SUCCESS;
+}
+
+/*
+ * This test ensures that the failure counter isn't incremented during
+ * normal termination of the memcached instance.
+ */
+static test_return_t wrong_failure_counter_test(memcached_st *memc)
+{
+  memcached_return_t rc;
+  memcached_server_instance_st *instance;
+
+  /* Set value to force connection to the server */
+  const char *key= "marmotte";
+  const char *value= "milka";
+
+  /*
+   * Please note that I'm abusing the internal structures in libmemcached
+   * in a non-portable way and you shouldn't be doing this. I'm only
+   * doing this in order to verify that the library works the way it should
+   */
+  uint32_t number_of_hosts= memcached_server_count(memc);
+  memc->number_of_hosts= 1;
+
+  /* Ensure that we are connected to the server by setting a value */
+  rc= memcached_set(memc, key, strlen(key),
+                    value, strlen(value),
+                    (time_t)0, (uint32_t)0);
+  test_truth(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+
+
+  instance= memcached_server_instance_fetch(memc, 0);
+  /* The test is to see that the memcached_quit doesn't increase the
+   * the server failure conter, so let's ensure that it is zero
+   * before sending quit
+   */
+  instance->server_failure_counter= 0;
+
+  memcached_quit(memc);
+
+  /* Verify that it memcached_quit didn't increment the failure counter
+   * Please note that this isn't bullet proof, because an error could
+   * occur...
+   */
+  test_truth(instance->server_failure_counter == 0);
+
+  /* restore the instance */
+  memc->number_of_hosts= number_of_hosts;
+
+  return TEST_SUCCESS;
+}
+
+
+
+
+/*
+ * Test that ensures mget_execute does not end into recursive calls that finally fails
+ */
+static test_return_t regression_bug_490486(memcached_st *memc)
+{
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, 1000);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, 1);
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, 3600);
+
+  /*
+   * I only want to hit _one_ server so I know the number of requests I'm
+   * sending in the pipeline.
+   */
+  uint32_t number_of_hosts= memc->number_of_hosts;
+  memc->number_of_hosts= 1;
+  size_t max_keys= 20480;
+
+
+  char **keys= calloc(max_keys, sizeof(char*));
+  size_t *key_length=calloc(max_keys, sizeof(size_t));
+
+  /* First add all of the items.. */
+  char blob[1024]= { 0 };
+  memcached_return rc;
+  for (size_t x= 0; x < max_keys; ++x)
+  {
+    char k[251];
+    key_length[x]= (size_t)snprintf(k, sizeof(k), "0200%zu", x);
+    keys[x]= strdup(k);
+    assert(keys[x] != NULL);
+    rc= memcached_set(memc, keys[x], key_length[x], blob, sizeof(blob), 0, 0);
+    assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
+  }
+
+  /* Try to get all of them with a large multiget */
+  size_t counter= 0;
+  memcached_execute_function callbacks[1]= { [0]= &callback_counter };
+  rc= memcached_mget_execute(memc, (const char**)keys, key_length,
+                             (size_t)max_keys, callbacks, &counter, 1);
+
+  assert(rc == MEMCACHED_SUCCESS);
+  char* the_value= NULL;
+  char the_key[MEMCACHED_MAX_KEY];
+  size_t the_key_length;
+  size_t the_value_length;
+  uint32_t the_flags;
+
+  do {
+    the_value= memcached_fetch(memc, the_key, &the_key_length, &the_value_length, &the_flags, &rc);
+
+    if ((the_value!= NULL) && (rc == MEMCACHED_SUCCESS))
+    {
+      ++counter;
+      free(the_value);
+    }
+
+  } while ( (the_value!= NULL) && (rc == MEMCACHED_SUCCESS));
+
+
+  assert(rc == MEMCACHED_END);
+
+  /* Verify that we got all of the items */
+  assert(counter == max_keys);
+
+  /* Release all allocated resources */
+  for (size_t x= 0; x < max_keys; ++x)
+  {
+    free(keys[x]);
+  }
+  free(keys);
+  free(key_length);
+
+  memc->number_of_hosts= number_of_hosts;
+
+  return TEST_SUCCESS;
+}
+
+
+
+
+test_st udp_setup_server_tests[] ={
+  {"set_udp_behavior_test", 0, (test_callback_fn)set_udp_behavior_test},
+  {"add_tcp_server_udp_client_test", 0, (test_callback_fn)add_tcp_server_udp_client_test},
+  {"add_udp_server_tcp_client_test", 0, (test_callback_fn)add_udp_server_tcp_client_test},
+  {0, 0, 0}
+};
+
+test_st upd_io_tests[] ={
+  {"udp_set_test", 0, (test_callback_fn)udp_set_test},
+  {"udp_buffered_set_test", 0, (test_callback_fn)udp_buffered_set_test},
+  {"udp_set_too_big_test", 0, (test_callback_fn)udp_set_too_big_test},
+  {"udp_delete_test", 0, (test_callback_fn)udp_delete_test},
+  {"udp_buffered_delete_test", 0, (test_callback_fn)udp_buffered_delete_test},
+  {"udp_verbosity_test", 0, (test_callback_fn)udp_verbosity_test},
+  {"udp_quit_test", 0, (test_callback_fn)udp_quit_test},
+  {"udp_flush_test", 0, (test_callback_fn)udp_flush_test},
+  {"udp_incr_test", 0, (test_callback_fn)udp_incr_test},
+  {"udp_decr_test", 0, (test_callback_fn)udp_decr_test},
+  {"udp_stat_test", 0, (test_callback_fn)udp_stat_test},
+  {"udp_version_test", 0, (test_callback_fn)udp_version_test},
+  {"udp_get_test", 0, (test_callback_fn)udp_get_test},
+  {"udp_mixed_io_test", 0, (test_callback_fn)udp_mixed_io_test},
+  {0, 0, 0}
+};
+
+/* Clean the server before beginning testing */
+test_st tests[] ={
+  {"flush", 0, (test_callback_fn)flush_test },
+  {"init", 0, (test_callback_fn)init_test },
+  {"allocation", 0, (test_callback_fn)allocation_test },
+  {"server_list_null_test", 0, (test_callback_fn)server_list_null_test},
+  {"server_unsort", 0, (test_callback_fn)server_unsort_test},
+  {"server_sort", 0, (test_callback_fn)server_sort_test},
+  {"server_sort2", 0, (test_callback_fn)server_sort2_test},
+  {"clone_test", 0, (test_callback_fn)clone_test },
+  {"connection_test", 0, (test_callback_fn)connection_test},
+  {"callback_test", 0, (test_callback_fn)callback_test},
+  {"userdata_test", 0, (test_callback_fn)userdata_test},
+  {"error", 0, (test_callback_fn)error_test },
+  {"set", 0, (test_callback_fn)set_test },
+  {"set2", 0, (test_callback_fn)set_test2 },
+  {"set3", 0, (test_callback_fn)set_test3 },
+  {"dump", 1, (test_callback_fn)dump_test},
+  {"add", 1, (test_callback_fn)add_test },
+  {"replace", 1, (test_callback_fn)replace_test },
+  {"delete", 1, (test_callback_fn)delete_test },
+  {"get", 1, (test_callback_fn)get_test },
+  {"get2", 0, (test_callback_fn)get_test2 },
+  {"get3", 0, (test_callback_fn)get_test3 },
+  {"get4", 0, (test_callback_fn)get_test4 },
+  {"partial mget", 0, (test_callback_fn)get_test5 },
+  {"stats_servername", 0, (test_callback_fn)stats_servername_test },
+  {"increment", 0, (test_callback_fn)increment_test },
+  {"increment_with_initial", 1, (test_callback_fn)increment_with_initial_test },
+  {"decrement", 0, (test_callback_fn)decrement_test },
+  {"decrement_with_initial", 1, (test_callback_fn)decrement_with_initial_test },
+  {"increment_by_key", 0, (test_callback_fn)increment_by_key_test },
+  {"increment_with_initial_by_key", 1, (test_callback_fn)increment_with_initial_by_key_test },
+  {"decrement_by_key", 0, (test_callback_fn)decrement_by_key_test },
+  {"decrement_with_initial_by_key", 1, (test_callback_fn)decrement_with_initial_by_key_test },
+  {"quit", 0, (test_callback_fn)quit_test },
+  {"mget", 1, (test_callback_fn)mget_test },
+  {"mget_result", 1, (test_callback_fn)mget_result_test },
+  {"mget_result_alloc", 1, (test_callback_fn)mget_result_alloc_test },
+  {"mget_result_function", 1, (test_callback_fn)mget_result_function },
+  {"mget_execute", 1, (test_callback_fn)mget_execute },
+  {"mget_end", 0, (test_callback_fn)mget_end },
+  {"get_stats", 0, (test_callback_fn)get_stats },
+  {"add_host_test", 0, (test_callback_fn)add_host_test },
+  {"add_host_test_1", 0, (test_callback_fn)add_host_test1 },
+  {"get_stats_keys", 0, (test_callback_fn)get_stats_keys },
+  {"version_string_test", 0, (test_callback_fn)version_string_test},
+  {"bad_key", 1, (test_callback_fn)bad_key_test },
+  {"memcached_server_cursor", 1, (test_callback_fn)memcached_server_cursor_test },
+  {"read_through", 1, (test_callback_fn)read_through },
+  {"delete_through", 1, (test_callback_fn)delete_through },
+  {"noreply", 1, (test_callback_fn)noreply_test},
+  {"analyzer", 1, (test_callback_fn)analyzer_test},
+#ifdef HAVE_LIBMEMCACHEDUTIL
+  {"connectionpool", 1, (test_callback_fn)connection_pool_test },
+#endif
+  {"test_get_last_disconnect", 1, (test_callback_fn)test_get_last_disconnect},
+  {0, 0, 0}
+};
+
+test_st behavior_tests[] ={
+  {"behavior_test", 0, (test_callback_fn)behavior_test},
+  {"MEMCACHED_BEHAVIOR_CORK", 0, (test_callback_fn)MEMCACHED_BEHAVIOR_CORK_test},
+  {0, 0, 0}
+};
+
+test_st async_tests[] ={
+  {"add", 1, (test_callback_fn)add_wrapper },
+  {0, 0, 0}
+};
+
+test_st string_tests[] ={
+  {"string static with null", 0, (test_callback_fn)string_static_null },
+  {"string alloc with null", 0, (test_callback_fn)string_alloc_null },
+  {"string alloc with 1K", 0, (test_callback_fn)string_alloc_with_size },
+  {"string alloc with malloc failure", 0, (test_callback_fn)string_alloc_with_size_toobig },
+  {"string append", 0, (test_callback_fn)string_alloc_append },
+  {"string append failure (too big)", 0, (test_callback_fn)string_alloc_append_toobig },
+  {0, 0, (test_callback_fn)0}
+};
+
+test_st result_tests[] ={
+  {"result static", 0, (test_callback_fn)result_static},
+  {"result alloc", 0, (test_callback_fn)result_alloc},
+  {0, 0, (test_callback_fn)0}
+};
+
+test_st version_1_2_3[] ={
+  {"append", 0, (test_callback_fn)append_test },
+  {"prepend", 0, (test_callback_fn)prepend_test },
+  {"cas", 0, (test_callback_fn)cas_test },
+  {"cas2", 0, (test_callback_fn)cas2_test },
+  {"append_binary", 0, (test_callback_fn)append_binary_test },
+  {0, 0, (test_callback_fn)0}
+};
+
+test_st user_tests[] ={
+  {"user_supplied_bug1", 0, (test_callback_fn)user_supplied_bug1 },
+  {"user_supplied_bug2", 0, (test_callback_fn)user_supplied_bug2 },
+  {"user_supplied_bug3", 0, (test_callback_fn)user_supplied_bug3 },
+  {"user_supplied_bug4", 0, (test_callback_fn)user_supplied_bug4 },
+  {"user_supplied_bug5", 1, (test_callback_fn)user_supplied_bug5 },
+  {"user_supplied_bug6", 1, (test_callback_fn)user_supplied_bug6 },
+  {"user_supplied_bug7", 1, (test_callback_fn)user_supplied_bug7 },
+  {"user_supplied_bug8", 1, (test_callback_fn)user_supplied_bug8 },
+  {"user_supplied_bug9", 1, (test_callback_fn)user_supplied_bug9 },
+  {"user_supplied_bug10", 1, (test_callback_fn)user_supplied_bug10 },
+  {"user_supplied_bug11", 1, (test_callback_fn)user_supplied_bug11 },
+  {"user_supplied_bug12", 1, (test_callback_fn)user_supplied_bug12 },
+  {"user_supplied_bug13", 1, (test_callback_fn)user_supplied_bug13 },
+  {"user_supplied_bug14", 1, (test_callback_fn)user_supplied_bug14 },
+  {"user_supplied_bug15", 1, (test_callback_fn)user_supplied_bug15 },
+  {"user_supplied_bug16", 1, (test_callback_fn)user_supplied_bug16 },
+#ifndef __sun
+  /*
+  ** It seems to be something weird with the character sets..
+  ** value_fetch is unable to parse the value line (iscntrl "fails"), so I
+  ** guess I need to find out how this is supposed to work.. Perhaps I need
+  ** to run the test in a specific locale (I tried zh_CN.UTF-8 without success,
+  ** so just disable the code for now...).
+  */
+  {"user_supplied_bug17", 1, (test_callback_fn)user_supplied_bug17 },
+#endif
+  {"user_supplied_bug18", 1, (test_callback_fn)user_supplied_bug18 },
+  {"user_supplied_bug19", 1, (test_callback_fn)user_supplied_bug19 },
+  {"user_supplied_bug20", 1, (test_callback_fn)user_supplied_bug20 },
+  {"user_supplied_bug21", 1, (test_callback_fn)user_supplied_bug21 },
+  {"wrong_failure_counter_test", 1, (test_callback_fn)wrong_failure_counter_test},
+  {0, 0, (test_callback_fn)0}
+};
+
+test_st replication_tests[]= {
+  {"set", 1, (test_callback_fn)replication_set_test },
+  {"get", 0, (test_callback_fn)replication_get_test },
+  {"mget", 0, (test_callback_fn)replication_mget_test },
+  {"delete", 0, (test_callback_fn)replication_delete_test },
+  {"rand_mget", 0, (test_callback_fn)replication_randomize_mget_test },
+  {0, 0, (test_callback_fn)0}
+};
+
+/*
+ * The following test suite is used to verify that we don't introduce
+ * regression bugs. If you want more information about the bug / test,
+ * you should look in the bug report at
+ *   http://bugs.launchpad.net/libmemcached
+ */
+test_st regression_tests[]= {
+  {"lp:434484", 1, (test_callback_fn)regression_bug_434484 },
+  {"lp:434843", 1, (test_callback_fn)regression_bug_434843 },
+  {"lp:434843 buffered", 1, (test_callback_fn)regression_bug_434843_buffered },
+  {"lp:421108", 1, (test_callback_fn)regression_bug_421108 },
+  {"lp:442914", 1, (test_callback_fn)regression_bug_442914 },
+  {"lp:447342", 1, (test_callback_fn)regression_bug_447342 },
+  {"lp:463297", 1, (test_callback_fn)regression_bug_463297 },
+  {"lp:490486", 1, (test_callback_fn)regression_bug_490486 },
+  {0, 0, (test_callback_fn)0}
+};
+
+test_st ketama_compatibility[]= {
+  {"libmemcached", 1, (test_callback_fn)ketama_compatibility_libmemcached },
+  {"spymemcached", 1, (test_callback_fn)ketama_compatibility_spymemcached },
+  {0, 0, (test_callback_fn)0}
+};
+
+test_st generate_tests[] ={
+  {"generate_pairs", 1, (test_callback_fn)generate_pairs },
+  {"generate_data", 1, (test_callback_fn)generate_data },
+  {"get_read", 0, (test_callback_fn)get_read },
+  {"delete_generate", 0, (test_callback_fn)delete_generate },
+  {"generate_buffer_data", 1, (test_callback_fn)generate_buffer_data },
+  {"delete_buffer", 0, (test_callback_fn)delete_buffer_generate},
+  {"generate_data", 1, (test_callback_fn)generate_data },
+  {"mget_read", 0, (test_callback_fn)mget_read },
+  {"mget_read_result", 0, (test_callback_fn)mget_read_result },
+  {"mget_read_function", 0, (test_callback_fn)mget_read_function },
+  {"cleanup", 1, (test_callback_fn)cleanup_pairs },
+  {"generate_large_pairs", 1, (test_callback_fn)generate_large_pairs },
+  {"generate_data", 1, (test_callback_fn)generate_data },
+  {"generate_buffer_data", 1, (test_callback_fn)generate_buffer_data },
+  {"cleanup", 1, (test_callback_fn)cleanup_pairs },
+  {0, 0, (test_callback_fn)0}
+};
+
+test_st consistent_tests[] ={
+  {"generate_pairs", 1, (test_callback_fn)generate_pairs },
+  {"generate_data", 1, (test_callback_fn)generate_data },
+  {"get_read", 0, (test_callback_fn)get_read_count },
+  {"cleanup", 1, (test_callback_fn)cleanup_pairs },
+  {0, 0, (test_callback_fn)0}
+};
+
+test_st consistent_weighted_tests[] ={
+  {"generate_pairs", 1, (test_callback_fn)generate_pairs },
+  {"generate_data", 1, (test_callback_fn)generate_data_with_stats },
+  {"get_read", 0, (test_callback_fn)get_read_count },
+  {"cleanup", 1, (test_callback_fn)cleanup_pairs },
+  {0, 0, (test_callback_fn)0}
+};
+
+test_st hsieh_availability[] ={
+  {"hsieh_avaibility_test", 0, (test_callback_fn)hsieh_avaibility_test},
+  {0, 0, (test_callback_fn)0}
+};
+
+#if 0
+test_st hash_sanity[] ={
+  {"hash sanity", 0, (test_callback_fn)hash_sanity_test},
+  {0, 0, (test_callback_fn)0}
+};
+#endif
+
+test_st ketama_auto_eject_hosts[] ={
+  {"auto_eject_hosts", 1, (test_callback_fn)auto_eject_hosts },
+  {"output_ketama_weighted_keys", 1, (test_callback_fn)output_ketama_weighted_keys },
+  {0, 0, (test_callback_fn)0}
+};
+
+test_st hash_tests[] ={
+  {"md5", 0, (test_callback_fn)md5_run },
+  {"crc", 0, (test_callback_fn)crc_run },
+  {"fnv1_64", 0, (test_callback_fn)fnv1_64_run },
+  {"fnv1a_64", 0, (test_callback_fn)fnv1a_64_run },
+  {"fnv1_32", 0, (test_callback_fn)fnv1_32_run },
+  {"fnv1a_32", 0, (test_callback_fn)fnv1a_32_run },
+  {"hsieh", 0, (test_callback_fn)hsieh_run },
+  {"murmur", 0, (test_callback_fn)murmur_run },
+  {"jenkis", 0, (test_callback_fn)jenkins_run },
+  {0, 0, (test_callback_fn)0}
+};
+
+collection_st collection[] ={
+#if 0
+  {"hash_sanity", 0, 0, hash_sanity},
+#endif
+  {"hsieh_availability", 0, 0, hsieh_availability},
+  {"udp_setup", (test_callback_fn)init_udp, 0, udp_setup_server_tests},
+  {"udp_io", (test_callback_fn)init_udp, 0, upd_io_tests},
+  {"udp_binary_io", (test_callback_fn)binary_init_udp, 0, upd_io_tests},
+  {"block", 0, 0, tests},
+  {"binary", (test_callback_fn)pre_binary, 0, tests},
+  {"nonblock", (test_callback_fn)pre_nonblock, 0, tests},
+  {"nodelay", (test_callback_fn)pre_nodelay, 0, tests},
+  {"settimer", (test_callback_fn)pre_settimer, 0, tests},
+  {"md5", (test_callback_fn)pre_md5, 0, tests},
+  {"crc", (test_callback_fn)pre_crc, 0, tests},
+  {"hsieh", (test_callback_fn)pre_hsieh, 0, tests},
+  {"jenkins", (test_callback_fn)pre_jenkins, 0, tests},
+  {"fnv1_64", (test_callback_fn)pre_hash_fnv1_64, 0, tests},
+  {"fnv1a_64", (test_callback_fn)pre_hash_fnv1a_64, 0, tests},
+  {"fnv1_32", (test_callback_fn)pre_hash_fnv1_32, 0, tests},
+  {"fnv1a_32", (test_callback_fn)pre_hash_fnv1a_32, 0, tests},
+  {"ketama", (test_callback_fn)pre_behavior_ketama, 0, tests},
+  {"ketama_auto_eject_hosts", (test_callback_fn)pre_behavior_ketama, 0, ketama_auto_eject_hosts},
+  {"unix_socket", (test_callback_fn)pre_unix_socket, 0, tests},
+  {"unix_socket_nodelay", (test_callback_fn)pre_nodelay, 0, tests},
+  {"poll_timeout", (test_callback_fn)poll_timeout, 0, tests},
+  {"gets", (test_callback_fn)enable_cas, 0, tests},
+  {"consistent_crc", (test_callback_fn)enable_consistent_crc, 0, tests},
+  {"consistent_hsieh", (test_callback_fn)enable_consistent_hsieh, 0, tests},
+#ifdef MEMCACHED_ENABLE_DEPRECATED
+  {"deprecated_memory_allocators", (test_callback_fn)deprecated_set_memory_alloc, 0, tests},
+#endif
+  {"memory_allocators", (test_callback_fn)set_memory_alloc, 0, tests},
+  {"prefix", (test_callback_fn)set_prefix, 0, tests},
+  {"version_1_2_3", (test_callback_fn)check_for_1_2_3, 0, version_1_2_3},
+  {"string", 0, 0, string_tests},
+  {"result", 0, 0, result_tests},
+  {"async", (test_callback_fn)pre_nonblock, 0, async_tests},
+  {"async_binary", (test_callback_fn)pre_nonblock_binary, 0, async_tests},
+  {"user", 0, 0, user_tests},
+  {"generate", 0, 0, generate_tests},
+  {"generate_hsieh", (test_callback_fn)pre_hsieh, 0, generate_tests},
+  {"generate_ketama", (test_callback_fn)pre_behavior_ketama, 0, generate_tests},
+  {"generate_hsieh_consistent", (test_callback_fn)enable_consistent_hsieh, 0, generate_tests},
+  {"generate_md5", (test_callback_fn)pre_md5, 0, generate_tests},
+  {"generate_murmur", (test_callback_fn)pre_murmur, 0, generate_tests},
+  {"generate_jenkins", (test_callback_fn)pre_jenkins, 0, generate_tests},
+  {"generate_nonblock", (test_callback_fn)pre_nonblock, 0, generate_tests},
+  {"generate_corked", (test_callback_fn)pre_cork, 0, generate_tests},
+  {"generate_corked_and_nonblock", (test_callback_fn)pre_cork_and_nonblock, 0, generate_tests},
+  {"consistent_not", 0, 0, consistent_tests},
+  {"consistent_ketama", (test_callback_fn)pre_behavior_ketama, 0, consistent_tests},
+  {"consistent_ketama_weighted", (test_callback_fn)pre_behavior_ketama_weighted, 0, consistent_weighted_tests},
+  {"ketama_compat", 0, 0, ketama_compatibility},
+  {"test_hashes", 0, 0, hash_tests},
+  {"replication", (test_callback_fn)pre_replication, 0, replication_tests},
+  {"replication_noblock", (test_callback_fn)pre_replication_noblock, 0, replication_tests},
+  {"regression", 0, 0, regression_tests},
+  {"behaviors", 0, 0, behavior_tests},
+  {0, 0, 0, 0}
+};
+
+#define SERVERS_TO_CREATE 5
+
+#include "libmemcached_world.h"
+
+void get_world(world_st *world)
+{
+  world->collections= collection;
+
+  world->create= (test_callback_create_fn)world_create;
+  world->destroy= (test_callback_fn)world_destroy;
+
+  world->test.startup= (test_callback_fn)world_test_startup;
+  world->test.flush= (test_callback_fn)world_flush;
+  world->test.pre_run= (test_callback_fn)world_pre_run;
+  world->test.post_run= (test_callback_fn)world_post_run;
+  world->test.on_error= (test_callback_error_fn)world_on_error;
+
+  world->collection.startup= (test_callback_fn)world_container_startup;
+  world->collection.shutdown= (test_callback_fn)world_container_shutdown;
+
+  world->runner= &defualt_libmemcached_runner;
+}
diff --git a/tests/output.res b/tests/output.res
deleted file mode 100644 (file)
index 5de5008..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-servers localhost:11221,localhost:11222,localhost:11223,localhost:11224,localhost:11225,
-       localhost : 11221
-       localhost : 11222
-       localhost : 11223
-       localhost : 11224
-       localhost : 11225
-
diff --git a/tests/output2.res b/tests/output2.res
deleted file mode 100644 (file)
index 7bf929e..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-Error 0 -> SUCCESS
-Error 1 -> FAILURE
-Error 2 -> HOSTNAME LOOKUP FAILURE
-Error 3 -> CONNECTION FAILURE
-Error 4 -> CONNECTION BIND FAILURE
-Error 5 -> WRITE FAILURE
-Error 6 -> READ FAILURE
-Error 7 -> UNKNOWN READ FAILURE
-Error 8 -> PROTOCOL ERROR
-Error 9 -> CLIENT ERROR
-Error 10 -> SERVER ERROR
-Error 11 -> CONNECTION SOCKET CREATE FAILURE
-Error 12 -> CONNECTION DATA EXISTS
-Error 13 -> CONNECTION DATA DOES NOT EXIST
-Error 14 -> NOT STORED
-Error 15 -> NOT FOUND
-Error 16 -> MEMORY ALLOCATION FAILURE
-Error 17 -> PARTIAL READ
-Error 18 -> SOME ERRORS WERE REPORTED
-Error 19 -> NO SERVERS DEFINED
-Found key pid
-Found key uptime
-Found key time
-Found key version
-Found key pointer_size
-Found key rusage_user
-Found key rusage_system
-Found key rusage_user_seconds
-Found key rusage_user_microseconds
-Found key rusage_system_seconds
-Found key rusage_system_microseconds
-Found key curr_items
-Found key total_items
-Found key bytes
-Found key curr_connections
-Found key total_connections
-Found key connection_structures
-Found key cmd_get
-Found key cmd_set
-Found key get_hits
-Found key get_misses
-Found key evictions
-Found key bytes_read
-Found key bytes_written
-Found key limit_maxbytes
-Found key threads
index d988334fb89459b8df47671bb66dae37c3aaa043..f9cbdd5e748b8b72afea8a81522df9b7ce899c83 100644 (file)
@@ -27,12 +27,11 @@ extern "C" {
    test_return_t increment_test(memcached_st *memc);
    test_return_t basic_master_key_test(memcached_st *memc);
    test_return_t mget_result_function(memcached_st *memc);
+   test_return_t basic_behavior(memcached_st *memc);
    test_return_t mget_test(memcached_st *memc);
-   memcached_return callback_counter(memcached_st *,
-                                     memcached_result_st *, 
-                                     void *context);
-   void *world_create(void);
-   void world_destroy(void *p);
+   memcached_return_t callback_counter(memcached_st *,
+                                       memcached_result_st *,
+                                       void *context);
 }
 
 static void populate_vector(vector<char> &vec, const string &str)
@@ -64,7 +63,7 @@ test_return_t basic_test(memcached_st *memc)
 
   assert((memcmp(&test_value[0], &value[0], test_value.size()) == 0));
 
-  /* 
+  /*
    * Simple test of the exceptions here...this should throw an exception
    * saying that the key is empty.
    */
@@ -108,7 +107,7 @@ test_return_t increment_test(memcached_st *memc)
 
   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); 
+  assert(int_ret_value == int_inc_value);
 
   rc= mcach.increment(key, 1, &int_ret_value);
   assert(rc == true);
@@ -151,8 +150,8 @@ test_return_t basic_master_key_test(memcached_st *memc)
 }
 
 /* Count the results */
-memcached_return callback_counter(memcached_st *,
-                                  memcached_result_st *, 
+memcached_return_t callback_counter(memcached_st *,
+                                  memcached_result_st *,
                                   void *context)
 {
   unsigned int *counter= static_cast<unsigned int *>(context);
@@ -186,7 +185,7 @@ test_return_t mget_result_function(memcached_st *memc)
   values.push_back(&val2);
   values.push_back(&val3);
   unsigned int counter;
-  memcached_execute_function callbacks[1];
+  memcached_execute_fn callbacks[1];
 
   /* We need to empty the server before we continue the test */
   rc= mc.flush(0);
@@ -198,7 +197,7 @@ test_return_t mget_result_function(memcached_st *memc)
 
   callbacks[0]= &callback_counter;
   counter= 0;
-  rc= mc.fetchExecute(callbacks, static_cast<void *>(&counter), 1); 
+  rc= mc.fetchExecute(callbacks, static_cast<void *>(&counter), 1);
 
   assert(counter == 3);
 
@@ -209,7 +208,7 @@ test_return_t mget_test(memcached_st *memc)
 {
   Memcache mc(memc);
   bool rc;
-  memcached_return mc_rc;
+  memcached_return_t mc_rc;
   vector<string> keys;
   vector< vector<char> *> values;
   keys.reserve(3);
@@ -259,12 +258,32 @@ test_return_t mget_test(memcached_st *memc)
   return TEST_SUCCESS;
 }
 
+test_return_t basic_behavior(memcached_st *memc)
+{
+  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);
+
+  return TEST_SUCCESS;
+}
+
 test_st tests[] ={
-  { "basic", 0, basic_test },
-  { "basic_master_key", 0, basic_master_key_test },
-  { "increment_test", 0, increment_test },
-  { "mget", 1, mget_test },
-  { "mget_result_function", 1, mget_result_function },
+  { "basic", 0,
+    reinterpret_cast<test_callback_fn>(basic_test) },
+  { "basic_master_key", 0,
+    reinterpret_cast<test_callback_fn>(basic_master_key_test) },
+  { "increment_test", 0,
+    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}
 };
 
@@ -273,35 +292,25 @@ collection_st collection[] ={
   {0, 0, 0, 0}
 };
 
-#define SERVERS_TO_CREATE 1
-
-extern "C" void *world_create(void)
-{
-  server_startup_st *construct;
+#define SERVERS_TO_CREATE 5
 
-  construct= (server_startup_st *)malloc(sizeof(server_startup_st));
-  memset(construct, 0, sizeof(server_startup_st));
+#include "libmemcached_world.h"
 
-  construct->count= SERVERS_TO_CREATE;
-  server_startup(construct);
+void get_world(world_st *world)
+{
+  world->collections= collection;
 
-  return construct;
-}
+  world->create= reinterpret_cast<test_callback_create_fn>(world_create);
+  world->destroy= reinterpret_cast<test_callback_fn>(world_destroy);
 
-void world_destroy(void *p)
-{
-  server_startup_st *construct= static_cast<server_startup_st *>(p);
-  memcached_server_st *servers=
-    static_cast<memcached_server_st *>(construct->servers);
-  memcached_server_list_free(servers);
+  world->test.startup= reinterpret_cast<test_callback_fn>(world_test_startup);
+  world->test.flush= reinterpret_cast<test_callback_fn>(world_flush);
+  world->test.pre_run= reinterpret_cast<test_callback_fn>(world_pre_run);
+  world->test.post_run= reinterpret_cast<test_callback_fn>(world_post_run);
+  world->test.on_error= reinterpret_cast<test_callback_error_fn>(world_on_error);
 
-  server_shutdown(construct);
-  free(construct);
-}
+  world->collection.startup= reinterpret_cast<test_callback_fn>(world_container_startup);
+  world->collection.shutdown= reinterpret_cast<test_callback_fn>(world_container_shutdown);
 
-void get_world(world_st *world)
-{
-  world->collections= collection;
-  world->create= world_create;
-  world->destroy= world_destroy;
+  world->runner= &defualt_libmemcached_runner;
 }
index f0926695133571f946ccfcad05a1f06dc11a5326..68b3d80146416ede910f85a8c963369dc09d8d98 100644 (file)
@@ -1,3 +1,14 @@
+/* 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:
+ *
+ */
+
 /*
   Startup, and shutdown the memcached servers.
 */
@@ -50,7 +61,7 @@ void server_startup(server_startup_st *construct)
           {
             if (fgets(buffer, sizeof(buffer), fp) != NULL)
             { 
-              pid_t pid = (pid_t)atol(buffer);
+              pid_t pid= (pid_t)atoi(buffer);
               if (pid != 0) 
                 kill(pid, SIGTERM);
             }
@@ -88,7 +99,7 @@ void server_startup(server_startup_st *construct)
 
   for (x= 0; x < memcached_server_list_count(construct->servers); x++)
   {
-    printf("\t%s : %u\n", construct->servers[x].hostname, construct->servers[x].port);
+    printf("\t%s : %d\n", construct->servers[x].hostname, construct->servers[x].port);
     assert(construct->servers[x].fd == -1);
     assert(construct->servers[x].cursor_active == 0);
   }
index 26452f54db31e4a9933b4b2221f2cc9964a6d87d..0aef86f93ce28ee57747a18329499e32da1b726c 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * 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.
+ */
+
 /*
   Server startup and shutdown functions.
 */
index aa042f976fa957626f044d357a2509151f7748f3..eb37357d6b5b43e1b1d7a8f4bff8fafaa848c76f 100644 (file)
@@ -1,3 +1,14 @@
+/* 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 <stdio.h>
 #include <string.h>
 #include "server.h"
index 7f7879dc14f65c2cedd108ee6764776b15afe12f..903ad4ee9e87610741a56bb9f1590fc16969405d 100644 (file)
@@ -1,3 +1,11 @@
+/* uTest
+ * 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.
+ */
+
 /*
   Sample test application.
 */
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <unistd.h>
 #include <time.h>
 #include <fnmatch.h>
-#include "server.h"
+#include <stdint.h>
 
 #include "test.h"
 
+static void world_stats_print(world_stats_st *stats)
+{
+  fputc('\n', stderr);
+  fprintf(stderr, "Total Collections\t\t\t\t%u\n", stats->collection_total);
+  fprintf(stderr, "\tFailed Collections\t\t\t%u\n", stats->collection_failed);
+  fprintf(stderr, "\tSkipped Collections\t\t\t%u\n", stats->collection_skipped);
+  fprintf(stderr, "\tSucceeded Collections\t\t%u\n", stats->collection_success);
+  fputc('\n', stderr);
+  fprintf(stderr, "Total\t\t\t\t%u\n", stats->total);
+  fprintf(stderr, "\tFailed\t\t\t%u\n", stats->failed);
+  fprintf(stderr, "\tSkipped\t\t\t%u\n", stats->skipped);
+  fprintf(stderr, "\tSucceeded\t\t%u\n", stats->success);
+}
+
 static long int timedif(struct timeval a, struct timeval b)
 {
-  register int us, s;
+  long us, s;
 
   us = (int)(a.tv_usec - b.tv_usec);
   us /= 1000;
@@ -25,7 +48,7 @@ static long int timedif(struct timeval a, struct timeval b)
   return s + us;
 }
 
-static const char *test_strerror(test_return_t code)
+const char *test_strerror(test_return_t code)
 {
   switch (code) {
   case TEST_SUCCESS:
@@ -41,33 +64,106 @@ static const char *test_strerror(test_return_t code)
     fprintf(stderr, "Unknown return value\n");
     abort();
   }
+}
+
+void create_core(void)
+{
+  if (getenv("LIBMEMCACHED_NO_COREDUMP") == NULL)
+  {
+    pid_t pid= fork();
+
+    if (pid == 0)
+    {
+      abort();
+    }
+    else
+    {
+      while (waitpid(pid, NULL, 0) != pid)
+      {
+        ;
+      }
+    }
+  }
+}
+
+
+static test_return_t _runner_default(test_callback_fn func, void *p)
+{
+  if (func)
+  {
+    return func(p);
+  }
+  else
+  {
+    return TEST_SUCCESS;
+  }
+}
+
+static world_runner_st defualt_runners= {
+  _runner_default,
+  _runner_default,
+  _runner_default
+};
+
+static test_return_t _default_callback(void *p)
+{
+  (void)p;
+
+  return TEST_SUCCESS;
+}
+
+static inline void set_default_fn(test_callback_fn *fn)
+{
+  if (*fn == NULL)
+  {
+    *fn= _default_callback;
+  }
+}
+
+static collection_st *init_world(world_st *world)
+{
+  if (! world->runner)
+  {
+    world->runner= &defualt_runners;
+  }
+
+  set_default_fn(&world->collection.startup);
+  set_default_fn(&world->collection.shutdown);
 
+  return world->collections;
 }
 
+
 int main(int argc, char *argv[])
 {
-  test_return_t failed;
+  test_return_t return_code;
   unsigned int x;
   char *collection_to_run= NULL;
   char *wildcard= NULL;
-  server_startup_st *startup_ptr;
-  memcached_server_st *servers;
   world_st world;
   collection_st *collection;
   collection_st *next;
   void *world_ptr;
 
-  memset(&world, 0, sizeof(world_st));
+  world_stats_st stats;
+
+  memset(&stats, 0, sizeof(stats));
+  memset(&world, 0, sizeof(world));
   get_world(&world);
-  collection= world.collections;
+
+  collection= init_world(&world);
 
   if (world.create)
-    world_ptr= world.create();
+  {
+    test_return_t error;
+    world_ptr= world.create(&error);
+    if (error != TEST_SUCCESS)
+      exit(1);
+  }
   else
+  {
     world_ptr= NULL;
-
-  startup_ptr= (server_startup_st *)world_ptr;
-  servers= (memcached_server_st *)startup_ptr->servers;
+  }
 
   if (argc > 1)
     collection_to_run= argv[1];
@@ -77,77 +173,173 @@ int main(int argc, char *argv[])
 
   for (next= collection; next->name; next++)
   {
+    test_return_t collection_rc= TEST_SUCCESS;
     test_st *run;
+    bool failed= false;
+    bool skipped= false;
 
     run= next->tests;
     if (collection_to_run && fnmatch(collection_to_run, next->name, 0))
       continue;
 
-    fprintf(stderr, "\n%s\n\n", next->name);
+    stats.collection_total++;
+
+    collection_rc= world.collection.startup(world_ptr);
+
+    switch (collection_rc)
+    {
+      case TEST_SUCCESS:
+        fprintf(stderr, "\n%s\n\n", next->name);
+        break;
+      case TEST_FAILURE:
+        fprintf(stderr, "\n%s [ failed ]\n\n", next->name);
+        stats.failed++;
+        continue;
+      case TEST_SKIPPED:
+        fprintf(stderr, "\n%s [ skipping ]\n\n", next->name);
+        stats.skipped++;
+        continue;
+      case TEST_MEMORY_ALLOCATION_FAILURE:
+      case TEST_MAXIMUM_RETURN:
+      default:
+        assert(0);
+        break;
+    }
 
     for (x= 0; run->name; run++)
     {
-      unsigned int loop;
-      memcached_st *memc;
-      memcached_return rc;
       struct timeval start_time, end_time;
-      long int load_time;
+      long int load_time= 0;
 
       if (wildcard && fnmatch(wildcard, run->name, 0))
         continue;
 
       fprintf(stderr, "Testing %s", run->name);
 
-      memc= memcached_create(NULL);
-      assert(memc);
-
-      rc= memcached_server_push(memc, servers);
-      assert(rc == MEMCACHED_SUCCESS);
+      if (world.test.startup)
+      {
+        world.test.startup(world_ptr);
+      }
 
-      if (run->requires_flush)
+      if (run->requires_flush && world.test.flush)
       {
-        memcached_flush(memc, 0);
-        memcached_quit(memc);
+        world.test.flush(world_ptr);
       }
 
-      for (loop= 0; loop < memcached_server_list_count(servers); loop++)
+      if (world.test.pre_run)
       {
-        assert(memc->hosts[loop].fd == -1);
-        assert(memc->hosts[loop].cursor_active == 0);
+        world.test.pre_run(world_ptr);
       }
 
-      if (next->pre)
+
+      // Runner code
       {
-        rc= next->pre(memc);
+        if (next->pre && world.runner->pre)
+        {
+          return_code= world.runner->pre(next->pre, world_ptr);
 
-        if (rc != MEMCACHED_SUCCESS)
+          if (return_code != TEST_SUCCESS)
+          {
+            goto error;
+          }
+        }
+
+        gettimeofday(&start_time, NULL);
+        return_code= world.runner->run(run->test_fn, world_ptr);
+        gettimeofday(&end_time, NULL);
+        load_time= timedif(end_time, start_time);
+
+        if (next->post && world.runner->post)
         {
-          fprintf(stderr, "\t\t\t\t\t [ skipping ]\n");
-          goto error;
+          (void) world.runner->post(next->post, world_ptr);
         }
       }
 
-      gettimeofday(&start_time, NULL);
-      failed= run->function(memc);
-      gettimeofday(&end_time, NULL);
-      load_time= timedif(end_time, start_time);
+      if (world.test.post_run)
+      {
+        world.test.post_run(world_ptr);
+      }
+
+error:
+      stats.total++;
+
+      fprintf(stderr, "\t\t\t\t\t");
 
-      fprintf(stderr, "\t\t\t\t\t %ld.%03ld [ %s ]\n", load_time / 1000,
-              load_time % 1000, test_strerror(failed));
+      switch (return_code)
+      {
+      case TEST_SUCCESS:
+        fprintf(stderr, "%ld.%03ld ", load_time / 1000, load_time % 1000);
+        stats.success++;
+        break;
+      case TEST_FAILURE:
+        stats.failed++;
+        failed= true;
+        break;
+      case TEST_SKIPPED:
+        stats.skipped++;
+        skipped= true;
+        break;
+      case TEST_MEMORY_ALLOCATION_FAILURE:
+        fprintf(stderr, "Exhausted memory, quitting\n");
+        abort();
+      case TEST_MAXIMUM_RETURN:
+      default:
+        assert(0); // Coding error.
+        break;
+      }
 
-      if (next->post)
-        (void)next->post(memc);
+      fprintf(stderr, "[ %s ]\n", test_strerror(return_code));
 
-      assert(memc);
-error:
-      memcached_free(memc);
+      if (world.test.on_error)
+      {
+        test_return_t rc;
+        rc= world.test.on_error(return_code, world_ptr);
+
+        if (rc != TEST_SUCCESS)
+          break;
+      }
+    }
+
+    if (failed)
+    {
+      stats.collection_failed++;
+    }
+
+    if (skipped)
+    {
+      stats.collection_skipped++;
+    }
+
+    if (! failed && ! skipped)
+    {
+      stats.collection_success++;
     }
+
+    world.collection.shutdown(world_ptr);
   }
 
-  fprintf(stderr, "All tests completed successfully\n\n");
+  if (stats.collection_failed || stats.collection_skipped)
+  {
+    fprintf(stderr, "Some test failures and/or skipped test occurred.\n\n");
+  }
+  else
+  {
+    fprintf(stderr, "All tests completed successfully\n\n");
+  }
 
   if (world.destroy)
-    world.destroy(world_ptr);
+  {
+    test_return_t error;
+    error= world.destroy(world_ptr);
+
+    if (error != TEST_SUCCESS)
+    {
+      fprintf(stderr, "Failure during shutdown.\n");
+      stats.failed++; // We do this to make our exit code return 1
+    }
+  }
+
+  world_stats_print(&stats);
 
-  return 0;
+  return stats.failed == 0 ? 0 : 1;
 }
index 28d29a41c79d118e47ab741c3f198baf6776b2ae..972788e5cb92f5c0fb37d03b17ae3f6fbb12386b 100644 (file)
@@ -1,12 +1,26 @@
+/* uTest
+ * 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.
+ */
+
 /*
   Structures for generic tests.
 */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#include <libmemcached/memcached.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#if !defined(__cplusplus)
+# include <stdbool.h>
+#endif
 
 typedef struct world_st world_st;
 typedef struct collection_st collection_st;
@@ -20,28 +34,158 @@ typedef enum {
   TEST_MAXIMUM_RETURN /* Always add new error code before */
 } test_return_t;
 
+typedef void *(*test_callback_create_fn)(test_return_t *error);
+typedef test_return_t (*test_callback_fn)(void *);
+typedef test_return_t (*test_callback_runner_fn)(test_callback_fn, void *);
+typedef test_return_t (*test_callback_error_fn)(test_return_t, void *);
+
+
+/**
+  A structure describing the test case.
+*/
 struct test_st {
   const char *name;
-  unsigned int requires_flush;
-  test_return_t (*function)(memcached_st *memc);
+  bool requires_flush;
+  test_callback_fn test_fn;
 };
 
+
+/**
+  A structure which describes a collection of test cases.
+*/
 struct collection_st {
   const char *name;
-  memcached_return (*pre)(memcached_st *memc);
-  memcached_return (*post)(memcached_st *memc);
+  test_callback_fn pre;
+  test_callback_fn post;
   test_st *tests;
 };
 
+
+/**
+  Structure which houses the actual callers for the test cases contained in
+  the collections.
+*/
+typedef struct {
+  test_callback_runner_fn pre;
+  test_callback_runner_fn run;
+  test_callback_runner_fn post;
+} world_runner_st;
+
+
+/**
+  world_st is the structure which is passed to the test implementation to be filled.
+  This must be implemented in order for the test framework to load the tests. We call
+  get_world() in order to fill this structure.
+*/
+
 struct world_st {
   collection_st *collections;
-  void *(*create)(void);
-  void (*destroy)(void *collection_object);
+
+  /* These methods are called outside of any collection call. */
+  test_callback_create_fn create;
+  test_callback_fn destroy;
+
+  struct {
+    /* This is called a the beginning of any test run. */
+    test_callback_fn startup;
+
+    /* This called on a test if the test requires a flush call (the bool is from test_st) */
+    test_callback_fn flush;
+
+    /**
+      These are run before/after the test. If implemented. Their execution is not controlled
+      by the test.
+    */
+    test_callback_fn pre_run;
+    test_callback_fn post_run;
+
+    /**
+      If an error occurs during the test, this is called.
+    */
+    test_callback_error_fn on_error;
+  } test;
+
+  struct {
+    /* This is called a the beginning of any collection run. */
+    test_callback_fn startup;
+
+    /* This is called at the end of any collection run. */
+    test_callback_fn shutdown;
+  } collection;
+
+
+  /**
+    Runner represents the callers for the tests. If not implemented we will use
+    a set of default implementations.
+  */
+  world_runner_st *runner;
 };
 
+
+
+/**
+  @note world_stats_st is a simple structure for tracking test successes.
+*/
+typedef struct {
+  uint32_t collection_success;
+  uint32_t collection_skipped;
+  uint32_t collection_failed;
+  uint32_t collection_total;
+  uint32_t success;
+  uint32_t skipped;
+  uint32_t failed;
+  uint32_t total;
+} world_stats_st;
+
 /* How we make all of this work :) */
 void get_world(world_st *world);
 
+void create_core(void);
+
+/**
+  @note Friendly print function for errors.
+*/
+const char *test_strerror(test_return_t code);
+
+#define test_fail(A) \
+do \
+{ \
+  fprintf(stderr, "\nFailed in %s:%d: %s\n", __FILE__, __LINE__, #A);\
+  create_core(); \
+  return TEST_FAILURE; \
+} while (0)
+
+#define test_truth(A) \
+do \
+{ \
+  if (! (A)) { \
+    fprintf(stderr, "\nAssertion failed in %s:%d: %s\n", __FILE__, __LINE__, #A);\
+    create_core(); \
+    return TEST_FAILURE; \
+  } \
+} while (0)
+
+#define test_false(A) \
+do \
+{ \
+  if ((A)) { \
+    fprintf(stderr, "\nAssertion failed in %s:%d: %s\n", __FILE__, __LINE__, #A);\
+    create_core(); \
+    return TEST_FAILURE; \
+  } \
+} while (0)
+
+#define test_strcmp(A,B) \
+do \
+{ \
+  if (strcmp((A), (B))) \
+  { \
+    fprintf(stderr, "\n%s:%d: %s -> %s\n", __FILE__, __LINE__, (A), (B)); \
+    create_core(); \
+    return TEST_FAILURE; \
+  } \
+} while (0)
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/tests/udp.c b/tests/udp.c
deleted file mode 100644 (file)
index dc33ae6..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-  Sample test application.
-*/
-#include <assert.h>
-#include <libmemcached/memcached.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <time.h>
-#include "test.h"
-#include "server.h"
-
-/* Prototypes */
-test_return_t set_test(memcached_st *memc);
-void *world_create(void);
-void world_destroy(void *p);
-
-test_return_t set_test(memcached_st *memc)
-{
-  memcached_return rc;
-  const char *key= "foo";
-  const char *value= "when we sanitize";
-
-  rc= memcached_set(memc, key, strlen(key), 
-                    value, strlen(value),
-                    (time_t)0, (uint32_t)0);
-  assert(rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
-
-  return TEST_SUCCESS;
-}
-
-test_st tests[] ={
-  {"set", 1, set_test },
-  {0, 0, 0}
-};
-
-collection_st collection[] ={
-  {"udp", 0, 0, tests},
-  {0, 0, 0, 0}
-};
-
-#define SERVERS_TO_CREATE 1
-
-void *world_create(void)
-{
-  server_startup_st *construct;
-
-  construct= (server_startup_st *)malloc(sizeof(server_startup_st));
-  memset(construct, 0, sizeof(server_startup_st));
-  construct->count= SERVERS_TO_CREATE;
-  construct->udp= 1;
-  server_startup(construct);
-
-  return construct;
-}
-
-void world_destroy(void *p)
-{
-  server_startup_st *construct= (server_startup_st *)p;
-  memcached_server_st *servers= (memcached_server_st *)construct->servers;
-  memcached_server_list_free(servers);
-
-  server_shutdown(construct);
-  free(construct);
-}
-
-void get_world(world_st *world)
-{
-  world->collections= collection;
-  world->create= world_create;
-  world->destroy= world_destroy;
-}